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 #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