Home | History | Annotate | Download | only in glx
      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 Hgsberg (krh (at) 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    case DRI2_BufferSwapComplete:
     98    {
     99       GLXBufferSwapComplete *aevent = (GLXBufferSwapComplete *)event;
    100       xDRI2BufferSwapComplete2 *awire = (xDRI2BufferSwapComplete2 *)wire;
    101       __GLXDRIdrawable *pdraw;
    102 
    103       pdraw = dri2GetGlxDrawableFromXDrawableId(dpy, awire->drawable);
    104       if (pdraw == NULL)
    105          return False;
    106 
    107       /* Ignore swap events if we're not looking for them */
    108       aevent->type = dri2GetSwapEventType(dpy, awire->drawable);
    109       if(!aevent->type)
    110          return False;
    111 
    112       aevent->serial = _XSetLastRequestRead(dpy, (xGenericReply *) wire);
    113       aevent->send_event = (awire->type & 0x80) != 0;
    114       aevent->display = dpy;
    115       aevent->drawable = awire->drawable;
    116       switch (awire->event_type) {
    117       case DRI2_EXCHANGE_COMPLETE:
    118 	 aevent->event_type = GLX_EXCHANGE_COMPLETE_INTEL;
    119 	 break;
    120       case DRI2_BLIT_COMPLETE:
    121 	 aevent->event_type = GLX_COPY_COMPLETE_INTEL;
    122 	 break;
    123       case DRI2_FLIP_COMPLETE:
    124 	 aevent->event_type = GLX_FLIP_COMPLETE_INTEL;
    125 	 break;
    126       default:
    127 	 /* unknown swap completion type */
    128 	 return False;
    129       }
    130       aevent->ust = ((CARD64)awire->ust_hi << 32) | awire->ust_lo;
    131       aevent->msc = ((CARD64)awire->msc_hi << 32) | awire->msc_lo;
    132 
    133       glxDraw = GetGLXDrawable(dpy, pdraw->drawable);
    134       if (glxDraw != NULL) {
    135          if (awire->sbc < glxDraw->lastEventSbc)
    136             glxDraw->eventSbcWrap += 0x100000000;
    137          glxDraw->lastEventSbc = awire->sbc;
    138          aevent->sbc = awire->sbc + glxDraw->eventSbcWrap;
    139       } else {
    140          aevent->sbc = awire->sbc;
    141       }
    142 
    143       return True;
    144    }
    145    case DRI2_InvalidateBuffers:
    146    {
    147       xDRI2InvalidateBuffers *awire = (xDRI2InvalidateBuffers *)wire;
    148 
    149       dri2InvalidateBuffers(dpy, awire->drawable);
    150       return False;
    151    }
    152    default:
    153       /* client doesn't support server event */
    154       break;
    155    }
    156 
    157    return False;
    158 }
    159 
    160 /* We don't actually support this.  It doesn't make sense for clients to
    161  * send each other DRI2 events.
    162  */
    163 static Status
    164 DRI2EventToWire(Display *dpy, XEvent *event, xEvent *wire)
    165 {
    166    XExtDisplayInfo *info = DRI2FindDisplay(dpy);
    167 
    168    XextCheckExtension(dpy, info, dri2ExtensionName, False);
    169 
    170    switch (event->type) {
    171    default:
    172       /* client doesn't support server event */
    173       break;
    174    }
    175 
    176    return Success;
    177 }
    178 
    179 static int
    180 DRI2Error(Display *display, xError *err, XExtCodes *codes, int *ret_code)
    181 {
    182     if (err->majorCode == codes->major_opcode &&
    183 	err->errorCode == BadDrawable &&
    184 	err->minorCode == X_DRI2CopyRegion)
    185 	return True;
    186 
    187     /* If the X drawable was destroyed before the GLX drawable, the
    188      * DRI2 drawble will be gone by the time we call
    189      * DRI2DestroyDrawable.  So just ignore BadDrawable here. */
    190     if (err->majorCode == codes->major_opcode &&
    191 	err->errorCode == BadDrawable &&
    192 	err->minorCode == X_DRI2DestroyDrawable)
    193 	return True;
    194 
    195     /* If the server is non-local DRI2Connect will raise BadRequest.
    196      * Swallow this so that DRI2Connect can signal this in its return code */
    197     if (err->majorCode == codes->major_opcode &&
    198         err->minorCode == X_DRI2Connect &&
    199         err->errorCode == BadRequest) {
    200 	*ret_code = False;
    201 	return True;
    202     }
    203 
    204     return False;
    205 }
    206 
    207 Bool
    208 DRI2QueryExtension(Display * dpy, int *eventBase, int *errorBase)
    209 {
    210    XExtDisplayInfo *info = DRI2FindDisplay(dpy);
    211 
    212    if (XextHasExtension(info)) {
    213       *eventBase = info->codes->first_event;
    214       *errorBase = info->codes->first_error;
    215       return True;
    216    }
    217 
    218    return False;
    219 }
    220 
    221 Bool
    222 DRI2QueryVersion(Display * dpy, int *major, int *minor)
    223 {
    224    XExtDisplayInfo *info = DRI2FindDisplay(dpy);
    225    xDRI2QueryVersionReply rep;
    226    xDRI2QueryVersionReq *req;
    227    int i, nevents;
    228 
    229    XextCheckExtension(dpy, info, dri2ExtensionName, False);
    230 
    231    LockDisplay(dpy);
    232    GetReq(DRI2QueryVersion, req);
    233    req->reqType = info->codes->major_opcode;
    234    req->dri2ReqType = X_DRI2QueryVersion;
    235    req->majorVersion = DRI2_MAJOR;
    236    req->minorVersion = DRI2_MINOR;
    237    if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) {
    238       UnlockDisplay(dpy);
    239       SyncHandle();
    240       return False;
    241    }
    242    *major = rep.majorVersion;
    243    *minor = rep.minorVersion;
    244    UnlockDisplay(dpy);
    245    SyncHandle();
    246 
    247    switch (rep.minorVersion) {
    248    case 1:
    249 	   nevents = 0;
    250 	   break;
    251    case 2:
    252 	   nevents = 1;
    253 	   break;
    254    case 3:
    255    default:
    256 	   nevents = 2;
    257 	   break;
    258    }
    259 
    260    for (i = 0; i < nevents; i++) {
    261        XESetWireToEvent (dpy, info->codes->first_event + i, DRI2WireToEvent);
    262        XESetEventToWire (dpy, info->codes->first_event + i, DRI2EventToWire);
    263    }
    264 
    265    return True;
    266 }
    267 
    268 Bool
    269 DRI2Connect(Display * dpy, XID window, char **driverName, char **deviceName)
    270 {
    271    XExtDisplayInfo *info = DRI2FindDisplay(dpy);
    272    xDRI2ConnectReply rep;
    273    xDRI2ConnectReq *req;
    274 
    275    XextCheckExtension(dpy, info, dri2ExtensionName, False);
    276 
    277    LockDisplay(dpy);
    278    GetReq(DRI2Connect, req);
    279    req->reqType = info->codes->major_opcode;
    280    req->dri2ReqType = X_DRI2Connect;
    281    req->window = window;
    282 
    283    req->driverType = DRI2DriverDRI;
    284    {
    285       char *prime = getenv("DRI_PRIME");
    286       if (prime) {
    287          uint32_t primeid;
    288          errno = 0;
    289          primeid = strtoul(prime, NULL, 0);
    290          if (errno == 0)
    291             req->driverType |=
    292                ((primeid & DRI2DriverPrimeMask) << DRI2DriverPrimeShift);
    293       }
    294    }
    295 
    296    if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) {
    297       UnlockDisplay(dpy);
    298       SyncHandle();
    299       return False;
    300    }
    301 
    302    if (rep.driverNameLength == 0 && rep.deviceNameLength == 0) {
    303       UnlockDisplay(dpy);
    304       SyncHandle();
    305       return False;
    306    }
    307 
    308    *driverName = malloc(rep.driverNameLength + 1);
    309    if (*driverName == NULL) {
    310       _XEatData(dpy,
    311                 ((rep.driverNameLength + 3) & ~3) +
    312                 ((rep.deviceNameLength + 3) & ~3));
    313       UnlockDisplay(dpy);
    314       SyncHandle();
    315       return False;
    316    }
    317    _XReadPad(dpy, *driverName, rep.driverNameLength);
    318    (*driverName)[rep.driverNameLength] = '\0';
    319 
    320    *deviceName = malloc(rep.deviceNameLength + 1);
    321    if (*deviceName == NULL) {
    322       free(*driverName);
    323       _XEatData(dpy, ((rep.deviceNameLength + 3) & ~3));
    324       UnlockDisplay(dpy);
    325       SyncHandle();
    326       return False;
    327    }
    328    _XReadPad(dpy, *deviceName, rep.deviceNameLength);
    329    (*deviceName)[rep.deviceNameLength] = '\0';
    330 
    331    UnlockDisplay(dpy);
    332    SyncHandle();
    333 
    334    return True;
    335 }
    336 
    337 Bool
    338 DRI2Authenticate(Display * dpy, XID window, drm_magic_t magic)
    339 {
    340    XExtDisplayInfo *info = DRI2FindDisplay(dpy);
    341    xDRI2AuthenticateReq *req;
    342    xDRI2AuthenticateReply rep;
    343 
    344    XextCheckExtension(dpy, info, dri2ExtensionName, False);
    345 
    346    LockDisplay(dpy);
    347    GetReq(DRI2Authenticate, req);
    348    req->reqType = info->codes->major_opcode;
    349    req->dri2ReqType = X_DRI2Authenticate;
    350    req->window = window;
    351    req->magic = magic;
    352 
    353    if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) {
    354       UnlockDisplay(dpy);
    355       SyncHandle();
    356       return False;
    357    }
    358 
    359    UnlockDisplay(dpy);
    360    SyncHandle();
    361 
    362    return rep.authenticated;
    363 }
    364 
    365 void
    366 DRI2CreateDrawable(Display * dpy, XID drawable)
    367 {
    368    XExtDisplayInfo *info = DRI2FindDisplay(dpy);
    369    xDRI2CreateDrawableReq *req;
    370 
    371    XextSimpleCheckExtension(dpy, info, dri2ExtensionName);
    372 
    373    LockDisplay(dpy);
    374    GetReq(DRI2CreateDrawable, req);
    375    req->reqType = info->codes->major_opcode;
    376    req->dri2ReqType = X_DRI2CreateDrawable;
    377    req->drawable = drawable;
    378    UnlockDisplay(dpy);
    379    SyncHandle();
    380 }
    381 
    382 void
    383 DRI2DestroyDrawable(Display * dpy, XID drawable)
    384 {
    385    XExtDisplayInfo *info = DRI2FindDisplay(dpy);
    386    xDRI2DestroyDrawableReq *req;
    387 
    388    XextSimpleCheckExtension(dpy, info, dri2ExtensionName);
    389 
    390    XSync(dpy, False);
    391 
    392    LockDisplay(dpy);
    393    GetReq(DRI2DestroyDrawable, req);
    394    req->reqType = info->codes->major_opcode;
    395    req->dri2ReqType = X_DRI2DestroyDrawable;
    396    req->drawable = drawable;
    397    UnlockDisplay(dpy);
    398    SyncHandle();
    399 }
    400 
    401 DRI2Buffer *
    402 DRI2GetBuffers(Display * dpy, XID drawable,
    403                int *width, int *height,
    404                unsigned int *attachments, int count, int *outCount)
    405 {
    406    XExtDisplayInfo *info = DRI2FindDisplay(dpy);
    407    xDRI2GetBuffersReply rep;
    408    xDRI2GetBuffersReq *req;
    409    DRI2Buffer *buffers;
    410    xDRI2Buffer repBuffer;
    411    CARD32 *p;
    412    int i;
    413 
    414    XextCheckExtension(dpy, info, dri2ExtensionName, False);
    415 
    416    LockDisplay(dpy);
    417    GetReqExtra(DRI2GetBuffers, count * 4, req);
    418    req->reqType = info->codes->major_opcode;
    419    req->dri2ReqType = X_DRI2GetBuffers;
    420    req->drawable = drawable;
    421    req->count = count;
    422    p = (CARD32 *) & req[1];
    423    for (i = 0; i < count; i++)
    424       p[i] = attachments[i];
    425 
    426    if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) {
    427       UnlockDisplay(dpy);
    428       SyncHandle();
    429       return NULL;
    430    }
    431 
    432    *width = rep.width;
    433    *height = rep.height;
    434    *outCount = rep.count;
    435 
    436    buffers = malloc(rep.count * sizeof buffers[0]);
    437    if (buffers == NULL) {
    438       _XEatData(dpy, rep.count * sizeof repBuffer);
    439       UnlockDisplay(dpy);
    440       SyncHandle();
    441       return NULL;
    442    }
    443 
    444    for (i = 0; i < rep.count; i++) {
    445       _XReadPad(dpy, (char *) &repBuffer, sizeof repBuffer);
    446       buffers[i].attachment = repBuffer.attachment;
    447       buffers[i].name = repBuffer.name;
    448       buffers[i].pitch = repBuffer.pitch;
    449       buffers[i].cpp = repBuffer.cpp;
    450       buffers[i].flags = repBuffer.flags;
    451    }
    452 
    453    UnlockDisplay(dpy);
    454    SyncHandle();
    455 
    456    return buffers;
    457 }
    458 
    459 
    460 DRI2Buffer *
    461 DRI2GetBuffersWithFormat(Display * dpy, XID drawable,
    462                          int *width, int *height,
    463                          unsigned int *attachments, int count, int *outCount)
    464 {
    465    XExtDisplayInfo *info = DRI2FindDisplay(dpy);
    466    xDRI2GetBuffersReply rep;
    467    xDRI2GetBuffersReq *req;
    468    DRI2Buffer *buffers;
    469    xDRI2Buffer repBuffer;
    470    CARD32 *p;
    471    int i;
    472 
    473    XextCheckExtension(dpy, info, dri2ExtensionName, False);
    474 
    475    LockDisplay(dpy);
    476    GetReqExtra(DRI2GetBuffers, count * (4 * 2), req);
    477    req->reqType = info->codes->major_opcode;
    478    req->dri2ReqType = X_DRI2GetBuffersWithFormat;
    479    req->drawable = drawable;
    480    req->count = count;
    481    p = (CARD32 *) & req[1];
    482    for (i = 0; i < (count * 2); i++)
    483       p[i] = attachments[i];
    484 
    485    if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) {
    486       UnlockDisplay(dpy);
    487       SyncHandle();
    488       return NULL;
    489    }
    490 
    491    *width = rep.width;
    492    *height = rep.height;
    493    *outCount = rep.count;
    494 
    495    buffers = malloc(rep.count * sizeof buffers[0]);
    496    if (buffers == NULL) {
    497       _XEatData(dpy, rep.count * sizeof repBuffer);
    498       UnlockDisplay(dpy);
    499       SyncHandle();
    500       return NULL;
    501    }
    502 
    503    for (i = 0; i < rep.count; i++) {
    504       _XReadPad(dpy, (char *) &repBuffer, sizeof repBuffer);
    505       buffers[i].attachment = repBuffer.attachment;
    506       buffers[i].name = repBuffer.name;
    507       buffers[i].pitch = repBuffer.pitch;
    508       buffers[i].cpp = repBuffer.cpp;
    509       buffers[i].flags = repBuffer.flags;
    510    }
    511 
    512    UnlockDisplay(dpy);
    513    SyncHandle();
    514 
    515    return buffers;
    516 }
    517 
    518 
    519 void
    520 DRI2CopyRegion(Display * dpy, XID drawable, XserverRegion region,
    521                CARD32 dest, CARD32 src)
    522 {
    523    XExtDisplayInfo *info = DRI2FindDisplay(dpy);
    524    xDRI2CopyRegionReq *req;
    525    xDRI2CopyRegionReply rep;
    526 
    527    XextSimpleCheckExtension(dpy, info, dri2ExtensionName);
    528 
    529    LockDisplay(dpy);
    530    GetReq(DRI2CopyRegion, req);
    531    req->reqType = info->codes->major_opcode;
    532    req->dri2ReqType = X_DRI2CopyRegion;
    533    req->drawable = drawable;
    534    req->region = region;
    535    req->dest = dest;
    536    req->src = src;
    537 
    538    _XReply(dpy, (xReply *) & rep, 0, xFalse);
    539 
    540    UnlockDisplay(dpy);
    541    SyncHandle();
    542 }
    543 
    544 #endif /* GLX_DIRECT_RENDERING */
    545