Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * Copyright © 2008 Red Hat, Inc.
  3.  *
  4.  * Permission is hereby granted, free of charge, to any person obtaining a
  5.  * copy of this software and associated documentation files (the "Soft-
  6.  * ware"), to deal in the Software without restriction, including without
  7.  * limitation the rights to use, copy, modify, merge, publish, distribute,
  8.  * and/or sell copies of the Software, and to permit persons to whom the
  9.  * Software is furnished to do so, provided that the above copyright
  10.  * notice(s) and this permission notice appear in all copies of the Soft-
  11.  * ware and that both the above copyright notice(s) and this permission
  12.  * notice appear in supporting documentation.
  13.  *
  14.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  15.  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
  16.  * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY
  17.  * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN
  18.  * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE-
  19.  * QUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
  20.  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
  21.  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFOR-
  22.  * MANCE OF THIS SOFTWARE.
  23.  *
  24.  * Except as contained in this notice, the name of a copyright holder shall
  25.  * not be used in advertising or otherwise to promote the sale, use or
  26.  * other dealings in this Software without prior written authorization of
  27.  * the copyright holder.
  28.  *
  29.  * Authors:
  30.  *   Kristian Høgsberg (krh@redhat.com)
  31.  */
  32.  
  33.  
  34. #ifdef GLX_DIRECT_RENDERING
  35.  
  36. #include <stdio.h>
  37. #include <X11/Xlibint.h>
  38. #include <X11/extensions/Xext.h>
  39. #include <X11/extensions/extutil.h>
  40. #include <X11/extensions/dri2proto.h>
  41. #include "dri2.h"
  42. #include "glxclient.h"
  43. #include "GL/glxext.h"
  44.  
  45. /* Allow the build to work with an older versions of dri2proto.h and
  46.  * dri2tokens.h.
  47.  */
  48. #if DRI2_MINOR < 1
  49. #undef DRI2_MINOR
  50. #define DRI2_MINOR 1
  51. #define X_DRI2GetBuffersWithFormat 7
  52. #endif
  53.  
  54.  
  55. static char dri2ExtensionName[] = DRI2_NAME;
  56. static XExtensionInfo _dri2Info_data;
  57. static XExtensionInfo *dri2Info = &_dri2Info_data;
  58. static XEXT_GENERATE_CLOSE_DISPLAY (DRI2CloseDisplay, dri2Info)
  59.  
  60. static Bool
  61. DRI2WireToEvent(Display *dpy, XEvent *event, xEvent *wire);
  62. static Status
  63. DRI2EventToWire(Display *dpy, XEvent *event, xEvent *wire);
  64. static int
  65. DRI2Error(Display *display, xError *err, XExtCodes *codes, int *ret_code);
  66.  
  67. static /* const */ XExtensionHooks dri2ExtensionHooks = {
  68.   NULL,                   /* create_gc */
  69.   NULL,                   /* copy_gc */
  70.   NULL,                   /* flush_gc */
  71.   NULL,                   /* free_gc */
  72.   NULL,                   /* create_font */
  73.   NULL,                   /* free_font */
  74.   DRI2CloseDisplay,       /* close_display */
  75.   DRI2WireToEvent,        /* wire_to_event */
  76.   DRI2EventToWire,        /* event_to_wire */
  77.   DRI2Error,              /* error */
  78.   NULL,                   /* error_string */
  79. };
  80.  
  81. static XEXT_GENERATE_FIND_DISPLAY (DRI2FindDisplay,
  82.                                    dri2Info,
  83.                                    dri2ExtensionName,
  84.                                    &dri2ExtensionHooks,
  85.                                    0, NULL)
  86.  
  87. static Bool
  88. DRI2WireToEvent(Display *dpy, XEvent *event, xEvent *wire)
  89. {
  90.    XExtDisplayInfo *info = DRI2FindDisplay(dpy);
  91.    struct glx_drawable *glxDraw;
  92.  
  93.    XextCheckExtension(dpy, info, dri2ExtensionName, False);
  94.  
  95.    switch ((wire->u.u.type & 0x7f) - info->codes->first_event) {
  96.  
  97. #ifdef X_DRI2SwapBuffers
  98.    case DRI2_BufferSwapComplete:
  99.    {
  100.       GLXBufferSwapComplete *aevent = (GLXBufferSwapComplete *)event;
  101.       xDRI2BufferSwapComplete2 *awire = (xDRI2BufferSwapComplete2 *)wire;
  102.       __GLXDRIdrawable *pdraw;
  103.  
  104.       pdraw = dri2GetGlxDrawableFromXDrawableId(dpy, awire->drawable);
  105.       if (pdraw == NULL)
  106.          return False;
  107.  
  108.       /* Ignore swap events if we're not looking for them */
  109.       aevent->type = dri2GetSwapEventType(dpy, awire->drawable);
  110.       if(!aevent->type)
  111.          return False;
  112.  
  113.       aevent->serial = _XSetLastRequestRead(dpy, (xGenericReply *) wire);
  114.       aevent->send_event = (awire->type & 0x80) != 0;
  115.       aevent->display = dpy;
  116.       aevent->drawable = awire->drawable;
  117.       switch (awire->event_type) {
  118.       case DRI2_EXCHANGE_COMPLETE:
  119.          aevent->event_type = GLX_EXCHANGE_COMPLETE_INTEL;
  120.          break;
  121.       case DRI2_BLIT_COMPLETE:
  122.          aevent->event_type = GLX_COPY_COMPLETE_INTEL;
  123.          break;
  124.       case DRI2_FLIP_COMPLETE:
  125.          aevent->event_type = GLX_FLIP_COMPLETE_INTEL;
  126.          break;
  127.       default:
  128.          /* unknown swap completion type */
  129.          return False;
  130.       }
  131.       aevent->ust = ((CARD64)awire->ust_hi << 32) | awire->ust_lo;
  132.       aevent->msc = ((CARD64)awire->msc_hi << 32) | awire->msc_lo;
  133.  
  134.       glxDraw = GetGLXDrawable(dpy, pdraw->drawable);
  135.       if (glxDraw != NULL) {
  136.          if (awire->sbc < glxDraw->lastEventSbc)
  137.             glxDraw->eventSbcWrap += 0x100000000;
  138.          glxDraw->lastEventSbc = awire->sbc;
  139.          aevent->sbc = awire->sbc + glxDraw->eventSbcWrap;
  140.       } else {
  141.          aevent->sbc = awire->sbc;
  142.       }
  143.  
  144.       return True;
  145.    }
  146. #endif
  147. #ifdef DRI2_InvalidateBuffers
  148.    case DRI2_InvalidateBuffers:
  149.    {
  150.       xDRI2InvalidateBuffers *awire = (xDRI2InvalidateBuffers *)wire;
  151.  
  152.       dri2InvalidateBuffers(dpy, awire->drawable);
  153.       return False;
  154.    }
  155. #endif
  156.    default:
  157.       /* client doesn't support server event */
  158.       break;
  159.    }
  160.  
  161.    return False;
  162. }
  163.  
  164. /* We don't actually support this.  It doesn't make sense for clients to
  165.  * send each other DRI2 events.
  166.  */
  167. static Status
  168. DRI2EventToWire(Display *dpy, XEvent *event, xEvent *wire)
  169. {
  170.    XExtDisplayInfo *info = DRI2FindDisplay(dpy);
  171.  
  172.    XextCheckExtension(dpy, info, dri2ExtensionName, False);
  173.  
  174.    switch (event->type) {
  175.    default:
  176.       /* client doesn't support server event */
  177.       break;
  178.    }
  179.  
  180.    return Success;
  181. }
  182.  
  183. static int
  184. DRI2Error(Display *display, xError *err, XExtCodes *codes, int *ret_code)
  185. {
  186.     if (err->majorCode == codes->major_opcode &&
  187.         err->errorCode == BadDrawable &&
  188.         err->minorCode == X_DRI2CopyRegion)
  189.         return True;
  190.  
  191.     /* If the X drawable was destroyed before the GLX drawable, the
  192.      * DRI2 drawble will be gone by the time we call
  193.      * DRI2DestroyDrawable.  So just ignore BadDrawable here. */
  194.     if (err->majorCode == codes->major_opcode &&
  195.         err->errorCode == BadDrawable &&
  196.         err->minorCode == X_DRI2DestroyDrawable)
  197.         return True;
  198.  
  199.     /* If the server is non-local DRI2Connect will raise BadRequest.
  200.      * Swallow this so that DRI2Connect can signal this in its return code */
  201.     if (err->majorCode == codes->major_opcode &&
  202.         err->minorCode == X_DRI2Connect &&
  203.         err->errorCode == BadRequest) {
  204.         *ret_code = False;
  205.         return True;
  206.     }
  207.  
  208.     return False;
  209. }
  210.  
  211. Bool
  212. DRI2QueryExtension(Display * dpy, int *eventBase, int *errorBase)
  213. {
  214.    XExtDisplayInfo *info = DRI2FindDisplay(dpy);
  215.  
  216.    if (XextHasExtension(info)) {
  217.       *eventBase = info->codes->first_event;
  218.       *errorBase = info->codes->first_error;
  219.       return True;
  220.    }
  221.  
  222.    return False;
  223. }
  224.  
  225. Bool
  226. DRI2QueryVersion(Display * dpy, int *major, int *minor)
  227. {
  228.    XExtDisplayInfo *info = DRI2FindDisplay(dpy);
  229.    xDRI2QueryVersionReply rep;
  230.    xDRI2QueryVersionReq *req;
  231.    int i, nevents;
  232.  
  233.    XextCheckExtension(dpy, info, dri2ExtensionName, False);
  234.  
  235.    LockDisplay(dpy);
  236.    GetReq(DRI2QueryVersion, req);
  237.    req->reqType = info->codes->major_opcode;
  238.    req->dri2ReqType = X_DRI2QueryVersion;
  239.    req->majorVersion = DRI2_MAJOR;
  240.    req->minorVersion = DRI2_MINOR;
  241.    if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) {
  242.       UnlockDisplay(dpy);
  243.       SyncHandle();
  244.       return False;
  245.    }
  246.    *major = rep.majorVersion;
  247.    *minor = rep.minorVersion;
  248.    UnlockDisplay(dpy);
  249.    SyncHandle();
  250.  
  251.    switch (rep.minorVersion) {
  252.    case 1:
  253.            nevents = 0;
  254.            break;
  255.    case 2:
  256.            nevents = 1;
  257.            break;
  258.    case 3:
  259.    default:
  260.            nevents = 2;
  261.            break;
  262.    }
  263.        
  264.    for (i = 0; i < nevents; i++) {
  265.        XESetWireToEvent (dpy, info->codes->first_event + i, DRI2WireToEvent);
  266.        XESetEventToWire (dpy, info->codes->first_event + i, DRI2EventToWire);
  267.    }
  268.  
  269.    return True;
  270. }
  271.  
  272. Bool
  273. DRI2Connect(Display * dpy, XID window, char **driverName, char **deviceName)
  274. {
  275.    XExtDisplayInfo *info = DRI2FindDisplay(dpy);
  276.    xDRI2ConnectReply rep;
  277.    xDRI2ConnectReq *req;
  278.  
  279.    XextCheckExtension(dpy, info, dri2ExtensionName, False);
  280.  
  281.    LockDisplay(dpy);
  282.    GetReq(DRI2Connect, req);
  283.    req->reqType = info->codes->major_opcode;
  284.    req->dri2ReqType = X_DRI2Connect;
  285.    req->window = window;
  286.  
  287.    req->driverType = DRI2DriverDRI;
  288. #ifdef DRI2DriverPrimeShift
  289.    {
  290.       char *prime = getenv("DRI_PRIME");
  291.       if (prime) {
  292.          uint32_t primeid;
  293.          errno = 0;
  294.          primeid = strtoul(prime, NULL, 0);
  295.          if (errno == 0)
  296.             req->driverType |=
  297.                ((primeid & DRI2DriverPrimeMask) << DRI2DriverPrimeShift);
  298.       }
  299.    }
  300. #endif
  301.  
  302.    if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) {
  303.       UnlockDisplay(dpy);
  304.       SyncHandle();
  305.       return False;
  306.    }
  307.  
  308.    if (rep.driverNameLength == 0 && rep.deviceNameLength == 0) {
  309.       UnlockDisplay(dpy);
  310.       SyncHandle();
  311.       return False;
  312.    }
  313.  
  314.    *driverName = malloc(rep.driverNameLength + 1);
  315.    if (*driverName == NULL) {
  316.       _XEatData(dpy,
  317.                 ((rep.driverNameLength + 3) & ~3) +
  318.                 ((rep.deviceNameLength + 3) & ~3));
  319.       UnlockDisplay(dpy);
  320.       SyncHandle();
  321.       return False;
  322.    }
  323.    _XReadPad(dpy, *driverName, rep.driverNameLength);
  324.    (*driverName)[rep.driverNameLength] = '\0';
  325.  
  326.    *deviceName = malloc(rep.deviceNameLength + 1);
  327.    if (*deviceName == NULL) {
  328.       free(*driverName);
  329.       _XEatData(dpy, ((rep.deviceNameLength + 3) & ~3));
  330.       UnlockDisplay(dpy);
  331.       SyncHandle();
  332.       return False;
  333.    }
  334.    _XReadPad(dpy, *deviceName, rep.deviceNameLength);
  335.    (*deviceName)[rep.deviceNameLength] = '\0';
  336.  
  337.    UnlockDisplay(dpy);
  338.    SyncHandle();
  339.  
  340.    return True;
  341. }
  342.  
  343. Bool
  344. DRI2Authenticate(Display * dpy, XID window, drm_magic_t magic)
  345. {
  346.    XExtDisplayInfo *info = DRI2FindDisplay(dpy);
  347.    xDRI2AuthenticateReq *req;
  348.    xDRI2AuthenticateReply rep;
  349.  
  350.    XextCheckExtension(dpy, info, dri2ExtensionName, False);
  351.  
  352.    LockDisplay(dpy);
  353.    GetReq(DRI2Authenticate, req);
  354.    req->reqType = info->codes->major_opcode;
  355.    req->dri2ReqType = X_DRI2Authenticate;
  356.    req->window = window;
  357.    req->magic = magic;
  358.  
  359.    if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) {
  360.       UnlockDisplay(dpy);
  361.       SyncHandle();
  362.       return False;
  363.    }
  364.  
  365.    UnlockDisplay(dpy);
  366.    SyncHandle();
  367.  
  368.    return rep.authenticated;
  369. }
  370.  
  371. void
  372. DRI2CreateDrawable(Display * dpy, XID drawable)
  373. {
  374.    XExtDisplayInfo *info = DRI2FindDisplay(dpy);
  375.    xDRI2CreateDrawableReq *req;
  376.  
  377.    XextSimpleCheckExtension(dpy, info, dri2ExtensionName);
  378.  
  379.    LockDisplay(dpy);
  380.    GetReq(DRI2CreateDrawable, req);
  381.    req->reqType = info->codes->major_opcode;
  382.    req->dri2ReqType = X_DRI2CreateDrawable;
  383.    req->drawable = drawable;
  384.    UnlockDisplay(dpy);
  385.    SyncHandle();
  386. }
  387.  
  388. void
  389. DRI2DestroyDrawable(Display * dpy, XID drawable)
  390. {
  391.    XExtDisplayInfo *info = DRI2FindDisplay(dpy);
  392.    xDRI2DestroyDrawableReq *req;
  393.  
  394.    XextSimpleCheckExtension(dpy, info, dri2ExtensionName);
  395.  
  396.    XSync(dpy, False);
  397.  
  398.    LockDisplay(dpy);
  399.    GetReq(DRI2DestroyDrawable, req);
  400.    req->reqType = info->codes->major_opcode;
  401.    req->dri2ReqType = X_DRI2DestroyDrawable;
  402.    req->drawable = drawable;
  403.    UnlockDisplay(dpy);
  404.    SyncHandle();
  405. }
  406.  
  407. DRI2Buffer *
  408. DRI2GetBuffers(Display * dpy, XID drawable,
  409.                int *width, int *height,
  410.                unsigned int *attachments, int count, int *outCount)
  411. {
  412.    XExtDisplayInfo *info = DRI2FindDisplay(dpy);
  413.    xDRI2GetBuffersReply rep;
  414.    xDRI2GetBuffersReq *req;
  415.    DRI2Buffer *buffers;
  416.    xDRI2Buffer repBuffer;
  417.    CARD32 *p;
  418.    int i;
  419.  
  420.    XextCheckExtension(dpy, info, dri2ExtensionName, False);
  421.  
  422.    LockDisplay(dpy);
  423.    GetReqExtra(DRI2GetBuffers, count * 4, req);
  424.    req->reqType = info->codes->major_opcode;
  425.    req->dri2ReqType = X_DRI2GetBuffers;
  426.    req->drawable = drawable;
  427.    req->count = count;
  428.    p = (CARD32 *) & req[1];
  429.    for (i = 0; i < count; i++)
  430.       p[i] = attachments[i];
  431.  
  432.    if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) {
  433.       UnlockDisplay(dpy);
  434.       SyncHandle();
  435.       return NULL;
  436.    }
  437.  
  438.    *width = rep.width;
  439.    *height = rep.height;
  440.    *outCount = rep.count;
  441.  
  442.    buffers = malloc(rep.count * sizeof buffers[0]);
  443.    if (buffers == NULL) {
  444.       _XEatData(dpy, rep.count * sizeof repBuffer);
  445.       UnlockDisplay(dpy);
  446.       SyncHandle();
  447.       return NULL;
  448.    }
  449.  
  450.    for (i = 0; i < rep.count; i++) {
  451.       _XReadPad(dpy, (char *) &repBuffer, sizeof repBuffer);
  452.       buffers[i].attachment = repBuffer.attachment;
  453.       buffers[i].name = repBuffer.name;
  454.       buffers[i].pitch = repBuffer.pitch;
  455.       buffers[i].cpp = repBuffer.cpp;
  456.       buffers[i].flags = repBuffer.flags;
  457.    }
  458.  
  459.    UnlockDisplay(dpy);
  460.    SyncHandle();
  461.  
  462.    return buffers;
  463. }
  464.  
  465.  
  466. DRI2Buffer *
  467. DRI2GetBuffersWithFormat(Display * dpy, XID drawable,
  468.                          int *width, int *height,
  469.                          unsigned int *attachments, int count, int *outCount)
  470. {
  471.    XExtDisplayInfo *info = DRI2FindDisplay(dpy);
  472.    xDRI2GetBuffersReply rep;
  473.    xDRI2GetBuffersReq *req;
  474.    DRI2Buffer *buffers;
  475.    xDRI2Buffer repBuffer;
  476.    CARD32 *p;
  477.    int i;
  478.  
  479.    XextCheckExtension(dpy, info, dri2ExtensionName, False);
  480.  
  481.    LockDisplay(dpy);
  482.    GetReqExtra(DRI2GetBuffers, count * (4 * 2), req);
  483.    req->reqType = info->codes->major_opcode;
  484.    req->dri2ReqType = X_DRI2GetBuffersWithFormat;
  485.    req->drawable = drawable;
  486.    req->count = count;
  487.    p = (CARD32 *) & req[1];
  488.    for (i = 0; i < (count * 2); i++)
  489.       p[i] = attachments[i];
  490.  
  491.    if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) {
  492.       UnlockDisplay(dpy);
  493.       SyncHandle();
  494.       return NULL;
  495.    }
  496.  
  497.    *width = rep.width;
  498.    *height = rep.height;
  499.    *outCount = rep.count;
  500.  
  501.    buffers = malloc(rep.count * sizeof buffers[0]);
  502.    if (buffers == NULL) {
  503.       _XEatData(dpy, rep.count * sizeof repBuffer);
  504.       UnlockDisplay(dpy);
  505.       SyncHandle();
  506.       return NULL;
  507.    }
  508.  
  509.    for (i = 0; i < rep.count; i++) {
  510.       _XReadPad(dpy, (char *) &repBuffer, sizeof repBuffer);
  511.       buffers[i].attachment = repBuffer.attachment;
  512.       buffers[i].name = repBuffer.name;
  513.       buffers[i].pitch = repBuffer.pitch;
  514.       buffers[i].cpp = repBuffer.cpp;
  515.       buffers[i].flags = repBuffer.flags;
  516.    }
  517.  
  518.    UnlockDisplay(dpy);
  519.    SyncHandle();
  520.  
  521.    return buffers;
  522. }
  523.  
  524.  
  525. void
  526. DRI2CopyRegion(Display * dpy, XID drawable, XserverRegion region,
  527.                CARD32 dest, CARD32 src)
  528. {
  529.    XExtDisplayInfo *info = DRI2FindDisplay(dpy);
  530.    xDRI2CopyRegionReq *req;
  531.    xDRI2CopyRegionReply rep;
  532.  
  533.    XextSimpleCheckExtension(dpy, info, dri2ExtensionName);
  534.  
  535.    LockDisplay(dpy);
  536.    GetReq(DRI2CopyRegion, req);
  537.    req->reqType = info->codes->major_opcode;
  538.    req->dri2ReqType = X_DRI2CopyRegion;
  539.    req->drawable = drawable;
  540.    req->region = region;
  541.    req->dest = dest;
  542.    req->src = src;
  543.  
  544.    _XReply(dpy, (xReply *) & rep, 0, xFalse);
  545.  
  546.    UnlockDisplay(dpy);
  547.    SyncHandle();
  548. }
  549.  
  550. #endif /* GLX_DIRECT_RENDERING */
  551.