glxext.c revision b1d344b3
1/* 2 * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) 3 * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a 6 * copy of this software and associated documentation files (the "Software"), 7 * to deal in the Software without restriction, including without limitation 8 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 * and/or sell copies of the Software, and to permit persons to whom the 10 * Software is furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice including the dates of first publication and 13 * either this permission notice or a reference to 14 * http://oss.sgi.com/projects/FreeB/ 15 * shall be included in all copies or substantial portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 21 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF 22 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 * SOFTWARE. 24 * 25 * Except as contained in this notice, the name of Silicon Graphics, Inc. 26 * shall not be used in advertising or otherwise to promote the sale, use or 27 * other dealings in this Software without prior written authorization from 28 * Silicon Graphics, Inc. 29 */ 30 31#define NEED_REPLIES 32#ifdef HAVE_DIX_CONFIG_H 33#include <dix-config.h> 34#endif 35 36#include <string.h> 37#include "glxserver.h" 38#include <windowstr.h> 39#include <propertyst.h> 40#include "privates.h" 41#include <os.h> 42#include "g_disptab.h" 43#include "unpack.h" 44#include "glxutil.h" 45#include "glxext.h" 46#include "indirect_table.h" 47#include "indirect_util.h" 48 49/* 50** The last context used by the server. It is the context that is current 51** from the server's perspective. 52*/ 53__GLXcontext *__glXLastContext; 54__GLXcontext *__glXContextList; 55 56/* 57** X resources. 58*/ 59RESTYPE __glXContextRes; 60RESTYPE __glXDrawableRes; 61RESTYPE __glXSwapBarrierRes; 62 63/* 64** Reply for most singles. 65*/ 66xGLXSingleReply __glXReply; 67 68static int glxClientPrivateKeyIndex; 69static DevPrivateKey glxClientPrivateKey = &glxClientPrivateKeyIndex; 70 71/* 72** Client that called into GLX dispatch. 73*/ 74ClientPtr __pGlxClient; 75 76/* 77** Forward declarations. 78*/ 79static int __glXDispatch(ClientPtr); 80 81/* 82** Called when the extension is reset. 83*/ 84static void ResetExtension(ExtensionEntry* extEntry) 85{ 86 __glXFlushContextCache(); 87} 88 89/* 90** Reset state used to keep track of large (multi-request) commands. 91*/ 92void __glXResetLargeCommandStatus(__GLXclientState *cl) 93{ 94 cl->largeCmdBytesSoFar = 0; 95 cl->largeCmdBytesTotal = 0; 96 cl->largeCmdRequestsSoFar = 0; 97 cl->largeCmdRequestsTotal = 0; 98} 99 100/* 101** This procedure is called when the client who created the context goes 102** away OR when glXDestroyContext is called. In either case, all we do is 103** flag that the ID is no longer valid, and (maybe) free the context. 104** use. 105*/ 106static int ContextGone(__GLXcontext* cx, XID id) 107{ 108 cx->idExists = GL_FALSE; 109 if (!cx->isCurrent) { 110 __glXFreeContext(cx); 111 } 112 113 return True; 114} 115 116static __GLXcontext *glxPendingDestroyContexts; 117static __GLXcontext *glxAllContexts; 118static int glxServerLeaveCount; 119static int glxBlockClients; 120 121/* 122** Destroy routine that gets called when a drawable is freed. A drawable 123** contains the ancillary buffers needed for rendering. 124*/ 125static Bool DrawableGone(__GLXdrawable *glxPriv, XID xid) 126{ 127 __GLXcontext *c; 128 129 for (c = glxAllContexts; c; c = c->next) { 130 if (c->isCurrent && (c->drawPriv == glxPriv || c->readPriv == glxPriv)) { 131 int i; 132 133 (*c->loseCurrent)(c); 134 c->isCurrent = GL_FALSE; 135 if (c == __glXLastContext) 136 __glXFlushContextCache(); 137 138 for (i = 1; i < currentMaxClients; i++) { 139 if (clients[i]) { 140 __GLXclientState *cl = glxGetClient(clients[i]); 141 142 if (cl->inUse) { 143 int j; 144 145 for (j = 0; j < cl->numCurrentContexts; j++) { 146 if (cl->currentContexts[j] == c) 147 cl->currentContexts[j] = NULL; 148 } 149 } 150 } 151 } 152 153 if (!c->idExists) { 154 __glXFreeContext(c); 155 } 156 } 157 if (c->drawPriv == glxPriv) 158 c->drawPriv = NULL; 159 if (c->readPriv == glxPriv) 160 c->readPriv = NULL; 161 } 162 163 glxPriv->destroy(glxPriv); 164 165 return True; 166} 167 168void __glXAddToContextList(__GLXcontext *cx) 169{ 170 cx->next = glxAllContexts; 171 glxAllContexts = cx; 172} 173 174void __glXRemoveFromContextList(__GLXcontext *cx) 175{ 176 __GLXcontext *c, **prev; 177 178 prev = &glxAllContexts; 179 for (c = glxAllContexts; c; c = c->next) 180 if (c == cx) 181 *prev = c->next; 182} 183 184/* 185** Free a context. 186*/ 187GLboolean __glXFreeContext(__GLXcontext *cx) 188{ 189 if (cx->idExists || cx->isCurrent) return GL_FALSE; 190 191 if (cx->feedbackBuf) xfree(cx->feedbackBuf); 192 if (cx->selectBuf) xfree(cx->selectBuf); 193 if (cx == __glXLastContext) { 194 __glXFlushContextCache(); 195 } 196 197 __glXRemoveFromContextList(cx); 198 199 /* We can get here through both regular dispatching from 200 * __glXDispatch() or as a callback from the resource manager. In 201 * the latter case we need to lift the DRI lock manually. */ 202 203 if (!glxBlockClients) { 204 __glXleaveServer(GL_FALSE); 205 cx->destroy(cx); 206 __glXenterServer(GL_FALSE); 207 } else { 208 cx->next = glxPendingDestroyContexts; 209 glxPendingDestroyContexts = cx; 210 } 211 212 return GL_TRUE; 213} 214 215extern RESTYPE __glXSwapBarrierRes; 216 217static int SwapBarrierGone(int screen, XID drawable) 218{ 219 __GLXscreen *pGlxScreen = glxGetScreen(screenInfo.screens[screen]); 220 221 if (pGlxScreen->swapBarrierFuncs) { 222 pGlxScreen->swapBarrierFuncs->bindSwapBarrierFunc(screen, drawable, 0); 223 } 224 FreeResourceByType(drawable, __glXSwapBarrierRes, FALSE); 225 return True; 226} 227 228/************************************************************************/ 229 230/* 231** These routines can be used to check whether a particular GL command 232** has caused an error. Specifically, we use them to check whether a 233** given query has caused an error, in which case a zero-length data 234** reply is sent to the client. 235*/ 236 237static GLboolean errorOccured = GL_FALSE; 238 239/* 240** The GL was will call this routine if an error occurs. 241*/ 242void __glXErrorCallBack(GLenum code) 243{ 244 errorOccured = GL_TRUE; 245} 246 247/* 248** Clear the error flag before calling the GL command. 249*/ 250void __glXClearErrorOccured(void) 251{ 252 errorOccured = GL_FALSE; 253} 254 255/* 256** Check if the GL command caused an error. 257*/ 258GLboolean __glXErrorOccured(void) 259{ 260 return errorOccured; 261} 262 263static int __glXErrorBase; 264 265int __glXError(int error) 266{ 267 return __glXErrorBase + error; 268} 269 270__GLXclientState * 271glxGetClient(ClientPtr pClient) 272{ 273 return dixLookupPrivate(&pClient->devPrivates, glxClientPrivateKey); 274} 275 276static void 277glxClientCallback (CallbackListPtr *list, 278 pointer closure, 279 pointer data) 280{ 281 NewClientInfoRec *clientinfo = (NewClientInfoRec *) data; 282 ClientPtr pClient = clientinfo->client; 283 __GLXclientState *cl = glxGetClient(pClient); 284 __GLXcontext *cx; 285 int i; 286 287 switch (pClient->clientState) { 288 case ClientStateRunning: 289 /* 290 ** By default, assume that the client supports 291 ** GLX major version 1 minor version 0 protocol. 292 */ 293 cl->GLClientmajorVersion = 1; 294 cl->GLClientminorVersion = 0; 295 cl->client = pClient; 296 break; 297 298 case ClientStateGone: 299 for (i = 0; i < cl->numCurrentContexts; i++) { 300 cx = cl->currentContexts[i]; 301 if (cx) { 302 cx->isCurrent = GL_FALSE; 303 if (!cx->idExists) 304 __glXFreeContext(cx); 305 } 306 } 307 308 if (cl->returnBuf) xfree(cl->returnBuf); 309 if (cl->largeCmdBuf) xfree(cl->largeCmdBuf); 310 if (cl->currentContexts) xfree(cl->currentContexts); 311 if (cl->GLClientextensions) xfree(cl->GLClientextensions); 312 break; 313 314 default: 315 break; 316 } 317} 318 319/************************************************************************/ 320 321static __GLXprovider *__glXProviderStack; 322 323void GlxPushProvider(__GLXprovider *provider) 324{ 325 provider->next = __glXProviderStack; 326 __glXProviderStack = provider; 327} 328 329/* 330** Initialize the GLX extension. 331*/ 332void GlxExtensionInit(void) 333{ 334 ExtensionEntry *extEntry; 335 ScreenPtr pScreen; 336 int i; 337 __GLXprovider *p; 338 Bool glx_provided = False; 339 340 __glXContextRes = CreateNewResourceType((DeleteType)ContextGone); 341 __glXDrawableRes = CreateNewResourceType((DeleteType)DrawableGone); 342 __glXSwapBarrierRes = CreateNewResourceType((DeleteType)SwapBarrierGone); 343 344 if (!dixRequestPrivate(glxClientPrivateKey, sizeof (__GLXclientState))) 345 return; 346 if (!AddCallback (&ClientStateCallback, glxClientCallback, 0)) 347 return; 348 349 for (i = 0; i < screenInfo.numScreens; i++) { 350 pScreen = screenInfo.screens[i]; 351 352 for (p = __glXProviderStack; p != NULL; p = p->next) { 353 if (p->screenProbe(pScreen) != NULL) { 354 LogMessage(X_INFO, 355 "GLX: Initialized %s GL provider for screen %d\n", 356 p->name, i); 357 break; 358 } 359 } 360 361 if (!p) 362 LogMessage(X_INFO, 363 "GLX: no usable GL providers found for screen %d\n", i); 364 else 365 glx_provided = True; 366 } 367 368 /* don't register extension if GL is not provided on any screen */ 369 if (!glx_provided) 370 return; 371 372 /* 373 ** Add extension to server extensions. 374 */ 375 extEntry = AddExtension(GLX_EXTENSION_NAME, __GLX_NUMBER_EVENTS, 376 __GLX_NUMBER_ERRORS, __glXDispatch, 377 __glXDispatch, ResetExtension, 378 StandardMinorOpcode); 379 if (!extEntry) { 380 FatalError("__glXExtensionInit: AddExtensions failed\n"); 381 return; 382 } 383 if (!AddExtensionAlias(GLX_EXTENSION_ALIAS, extEntry)) { 384 ErrorF("__glXExtensionInit: AddExtensionAlias failed\n"); 385 return; 386 } 387 388 __glXErrorBase = extEntry->errorBase; 389} 390 391/************************************************************************/ 392 393void __glXFlushContextCache(void) 394{ 395 __glXLastContext = 0; 396} 397 398/* 399** Make a context the current one for the GL (in this implementation, there 400** is only one instance of the GL, and we use it to serve all GL clients by 401** switching it between different contexts). While we are at it, look up 402** a context by its tag and return its (__GLXcontext *). 403*/ 404__GLXcontext *__glXForceCurrent(__GLXclientState *cl, GLXContextTag tag, 405 int *error) 406{ 407 __GLXcontext *cx; 408 409 /* 410 ** See if the context tag is legal; it is managed by the extension, 411 ** so if it's invalid, we have an implementation error. 412 */ 413 cx = (__GLXcontext *) __glXLookupContextByTag(cl, tag); 414 if (!cx) { 415 cl->client->errorValue = tag; 416 *error = __glXError(GLXBadContextTag); 417 return 0; 418 } 419 420 if (!cx->isDirect) { 421 if (cx->drawPriv == NULL) { 422 /* 423 ** The drawable has vanished. It must be a window, because only 424 ** windows can be destroyed from under us; GLX pixmaps are 425 ** refcounted and don't go away until no one is using them. 426 */ 427 *error = __glXError(GLXBadCurrentWindow); 428 return 0; 429 } 430 } 431 432 if (cx == __glXLastContext) { 433 /* No need to re-bind */ 434 return cx; 435 } 436 437 /* Make this context the current one for the GL. */ 438 if (!cx->isDirect) { 439 if (!(*cx->forceCurrent)(cx)) { 440 /* Bind failed, and set the error code. Bummer */ 441 cl->client->errorValue = cx->id; 442 *error = __glXError(GLXBadContextState); 443 return 0; 444 } 445 } 446 __glXLastContext = cx; 447 return cx; 448} 449 450/************************************************************************/ 451 452void glxSuspendClients(void) 453{ 454 int i; 455 456 for (i = 1; i < currentMaxClients; i++) { 457 if (clients[i] && glxGetClient(clients[i])->inUse) 458 IgnoreClient(clients[i]); 459 } 460 461 glxBlockClients = TRUE; 462} 463 464void glxResumeClients(void) 465{ 466 __GLXcontext *cx, *next; 467 int i; 468 469 glxBlockClients = FALSE; 470 471 for (i = 1; i < currentMaxClients; i++) { 472 if (clients[i] && glxGetClient(clients[i])->inUse) 473 AttendClient(clients[i]); 474 } 475 476 __glXleaveServer(GL_FALSE); 477 for (cx = glxPendingDestroyContexts; cx != NULL; cx = next) { 478 next = cx->next; 479 480 cx->destroy(cx); 481 } 482 glxPendingDestroyContexts = NULL; 483 __glXenterServer(GL_FALSE); 484} 485 486static void 487__glXnopEnterServer(GLboolean rendering) 488{ 489} 490 491static void 492__glXnopLeaveServer(GLboolean rendering) 493{ 494} 495 496static void (*__glXenterServerFunc)(GLboolean) = __glXnopEnterServer; 497static void (*__glXleaveServerFunc)(GLboolean) = __glXnopLeaveServer; 498 499void __glXsetEnterLeaveServerFuncs(void (*enter)(GLboolean), 500 void (*leave)(GLboolean)) 501{ 502 __glXenterServerFunc = enter; 503 __glXleaveServerFunc = leave; 504} 505 506 507void __glXenterServer(GLboolean rendering) 508{ 509 glxServerLeaveCount--; 510 511 if (glxServerLeaveCount == 0) 512 (*__glXenterServerFunc)(rendering); 513} 514 515void __glXleaveServer(GLboolean rendering) 516{ 517 if (glxServerLeaveCount == 0) 518 (*__glXleaveServerFunc)(rendering); 519 520 glxServerLeaveCount++; 521} 522 523/* 524** Top level dispatcher; all commands are executed from here down. 525*/ 526static int __glXDispatch(ClientPtr client) 527{ 528 REQUEST(xGLXSingleReq); 529 CARD8 opcode; 530 __GLXdispatchSingleProcPtr proc; 531 __GLXclientState *cl; 532 int retval; 533 534 opcode = stuff->glxCode; 535 cl = glxGetClient(client); 536 /* Mark it in use so we suspend it on VT switch. */ 537 cl->inUse = TRUE; 538 539 /* 540 ** If we're expecting a glXRenderLarge request, this better be one. 541 */ 542 if ((cl->largeCmdRequestsSoFar != 0) && (opcode != X_GLXRenderLarge)) { 543 client->errorValue = stuff->glxCode; 544 return __glXError(GLXBadLargeRequest); 545 } 546 547 /* If we're currently blocking GLX clients, just put this guy to 548 * sleep, reset the request and return. */ 549 if (glxBlockClients) { 550 ResetCurrentRequest(client); 551 client->sequence--; 552 IgnoreClient(client); 553 return(client->noClientException); 554 } 555 556 /* 557 ** Use the opcode to index into the procedure table. 558 */ 559 proc = (__GLXdispatchSingleProcPtr) __glXGetProtocolDecodeFunction(& Single_dispatch_info, 560 opcode, 561 client->swapped); 562 if (proc != NULL) { 563 GLboolean rendering = opcode <= X_GLXRenderLarge; 564 __glXleaveServer(rendering); 565 566 __pGlxClient = client; 567 568 retval = (*proc)(cl, (GLbyte *) stuff); 569 570 __glXenterServer(rendering); 571 } 572 else { 573 retval = BadRequest; 574 } 575 576 return retval; 577} 578