xserver

xserver with xephyr scale patch
git clone https://git.neptards.moe/u3shit/xserver.git
Log | Files | Refs | README | LICENSE

vndcmds.c (16525B)


      1 /*
      2  * Copyright (c) 2016, NVIDIA CORPORATION.
      3  *
      4  * Permission is hereby granted, free of charge, to any person obtaining a
      5  * copy of this software and/or associated documentation files (the
      6  * "Materials"), to deal in the Materials without restriction, including
      7  * without limitation the rights to use, copy, modify, merge, publish,
      8  * distribute, sublicense, and/or sell copies of the Materials, and to
      9  * permit persons to whom the Materials are furnished to do so, subject to
     10  * the following conditions:
     11  *
     12  * The above copyright notice and this permission notice shall be included
     13  * unaltered in all copies or substantial portions of the Materials.
     14  * Any additions, deletions, or changes to the original source files
     15  * must be clearly indicated in accompanying documentation.
     16  *
     17  * If only executable code is distributed, then the accompanying
     18  * documentation must state that "this software is based in part on the
     19  * work of the Khronos Group."
     20  *
     21  * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
     22  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     23  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
     24  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
     25  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
     26  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
     27  * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
     28  */
     29 
     30 #include <dix-config.h>
     31 
     32 #include "hashtable.h"
     33 #include "vndserver.h"
     34 #include "vndservervendor.h"
     35 
     36 /**
     37  * The length of the dispatchFuncs array. Every opcode above this is a
     38  * X_GLsop_* code, which all can use the same handler.
     39  */
     40 #define OPCODE_ARRAY_LEN 100
     41 
     42 // This hashtable is used to keep track of the dispatch stubs for
     43 // GLXVendorPrivate and GLXVendorPrivateWithReply.
     44 typedef struct GlxVendorPrivDispatchRec {
     45     CARD32 vendorCode;
     46     GlxServerDispatchProc proc;
     47     HashTable hh;
     48 } GlxVendorPrivDispatch;
     49 
     50 static GlxServerDispatchProc dispatchFuncs[OPCODE_ARRAY_LEN] = {};
     51 static HashTable vendorPrivHash = NULL;
     52 static HtGenericHashSetupRec vendorPrivSetup = {
     53     .keySize = sizeof(CARD32)
     54 };
     55 
     56 static int DispatchBadRequest(ClientPtr client)
     57 {
     58     return BadRequest;
     59 }
     60 
     61 static GlxVendorPrivDispatch *LookupVendorPrivDispatch(CARD32 vendorCode, Bool create)
     62 {
     63     GlxVendorPrivDispatch *disp = NULL;
     64 
     65     disp = ht_find(vendorPrivHash, &vendorCode);
     66     if (disp == NULL && create) {
     67         if ((disp = ht_add(vendorPrivHash, &vendorCode))) {
     68             disp->vendorCode = vendorCode;
     69             disp->proc = NULL;
     70         }
     71     }
     72 
     73     return disp;
     74 }
     75 
     76 static GlxServerDispatchProc GetVendorDispatchFunc(CARD8 opcode, CARD32 vendorCode)
     77 {
     78     GlxServerVendor *vendor;
     79 
     80     xorg_list_for_each_entry(vendor, &GlxVendorList, entry) {
     81         GlxServerDispatchProc proc = vendor->glxvc.getDispatchAddress(opcode, vendorCode);
     82         if (proc != NULL) {
     83             return proc;
     84         }
     85     }
     86 
     87     return DispatchBadRequest;
     88 }
     89 
     90 static void SetReplyHeader(ClientPtr client, void *replyPtr)
     91 {
     92     xGenericReply *rep = (xGenericReply *) replyPtr;
     93     rep->type = X_Reply;
     94     rep->sequenceNumber = client->sequence;
     95     if (client->swapped) {
     96 	swaps(&rep->sequenceNumber);
     97     }
     98     rep->length = 0;
     99 }
    100 
    101 /* Include the trivial dispatch handlers */
    102 #include "vnd_dispatch_stubs.c"
    103 
    104 static int dispatch_GLXQueryVersion(ClientPtr client)
    105 {
    106     xGLXQueryVersionReply reply;
    107     REQUEST_SIZE_MATCH(xGLXQueryVersionReq);
    108 
    109     SetReplyHeader(client, &reply);
    110     reply.majorVersion = GlxCheckSwap(client, 1);
    111     reply.minorVersion = GlxCheckSwap(client, 4);
    112 
    113     WriteToClient(client, sz_xGLXQueryVersionReply, &reply);
    114     return Success;
    115 }
    116 
    117 /* broken header workaround */
    118 #ifndef X_GLXSetClientInfo2ARB
    119 #define X_GLXSetClientInfo2ARB X_GLXSetConfigInfo2ARB
    120 #endif
    121 
    122 /**
    123  * This function is used for X_GLXClientInfo, X_GLXSetClientInfoARB, and
    124  * X_GLXSetClientInfo2ARB.
    125  */
    126 static int dispatch_GLXClientInfo(ClientPtr client)
    127 {
    128     GlxServerVendor *vendor;
    129     void *requestCopy = NULL;
    130     size_t requestSize = client->req_len * 4;
    131 
    132     if (client->minorOp == X_GLXClientInfo) {
    133         REQUEST_AT_LEAST_SIZE(xGLXClientInfoReq);
    134     } else if (client->minorOp == X_GLXSetClientInfoARB) {
    135         REQUEST_AT_LEAST_SIZE(xGLXSetClientInfoARBReq);
    136     } else if (client->minorOp == X_GLXSetClientInfo2ARB) {
    137         REQUEST_AT_LEAST_SIZE(xGLXSetClientInfo2ARBReq);
    138     } else {
    139         return BadImplementation;
    140     }
    141 
    142     // We'll forward this request to each vendor library. Since a vendor might
    143     // modify the request data in place (e.g., for byte swapping), make a copy
    144     // of the request first.
    145     requestCopy = malloc(requestSize);
    146     if (requestCopy == NULL) {
    147         return BadAlloc;
    148     }
    149     memcpy(requestCopy, client->requestBuffer, requestSize);
    150 
    151     xorg_list_for_each_entry(vendor, &GlxVendorList, entry) {
    152         vendor->glxvc.handleRequest(client);
    153         // Revert the request buffer back to our copy.
    154         memcpy(client->requestBuffer, requestCopy, requestSize);
    155     }
    156     free(requestCopy);
    157     return Success;
    158 }
    159 
    160 static int CommonLoseCurrent(ClientPtr client, GlxContextTagInfo *tagInfo)
    161 {
    162     int ret;
    163 
    164     ret = tagInfo->vendor->glxvc.makeCurrent(client,
    165             tagInfo->tag, // No old context tag,
    166             None, None, None, 0);
    167 
    168     if (ret == Success) {
    169         GlxFreeContextTag(tagInfo);
    170     }
    171     return ret;
    172 }
    173 
    174 static int CommonMakeNewCurrent(ClientPtr client,
    175         GlxServerVendor *vendor,
    176         GLXDrawable drawable,
    177         GLXDrawable readdrawable,
    178         GLXContextID context,
    179         GLXContextTag *newContextTag)
    180 {
    181     int ret = BadAlloc;
    182     GlxContextTagInfo *tagInfo;
    183 
    184     tagInfo = GlxAllocContextTag(client, vendor);
    185 
    186     if (tagInfo) {
    187         ret = vendor->glxvc.makeCurrent(client,
    188                 0, // No old context tag,
    189                 drawable, readdrawable, context,
    190                 tagInfo->tag);
    191 
    192         if (ret == Success) {
    193             tagInfo->drawable = drawable;
    194             tagInfo->readdrawable = readdrawable;
    195             tagInfo->context = context;
    196             *newContextTag = tagInfo->tag;
    197         } else {
    198             GlxFreeContextTag(tagInfo);
    199         }
    200     }
    201 
    202     return ret;
    203 }
    204 
    205 static int CommonMakeCurrent(ClientPtr client,
    206         GLXContextTag oldContextTag,
    207         GLXDrawable drawable,
    208         GLXDrawable readdrawable,
    209         GLXContextID context)
    210 {
    211     xGLXMakeCurrentReply reply = {};
    212     GlxContextTagInfo *oldTag = NULL;
    213     GlxServerVendor *newVendor = NULL;
    214 
    215     oldContextTag = GlxCheckSwap(client, oldContextTag);
    216     drawable = GlxCheckSwap(client, drawable);
    217     readdrawable = GlxCheckSwap(client, readdrawable);
    218     context = GlxCheckSwap(client, context);
    219 
    220     SetReplyHeader(client, &reply);
    221 
    222     if (oldContextTag != 0) {
    223         oldTag = GlxLookupContextTag(client, oldContextTag);
    224         if (oldTag == NULL) {
    225             return GlxErrorBase + GLXBadContextTag;
    226         }
    227     }
    228     if (context != 0) {
    229         newVendor = GlxGetXIDMap(context);
    230         if (newVendor == NULL) {
    231             return GlxErrorBase + GLXBadContext;
    232         }
    233     }
    234 
    235     if (oldTag == NULL && newVendor == NULL) {
    236         // Nothing to do here. Just send a successful reply.
    237         reply.contextTag = 0;
    238     } else if (oldTag != NULL && newVendor != NULL
    239             && oldTag->context == context
    240             && oldTag->drawable == drawable
    241             && oldTag->readdrawable == readdrawable)
    242     {
    243         // The old and new values are all the same, so send a successful reply.
    244         reply.contextTag = oldTag->tag;
    245     } else {
    246         // TODO: For switching contexts in a single vendor, just make one
    247         // makeCurrent call?
    248 
    249         // TODO: When changing vendors, would it be better to do the
    250         // MakeCurrent(new) first, then the LoseCurrent(old)?
    251         // If the MakeCurrent(new) fails, then the old context will still be current.
    252         // If the LoseCurrent(old) fails, then we can (probably) undo the MakeCurrent(new) with
    253         // a LoseCurrent(old).
    254         // But, if the recovery LoseCurrent(old) fails, then we're really in a bad state.
    255 
    256         // Clear the old context first.
    257         if (oldTag != NULL) {
    258             int ret = CommonLoseCurrent(client, oldTag);
    259             if (ret != Success) {
    260                 return ret;
    261             }
    262             oldTag = NULL;
    263         }
    264 
    265         if (newVendor != NULL) {
    266             int ret = CommonMakeNewCurrent(client, newVendor, drawable, readdrawable, context, &reply.contextTag);
    267             if (ret != Success) {
    268                 return ret;
    269             }
    270         } else {
    271             reply.contextTag = 0;
    272         }
    273     }
    274 
    275     reply.contextTag = GlxCheckSwap(client, reply.contextTag);
    276     WriteToClient(client, sz_xGLXMakeCurrentReply, &reply);
    277     return Success;
    278 }
    279 
    280 static int dispatch_GLXMakeCurrent(ClientPtr client)
    281 {
    282     REQUEST(xGLXMakeCurrentReq);
    283     REQUEST_SIZE_MATCH(*stuff);
    284 
    285     return CommonMakeCurrent(client, stuff->oldContextTag,
    286             stuff->drawable, stuff->drawable, stuff->context);
    287 }
    288 
    289 static int dispatch_GLXMakeContextCurrent(ClientPtr client)
    290 {
    291     REQUEST(xGLXMakeContextCurrentReq);
    292     REQUEST_SIZE_MATCH(*stuff);
    293 
    294     return CommonMakeCurrent(client, stuff->oldContextTag,
    295             stuff->drawable, stuff->readdrawable, stuff->context);
    296 }
    297 
    298 static int dispatch_GLXMakeCurrentReadSGI(ClientPtr client)
    299 {
    300     REQUEST(xGLXMakeCurrentReadSGIReq);
    301     REQUEST_SIZE_MATCH(*stuff);
    302 
    303     return CommonMakeCurrent(client, stuff->oldContextTag,
    304             stuff->drawable, stuff->readable, stuff->context);
    305 }
    306 
    307 static int dispatch_GLXCopyContext(ClientPtr client)
    308 {
    309     REQUEST(xGLXCopyContextReq);
    310     GlxServerVendor *vendor;
    311     REQUEST_SIZE_MATCH(*stuff);
    312 
    313     // If we've got a context tag, then we'll use it to select a vendor. If we
    314     // don't have a tag, then we'll look up one of the contexts. In either
    315     // case, it's up to the vendor library to make sure that the context ID's
    316     // are valid.
    317     if (stuff->contextTag != 0) {
    318         GlxContextTagInfo *tagInfo = GlxLookupContextTag(client, GlxCheckSwap(client, stuff->contextTag));
    319         if (tagInfo == NULL) {
    320             return GlxErrorBase + GLXBadContextTag;
    321         }
    322         vendor = tagInfo->vendor;
    323     } else {
    324         vendor = GlxGetXIDMap(GlxCheckSwap(client, stuff->source));
    325         if (vendor == NULL) {
    326             return GlxErrorBase + GLXBadContext;
    327         }
    328     }
    329     return vendor->glxvc.handleRequest(client);
    330 }
    331 
    332 static int dispatch_GLXSwapBuffers(ClientPtr client)
    333 {
    334     GlxServerVendor *vendor = NULL;
    335     REQUEST(xGLXSwapBuffersReq);
    336     REQUEST_SIZE_MATCH(*stuff);
    337 
    338     if (stuff->contextTag != 0) {
    339         // If the request has a context tag, then look up a vendor from that.
    340         // The vendor library is then responsible for validating the drawable.
    341         GlxContextTagInfo *tagInfo = GlxLookupContextTag(client, GlxCheckSwap(client, stuff->contextTag));
    342         if (tagInfo == NULL) {
    343             return GlxErrorBase + GLXBadContextTag;
    344         }
    345         vendor = tagInfo->vendor;
    346     } else {
    347         // We don't have a context tag, so look up the vendor from the
    348         // drawable.
    349         vendor = GlxGetXIDMap(GlxCheckSwap(client, stuff->drawable));
    350         if (vendor == NULL) {
    351             return GlxErrorBase + GLXBadDrawable;
    352         }
    353     }
    354 
    355     return vendor->glxvc.handleRequest(client);
    356 }
    357 
    358 /**
    359  * This is a generic handler for all of the X_GLXsop* requests.
    360  */
    361 static int dispatch_GLXSingle(ClientPtr client)
    362 {
    363     REQUEST(xGLXSingleReq);
    364     GlxContextTagInfo *tagInfo;
    365     REQUEST_AT_LEAST_SIZE(*stuff);
    366 
    367     tagInfo = GlxLookupContextTag(client, GlxCheckSwap(client, stuff->contextTag));
    368     if (tagInfo != NULL) {
    369         return tagInfo->vendor->glxvc.handleRequest(client);
    370     } else {
    371         return GlxErrorBase + GLXBadContextTag;
    372     }
    373 }
    374 
    375 static int dispatch_GLXVendorPriv(ClientPtr client)
    376 {
    377     GlxVendorPrivDispatch *disp;
    378     REQUEST(xGLXVendorPrivateReq);
    379     REQUEST_AT_LEAST_SIZE(*stuff);
    380 
    381     disp = LookupVendorPrivDispatch(GlxCheckSwap(client, stuff->vendorCode), TRUE);
    382     if (disp == NULL) {
    383         return BadAlloc;
    384     }
    385 
    386     if (disp->proc == NULL) {
    387         // We don't have a dispatch function for this request yet. Check with
    388         // each vendor library to find one.
    389         // Note that even if none of the vendors provides a dispatch stub,
    390         // we'll still add an entry to the dispatch table, so that we don't
    391         // have to look it up again later.
    392 
    393         disp->proc = GetVendorDispatchFunc(stuff->glxCode,
    394                                            GlxCheckSwap(client,
    395                                                         stuff->vendorCode));
    396     }
    397     return disp->proc(client);
    398 }
    399 
    400 Bool GlxDispatchInit(void)
    401 {
    402     GlxVendorPrivDispatch *disp;
    403 
    404     vendorPrivHash = ht_create(sizeof(CARD32), sizeof(GlxVendorPrivDispatch),
    405                                ht_generic_hash, ht_generic_compare,
    406                                (void *) &vendorPrivSetup);
    407     if (!vendorPrivHash) {
    408         return FALSE;
    409     }
    410 
    411     // Assign a custom dispatch stub GLXMakeCurrentReadSGI. This is the only
    412     // vendor private request that we need to deal with in libglvnd itself.
    413     disp = LookupVendorPrivDispatch(X_GLXvop_MakeCurrentReadSGI, TRUE);
    414     if (disp == NULL) {
    415         return FALSE;
    416     }
    417     disp->proc = dispatch_GLXMakeCurrentReadSGI;
    418 
    419     // Assign the dispatch stubs for requests that need special handling.
    420     dispatchFuncs[X_GLXQueryVersion] = dispatch_GLXQueryVersion;
    421     dispatchFuncs[X_GLXMakeCurrent] = dispatch_GLXMakeCurrent;
    422     dispatchFuncs[X_GLXMakeContextCurrent] = dispatch_GLXMakeContextCurrent;
    423     dispatchFuncs[X_GLXCopyContext] = dispatch_GLXCopyContext;
    424     dispatchFuncs[X_GLXSwapBuffers] = dispatch_GLXSwapBuffers;
    425 
    426     dispatchFuncs[X_GLXClientInfo] = dispatch_GLXClientInfo;
    427     dispatchFuncs[X_GLXSetClientInfoARB] = dispatch_GLXClientInfo;
    428     dispatchFuncs[X_GLXSetClientInfo2ARB] = dispatch_GLXClientInfo;
    429 
    430     dispatchFuncs[X_GLXVendorPrivate] = dispatch_GLXVendorPriv;
    431     dispatchFuncs[X_GLXVendorPrivateWithReply] = dispatch_GLXVendorPriv;
    432 
    433     // Assign the trivial stubs
    434     dispatchFuncs[X_GLXRender] = dispatch_Render;
    435     dispatchFuncs[X_GLXRenderLarge] = dispatch_RenderLarge;
    436     dispatchFuncs[X_GLXCreateContext] = dispatch_CreateContext;
    437     dispatchFuncs[X_GLXDestroyContext] = dispatch_DestroyContext;
    438     dispatchFuncs[X_GLXWaitGL] = dispatch_WaitGL;
    439     dispatchFuncs[X_GLXWaitX] = dispatch_WaitX;
    440     dispatchFuncs[X_GLXUseXFont] = dispatch_UseXFont;
    441     dispatchFuncs[X_GLXCreateGLXPixmap] = dispatch_CreateGLXPixmap;
    442     dispatchFuncs[X_GLXGetVisualConfigs] = dispatch_GetVisualConfigs;
    443     dispatchFuncs[X_GLXDestroyGLXPixmap] = dispatch_DestroyGLXPixmap;
    444     dispatchFuncs[X_GLXQueryExtensionsString] = dispatch_QueryExtensionsString;
    445     dispatchFuncs[X_GLXQueryServerString] = dispatch_QueryServerString;
    446     dispatchFuncs[X_GLXChangeDrawableAttributes] = dispatch_ChangeDrawableAttributes;
    447     dispatchFuncs[X_GLXCreateNewContext] = dispatch_CreateNewContext;
    448     dispatchFuncs[X_GLXCreatePbuffer] = dispatch_CreatePbuffer;
    449     dispatchFuncs[X_GLXCreatePixmap] = dispatch_CreatePixmap;
    450     dispatchFuncs[X_GLXCreateWindow] = dispatch_CreateWindow;
    451     dispatchFuncs[X_GLXCreateContextAttribsARB] = dispatch_CreateContextAttribsARB;
    452     dispatchFuncs[X_GLXDestroyPbuffer] = dispatch_DestroyPbuffer;
    453     dispatchFuncs[X_GLXDestroyPixmap] = dispatch_DestroyPixmap;
    454     dispatchFuncs[X_GLXDestroyWindow] = dispatch_DestroyWindow;
    455     dispatchFuncs[X_GLXGetDrawableAttributes] = dispatch_GetDrawableAttributes;
    456     dispatchFuncs[X_GLXGetFBConfigs] = dispatch_GetFBConfigs;
    457     dispatchFuncs[X_GLXQueryContext] = dispatch_QueryContext;
    458     dispatchFuncs[X_GLXIsDirect] = dispatch_IsDirect;
    459 
    460     return TRUE;
    461 }
    462 
    463 void GlxDispatchReset(void)
    464 {
    465     memset(dispatchFuncs, 0, sizeof(dispatchFuncs));
    466 
    467     ht_destroy(vendorPrivHash);
    468     vendorPrivHash = NULL;
    469 }
    470 
    471 int GlxDispatchRequest(ClientPtr client)
    472 {
    473     REQUEST(xReq);
    474     int result;
    475 
    476     if (GlxExtensionEntry->base == 0)
    477         return BadRequest;
    478 
    479     GlxSetRequestClient(client);
    480 
    481     if (stuff->data < OPCODE_ARRAY_LEN) {
    482         if (dispatchFuncs[stuff->data] == NULL) {
    483             // Try to find a dispatch stub.
    484             dispatchFuncs[stuff->data] = GetVendorDispatchFunc(stuff->data, 0);
    485         }
    486         result = dispatchFuncs[stuff->data](client);
    487     } else {
    488         result = dispatch_GLXSingle(client);
    489     }
    490 
    491     GlxSetRequestClient(NULL);
    492 
    493     return result;
    494 }