vndcmds.c revision 25da500f
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 rep->length = 0; 96} 97 98/* Include the trivial dispatch handlers */ 99#include "vnd_dispatch_stubs.c" 100 101static int dispatch_GLXQueryVersion(ClientPtr client) 102{ 103 xGLXQueryVersionReply reply; 104 REQUEST_SIZE_MATCH(xGLXQueryVersionReq); 105 106 SetReplyHeader(client, &reply); 107 reply.majorVersion = GlxCheckSwap(client, 1); 108 reply.minorVersion = GlxCheckSwap(client, 4); 109 110 WriteToClient(client, sz_xGLXQueryVersionReply, &reply); 111 return Success; 112} 113 114/* broken header workaround */ 115#ifndef X_GLXSetClientInfo2ARB 116#define X_GLXSetClientInfo2ARB X_GLXSetConfigInfo2ARB 117#endif 118 119/** 120 * This function is used for X_GLXClientInfo, X_GLXSetClientInfoARB, and 121 * X_GLXSetClientInfo2ARB. 122 */ 123static int dispatch_GLXClientInfo(ClientPtr client) 124{ 125 GlxServerVendor *vendor; 126 void *requestCopy = NULL; 127 size_t requestSize = client->req_len * 4; 128 129 if (client->minorOp == X_GLXClientInfo) { 130 REQUEST_AT_LEAST_SIZE(xGLXClientInfoReq); 131 } else if (client->minorOp == X_GLXSetClientInfoARB) { 132 REQUEST_AT_LEAST_SIZE(xGLXSetClientInfoARBReq); 133 } else if (client->minorOp == X_GLXSetClientInfo2ARB) { 134 REQUEST_AT_LEAST_SIZE(xGLXSetClientInfo2ARBReq); 135 } else { 136 return BadImplementation; 137 } 138 139 // We'll forward this request to each vendor library. Since a vendor might 140 // modify the request data in place (e.g., for byte swapping), make a copy 141 // of the request first. 142 requestCopy = malloc(requestSize); 143 if (requestCopy == NULL) { 144 return BadAlloc; 145 } 146 memcpy(requestCopy, client->requestBuffer, requestSize); 147 148 xorg_list_for_each_entry(vendor, &GlxVendorList, entry) { 149 vendor->glxvc.handleRequest(client); 150 // Revert the request buffer back to our copy. 151 memcpy(client->requestBuffer, requestCopy, requestSize); 152 } 153 free(requestCopy); 154 return Success; 155} 156 157static int CommonLoseCurrent(ClientPtr client, GlxContextTagInfo *tagInfo) 158{ 159 int ret; 160 161 ret = tagInfo->vendor->glxvc.makeCurrent(client, 162 tagInfo->tag, // No old context tag, 163 None, None, None, 0); 164 165 if (ret == Success) { 166 GlxFreeContextTag(tagInfo); 167 } 168 return ret; 169} 170 171static int CommonMakeNewCurrent(ClientPtr client, 172 GlxServerVendor *vendor, 173 GLXDrawable drawable, 174 GLXDrawable readdrawable, 175 GLXContextID context, 176 GLXContextTag *newContextTag) 177{ 178 int ret = BadAlloc; 179 GlxContextTagInfo *tagInfo; 180 181 tagInfo = GlxAllocContextTag(client, vendor); 182 183 if (tagInfo) { 184 ret = vendor->glxvc.makeCurrent(client, 185 0, // No old context tag, 186 drawable, readdrawable, context, 187 tagInfo->tag); 188 189 if (ret == Success) { 190 tagInfo->drawable = drawable; 191 tagInfo->readdrawable = readdrawable; 192 tagInfo->context = context; 193 *newContextTag = tagInfo->tag; 194 } else { 195 GlxFreeContextTag(tagInfo); 196 } 197 } 198 199 return ret; 200} 201 202static int CommonMakeCurrent(ClientPtr client, 203 GLXContextTag oldContextTag, 204 GLXDrawable drawable, 205 GLXDrawable readdrawable, 206 GLXContextID context) 207{ 208 xGLXMakeCurrentReply reply = {}; 209 GlxContextTagInfo *oldTag = NULL; 210 GlxServerVendor *newVendor = NULL; 211 212 oldContextTag = GlxCheckSwap(client, oldContextTag); 213 drawable = GlxCheckSwap(client, drawable); 214 readdrawable = GlxCheckSwap(client, readdrawable); 215 context = GlxCheckSwap(client, context); 216 217 SetReplyHeader(client, &reply); 218 219 if (oldContextTag != 0) { 220 oldTag = GlxLookupContextTag(client, oldContextTag); 221 if (oldTag == NULL) { 222 return GlxErrorBase + GLXBadContextTag; 223 } 224 } 225 if (context != 0) { 226 newVendor = GlxGetXIDMap(context); 227 if (newVendor == NULL) { 228 return GlxErrorBase + GLXBadContext; 229 } 230 } 231 232 if (oldTag == NULL && newVendor == NULL) { 233 // Nothing to do here. Just send a successful reply. 234 reply.contextTag = 0; 235 } else if (oldTag != NULL && newVendor != NULL 236 && oldTag->context == context 237 && oldTag->drawable == drawable 238 && oldTag->readdrawable == readdrawable) 239 { 240 // The old and new values are all the same, so send a successful reply. 241 reply.contextTag = oldTag->tag; 242 } else { 243 // TODO: For switching contexts in a single vendor, just make one 244 // makeCurrent call? 245 246 // TODO: When changing vendors, would it be better to do the 247 // MakeCurrent(new) first, then the LoseCurrent(old)? 248 // If the MakeCurrent(new) fails, then the old context will still be current. 249 // If the LoseCurrent(old) fails, then we can (probably) undo the MakeCurrent(new) with 250 // a LoseCurrent(old). 251 // But, if the recovery LoseCurrent(old) fails, then we're really in a bad state. 252 253 // Clear the old context first. 254 if (oldTag != NULL) { 255 int ret = CommonLoseCurrent(client, oldTag); 256 if (ret != Success) { 257 return ret; 258 } 259 oldTag = NULL; 260 } 261 262 if (newVendor != NULL) { 263 int ret = CommonMakeNewCurrent(client, newVendor, drawable, readdrawable, context, &reply.contextTag); 264 if (ret != Success) { 265 return ret; 266 } 267 } else { 268 reply.contextTag = 0; 269 } 270 } 271 272 reply.contextTag = GlxCheckSwap(client, reply.contextTag); 273 WriteToClient(client, sz_xGLXMakeCurrentReply, &reply); 274 return Success; 275} 276 277static int dispatch_GLXMakeCurrent(ClientPtr client) 278{ 279 REQUEST(xGLXMakeCurrentReq); 280 REQUEST_SIZE_MATCH(*stuff); 281 282 return CommonMakeCurrent(client, stuff->oldContextTag, 283 stuff->drawable, stuff->drawable, stuff->context); 284} 285 286static int dispatch_GLXMakeContextCurrent(ClientPtr client) 287{ 288 REQUEST(xGLXMakeContextCurrentReq); 289 REQUEST_SIZE_MATCH(*stuff); 290 291 return CommonMakeCurrent(client, stuff->oldContextTag, 292 stuff->drawable, stuff->readdrawable, stuff->context); 293} 294 295static int dispatch_GLXMakeCurrentReadSGI(ClientPtr client) 296{ 297 REQUEST(xGLXMakeCurrentReadSGIReq); 298 REQUEST_SIZE_MATCH(*stuff); 299 300 return CommonMakeCurrent(client, stuff->oldContextTag, 301 stuff->drawable, stuff->readable, stuff->context); 302} 303 304static int dispatch_GLXCopyContext(ClientPtr client) 305{ 306 REQUEST(xGLXCopyContextReq); 307 GlxServerVendor *vendor; 308 REQUEST_SIZE_MATCH(*stuff); 309 310 // If we've got a context tag, then we'll use it to select a vendor. If we 311 // don't have a tag, then we'll look up one of the contexts. In either 312 // case, it's up to the vendor library to make sure that the context ID's 313 // are valid. 314 if (stuff->contextTag != 0) { 315 GlxContextTagInfo *tagInfo = GlxLookupContextTag(client, GlxCheckSwap(client, stuff->contextTag)); 316 if (tagInfo == NULL) { 317 return GlxErrorBase + GLXBadContextTag; 318 } 319 vendor = tagInfo->vendor; 320 } else { 321 vendor = GlxGetXIDMap(GlxCheckSwap(client, stuff->source)); 322 if (vendor == NULL) { 323 return GlxErrorBase + GLXBadContext; 324 } 325 } 326 return vendor->glxvc.handleRequest(client); 327} 328 329static int dispatch_GLXSwapBuffers(ClientPtr client) 330{ 331 GlxServerVendor *vendor = NULL; 332 REQUEST(xGLXSwapBuffersReq); 333 REQUEST_SIZE_MATCH(*stuff); 334 335 if (stuff->contextTag != 0) { 336 // If the request has a context tag, then look up a vendor from that. 337 // The vendor library is then responsible for validating the drawable. 338 GlxContextTagInfo *tagInfo = GlxLookupContextTag(client, GlxCheckSwap(client, stuff->contextTag)); 339 if (tagInfo == NULL) { 340 return GlxErrorBase + GLXBadContextTag; 341 } 342 vendor = tagInfo->vendor; 343 } else { 344 // We don't have a context tag, so look up the vendor from the 345 // drawable. 346 vendor = GlxGetXIDMap(GlxCheckSwap(client, stuff->drawable)); 347 if (vendor == NULL) { 348 return GlxErrorBase + GLXBadDrawable; 349 } 350 } 351 352 return vendor->glxvc.handleRequest(client); 353} 354 355/** 356 * This is a generic handler for all of the X_GLXsop* requests. 357 */ 358static int dispatch_GLXSingle(ClientPtr client) 359{ 360 REQUEST(xGLXSingleReq); 361 GlxContextTagInfo *tagInfo; 362 REQUEST_AT_LEAST_SIZE(*stuff); 363 364 tagInfo = GlxLookupContextTag(client, GlxCheckSwap(client, stuff->contextTag)); 365 if (tagInfo != NULL) { 366 return tagInfo->vendor->glxvc.handleRequest(client); 367 } else { 368 return GlxErrorBase + GLXBadContextTag; 369 } 370} 371 372static int dispatch_GLXVendorPriv(ClientPtr client) 373{ 374 GlxVendorPrivDispatch *disp; 375 REQUEST(xGLXVendorPrivateReq); 376 REQUEST_AT_LEAST_SIZE(*stuff); 377 378 disp = LookupVendorPrivDispatch(GlxCheckSwap(client, stuff->vendorCode), TRUE); 379 if (disp == NULL) { 380 return BadAlloc; 381 } 382 383 if (disp->proc == NULL) { 384 // We don't have a dispatch function for this request yet. Check with 385 // each vendor library to find one. 386 // Note that even if none of the vendors provides a dispatch stub, 387 // we'll still add an entry to the dispatch table, so that we don't 388 // have to look it up again later. 389 390 disp->proc = GetVendorDispatchFunc(stuff->glxCode, 391 GlxCheckSwap(client, 392 stuff->vendorCode)); 393 } 394 return disp->proc(client); 395} 396 397Bool GlxDispatchInit(void) 398{ 399 GlxVendorPrivDispatch *disp; 400 401 vendorPrivHash = ht_create(sizeof(CARD32), sizeof(GlxVendorPrivDispatch), 402 ht_generic_hash, ht_generic_compare, 403 (void *) &vendorPrivSetup); 404 if (!vendorPrivHash) { 405 return FALSE; 406 } 407 408 // Assign a custom dispatch stub GLXMakeCurrentReadSGI. This is the only 409 // vendor private request that we need to deal with in libglvnd itself. 410 disp = LookupVendorPrivDispatch(X_GLXvop_MakeCurrentReadSGI, TRUE); 411 if (disp == NULL) { 412 return FALSE; 413 } 414 disp->proc = dispatch_GLXMakeCurrentReadSGI; 415 416 // Assign the dispatch stubs for requests that need special handling. 417 dispatchFuncs[X_GLXQueryVersion] = dispatch_GLXQueryVersion; 418 dispatchFuncs[X_GLXMakeCurrent] = dispatch_GLXMakeCurrent; 419 dispatchFuncs[X_GLXMakeContextCurrent] = dispatch_GLXMakeContextCurrent; 420 dispatchFuncs[X_GLXCopyContext] = dispatch_GLXCopyContext; 421 dispatchFuncs[X_GLXSwapBuffers] = dispatch_GLXSwapBuffers; 422 423 dispatchFuncs[X_GLXClientInfo] = dispatch_GLXClientInfo; 424 dispatchFuncs[X_GLXSetClientInfoARB] = dispatch_GLXClientInfo; 425 dispatchFuncs[X_GLXSetClientInfo2ARB] = dispatch_GLXClientInfo; 426 427 dispatchFuncs[X_GLXVendorPrivate] = dispatch_GLXVendorPriv; 428 dispatchFuncs[X_GLXVendorPrivateWithReply] = dispatch_GLXVendorPriv; 429 430 // Assign the trivial stubs 431 dispatchFuncs[X_GLXRender] = dispatch_Render; 432 dispatchFuncs[X_GLXRenderLarge] = dispatch_RenderLarge; 433 dispatchFuncs[X_GLXCreateContext] = dispatch_CreateContext; 434 dispatchFuncs[X_GLXDestroyContext] = dispatch_DestroyContext; 435 dispatchFuncs[X_GLXWaitGL] = dispatch_WaitGL; 436 dispatchFuncs[X_GLXWaitX] = dispatch_WaitX; 437 dispatchFuncs[X_GLXUseXFont] = dispatch_UseXFont; 438 dispatchFuncs[X_GLXCreateGLXPixmap] = dispatch_CreateGLXPixmap; 439 dispatchFuncs[X_GLXGetVisualConfigs] = dispatch_GetVisualConfigs; 440 dispatchFuncs[X_GLXDestroyGLXPixmap] = dispatch_DestroyGLXPixmap; 441 dispatchFuncs[X_GLXQueryExtensionsString] = dispatch_QueryExtensionsString; 442 dispatchFuncs[X_GLXQueryServerString] = dispatch_QueryServerString; 443 dispatchFuncs[X_GLXChangeDrawableAttributes] = dispatch_ChangeDrawableAttributes; 444 dispatchFuncs[X_GLXCreateNewContext] = dispatch_CreateNewContext; 445 dispatchFuncs[X_GLXCreatePbuffer] = dispatch_CreatePbuffer; 446 dispatchFuncs[X_GLXCreatePixmap] = dispatch_CreatePixmap; 447 dispatchFuncs[X_GLXCreateWindow] = dispatch_CreateWindow; 448 dispatchFuncs[X_GLXCreateContextAttribsARB] = dispatch_CreateContextAttribsARB; 449 dispatchFuncs[X_GLXDestroyPbuffer] = dispatch_DestroyPbuffer; 450 dispatchFuncs[X_GLXDestroyPixmap] = dispatch_DestroyPixmap; 451 dispatchFuncs[X_GLXDestroyWindow] = dispatch_DestroyWindow; 452 dispatchFuncs[X_GLXGetDrawableAttributes] = dispatch_GetDrawableAttributes; 453 dispatchFuncs[X_GLXGetFBConfigs] = dispatch_GetFBConfigs; 454 dispatchFuncs[X_GLXQueryContext] = dispatch_QueryContext; 455 dispatchFuncs[X_GLXIsDirect] = dispatch_IsDirect; 456 457 return TRUE; 458} 459 460void GlxDispatchReset(void) 461{ 462 memset(dispatchFuncs, 0, sizeof(dispatchFuncs)); 463 464 ht_destroy(vendorPrivHash); 465 vendorPrivHash = NULL; 466} 467 468int GlxDispatchRequest(ClientPtr client) 469{ 470 REQUEST(xReq); 471 int result; 472 473 if (GlxExtensionEntry->base == 0) 474 return BadRequest; 475 476 GlxSetRequestClient(client); 477 478 if (stuff->data < OPCODE_ARRAY_LEN) { 479 if (dispatchFuncs[stuff->data] == NULL) { 480 // Try to find a dispatch stub. 481 dispatchFuncs[stuff->data] = GetVendorDispatchFunc(stuff->data, 0); 482 } 483 result = dispatchFuncs[stuff->data](client); 484 } else { 485 result = dispatch_GLXSingle(client); 486 } 487 488 GlxSetRequestClient(NULL); 489 490 return result; 491} 492