vndcmds.c revision ed6184df
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. 44typedef struct GlxVendorPrivDispatchRec { 45 CARD32 vendorCode; 46 GlxServerDispatchProc proc; 47 HashTable hh; 48} GlxVendorPrivDispatch; 49 50static GlxServerDispatchProc dispatchFuncs[OPCODE_ARRAY_LEN] = {}; 51static HashTable vendorPrivHash = NULL; 52static HtGenericHashSetupRec vendorPrivSetup = { 53 .keySize = sizeof(CARD32) 54}; 55 56static int DispatchBadRequest(ClientPtr client) 57{ 58 return BadRequest; 59} 60 61static 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 76static 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 90static 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 104static 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 */ 126static 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 160static 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 174static 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 205static 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 280static 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 289static 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 298static 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 307static 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 332static 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 */ 361static 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 375static 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 400Bool 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 463void GlxDispatchReset(void) 464{ 465 memset(dispatchFuncs, 0, sizeof(dispatchFuncs)); 466 467 ht_destroy(vendorPrivHash); 468 vendorPrivHash = NULL; 469} 470 471int 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} 495