glxcurrent.c revision 115203281cf791221f586f03c14cfe4e0a44dd7a
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/** 32 * \file glxcurrent.c 33 * Client-side GLX interface for current context management. 34 */ 35 36#include "glxclient.h" 37#include "glapi.h" 38#include "indirect_init.h" 39 40/* 41** We setup some dummy structures here so that the API can be used 42** even if no context is current. 43*/ 44 45static GLubyte dummyBuffer[__GLX_BUFFER_LIMIT_SIZE]; 46 47/* 48** Dummy context used by small commands when there is no current context. 49** All the 50** gl and glx entry points are designed to operate as nop's when using 51** the dummy context structure. 52*/ 53static __GLXcontext dummyContext = { 54 &dummyBuffer[0], 55 &dummyBuffer[0], 56 &dummyBuffer[0], 57 &dummyBuffer[__GLX_BUFFER_LIMIT_SIZE], 58 sizeof(dummyBuffer), 59}; 60 61 62/* 63** All indirect rendering contexts will share the same indirect dispatch table. 64*/ 65static __GLapi *IndirectAPI = NULL; 66 67 68/* 69 * Current context management and locking 70 */ 71 72#if defined( PTHREADS ) 73 74_X_HIDDEN pthread_mutex_t __glXmutex = PTHREAD_MUTEX_INITIALIZER; 75 76# if defined( GLX_USE_TLS ) 77 78/** 79 * Per-thread GLX context pointer. 80 * 81 * \c __glXSetCurrentContext is written is such a way that this pointer can 82 * \b never be \c NULL. This is important! Because of this 83 * \c __glXGetCurrentContext can be implemented as trivial macro. 84 */ 85__thread void *__glX_tls_Context __attribute__ ((tls_model("initial-exec"))) 86 = &dummyContext; 87 88_X_HIDDEN void 89__glXSetCurrentContext(__GLXcontext * c) 90{ 91 __glX_tls_Context = (c != NULL) ? c : &dummyContext; 92} 93 94# else 95 96static pthread_once_t once_control = PTHREAD_ONCE_INIT; 97 98/** 99 * Per-thread data key. 100 * 101 * Once \c init_thread_data has been called, the per-thread data key will 102 * take a value of \c NULL. As each new thread is created the default 103 * value, in that thread, will be \c NULL. 104 */ 105static pthread_key_t ContextTSD; 106 107/** 108 * Initialize the per-thread data key. 109 * 110 * This function is called \b exactly once per-process (not per-thread!) to 111 * initialize the per-thread data key. This is ideally done using the 112 * \c pthread_once mechanism. 113 */ 114static void 115init_thread_data(void) 116{ 117 if (pthread_key_create(&ContextTSD, NULL) != 0) { 118 perror("pthread_key_create"); 119 exit(-1); 120 } 121} 122 123_X_HIDDEN void 124__glXSetCurrentContext(__GLXcontext * c) 125{ 126 pthread_once(&once_control, init_thread_data); 127 pthread_setspecific(ContextTSD, c); 128} 129 130_X_HIDDEN __GLXcontext * 131__glXGetCurrentContext(void) 132{ 133 void *v; 134 135 pthread_once(&once_control, init_thread_data); 136 137 v = pthread_getspecific(ContextTSD); 138 return (v == NULL) ? &dummyContext : (__GLXcontext *) v; 139} 140 141# endif /* defined( GLX_USE_TLS ) */ 142 143#elif defined( THREADS ) 144 145#error Unknown threading method specified. 146 147#else 148 149/* not thread safe */ 150_X_HIDDEN __GLXcontext *__glXcurrentContext = &dummyContext; 151 152#endif 153 154 155_X_HIDDEN void 156__glXSetCurrentContextNull(void) 157{ 158 __glXSetCurrentContext(&dummyContext); 159#ifdef GLX_DIRECT_RENDERING 160 _glapi_set_dispatch(NULL); /* no-op functions */ 161 _glapi_set_context(NULL); 162#endif 163} 164 165 166/************************************************************************/ 167 168PUBLIC GLXContext 169glXGetCurrentContext(void) 170{ 171 GLXContext cx = __glXGetCurrentContext(); 172 173 if (cx == &dummyContext) { 174 return NULL; 175 } 176 else { 177 return cx; 178 } 179} 180 181PUBLIC GLXDrawable 182glXGetCurrentDrawable(void) 183{ 184 GLXContext gc = __glXGetCurrentContext(); 185 return gc->currentDrawable; 186} 187 188 189/************************************************************************/ 190 191/** 192 * Sends a GLX protocol message to the specified display to make the context 193 * and the drawables current. 194 * 195 * \param dpy Display to send the message to. 196 * \param opcode Major opcode value for the display. 197 * \param gc_id Context tag for the context to be made current. 198 * \param draw Drawable ID for the "draw" drawable. 199 * \param read Drawable ID for the "read" drawable. 200 * \param reply Space to store the X-server's reply. 201 * 202 * \warning 203 * This function assumes that \c dpy is locked with \c LockDisplay on entry. 204 */ 205static Bool 206SendMakeCurrentRequest(Display * dpy, CARD8 opcode, 207 GLXContextID gc_id, GLXContextTag gc_tag, 208 GLXDrawable draw, GLXDrawable read, 209 xGLXMakeCurrentReply * reply) 210{ 211 Bool ret; 212 213 214 LockDisplay(dpy); 215 216 if (draw == read) { 217 xGLXMakeCurrentReq *req; 218 219 GetReq(GLXMakeCurrent, req); 220 req->reqType = opcode; 221 req->glxCode = X_GLXMakeCurrent; 222 req->drawable = draw; 223 req->context = gc_id; 224 req->oldContextTag = gc_tag; 225 } 226 else { 227 __GLXdisplayPrivate *priv = __glXInitialize(dpy); 228 229 /* If the server can support the GLX 1.3 version, we should 230 * perfer that. Not only that, some servers support GLX 1.3 but 231 * not the SGI extension. 232 */ 233 234 if ((priv->majorVersion > 1) || (priv->minorVersion >= 3)) { 235 xGLXMakeContextCurrentReq *req; 236 237 GetReq(GLXMakeContextCurrent, req); 238 req->reqType = opcode; 239 req->glxCode = X_GLXMakeContextCurrent; 240 req->drawable = draw; 241 req->readdrawable = read; 242 req->context = gc_id; 243 req->oldContextTag = gc_tag; 244 } 245 else { 246 xGLXVendorPrivateWithReplyReq *vpreq; 247 xGLXMakeCurrentReadSGIReq *req; 248 249 GetReqExtra(GLXVendorPrivateWithReply, 250 sz_xGLXMakeCurrentReadSGIReq - 251 sz_xGLXVendorPrivateWithReplyReq, vpreq); 252 req = (xGLXMakeCurrentReadSGIReq *) vpreq; 253 req->reqType = opcode; 254 req->glxCode = X_GLXVendorPrivateWithReply; 255 req->vendorCode = X_GLXvop_MakeCurrentReadSGI; 256 req->drawable = draw; 257 req->readable = read; 258 req->context = gc_id; 259 req->oldContextTag = gc_tag; 260 } 261 } 262 263 ret = _XReply(dpy, (xReply *) reply, 0, False); 264 265 UnlockDisplay(dpy); 266 SyncHandle(); 267 268 return ret; 269} 270 271 272#ifdef GLX_DIRECT_RENDERING 273static __GLXDRIdrawable * 274FetchDRIDrawable(Display * dpy, GLXDrawable glxDrawable, GLXContext gc) 275{ 276 __GLXdisplayPrivate *const priv = __glXInitialize(dpy); 277 __GLXDRIdrawable *pdraw; 278 __GLXscreenConfigs *psc; 279 280 if (priv == NULL) 281 return NULL; 282 283 psc = &priv->screenConfigs[gc->screen]; 284 if (psc->drawHash == NULL) 285 return NULL; 286 287 if (__glxHashLookup(psc->drawHash, glxDrawable, (void *) &pdraw) == 0) 288 return pdraw; 289 290 pdraw = psc->driScreen->createDrawable(psc, glxDrawable, 291 glxDrawable, gc->mode); 292 if (__glxHashInsert(psc->drawHash, glxDrawable, pdraw)) { 293 (*pdraw->destroyDrawable) (pdraw); 294 return NULL; 295 } 296 297 return pdraw; 298} 299#endif /* GLX_DIRECT_RENDERING */ 300 301static void 302__glXGenerateError(Display * dpy, GLXContext gc, XID resource, 303 BYTE errorCode, CARD16 minorCode) 304{ 305 xError error; 306 307 error.errorCode = errorCode; 308 error.resourceID = resource; 309 error.sequenceNumber = dpy->request; 310 error.type = X_Error; 311 error.majorCode = gc->majorOpcode; 312 error.minorCode = minorCode; 313 _XError(dpy, &error); 314} 315 316/** 317 * Make a particular context current. 318 * 319 * \note This is in this file so that it can access dummyContext. 320 */ 321static Bool 322MakeContextCurrent(Display * dpy, GLXDrawable draw, 323 GLXDrawable read, GLXContext gc) 324{ 325 xGLXMakeCurrentReply reply; 326 const GLXContext oldGC = __glXGetCurrentContext(); 327 const CARD8 opcode = __glXSetupForCommand(dpy); 328 const CARD8 oldOpcode = ((gc == oldGC) || (oldGC == &dummyContext)) 329 ? opcode : __glXSetupForCommand(oldGC->currentDpy); 330 Bool bindReturnValue; 331 __GLXattribute *state; 332 333 if (!opcode || !oldOpcode) { 334 return GL_FALSE; 335 } 336 337 /* Make sure that the new context has a nonzero ID. In the request, 338 * a zero context ID is used only to mean that we bind to no current 339 * context. 340 */ 341 if ((gc != NULL) && (gc->xid == None)) { 342 return GL_FALSE; 343 } 344 345 if (gc == NULL && (draw != None || read != None)) { 346 __glXGenerateError(dpy, gc, (draw != None) ? draw : read, 347 BadMatch, X_GLXMakeContextCurrent); 348 return False; 349 } 350 if (gc != NULL && (draw == None || read == None)) { 351 __glXGenerateError(dpy, gc, None, BadMatch, X_GLXMakeContextCurrent); 352 return False; 353 } 354 355 _glapi_check_multithread(); 356 357 if (gc != NULL && gc->thread_id != 0 && gc->thread_id != _glthread_GetID()) { 358 __glXGenerateError(dpy, gc, gc->xid, 359 BadAccess, X_GLXMakeContextCurrent); 360 return False; 361 } 362 363#ifdef GLX_DIRECT_RENDERING 364 /* Bind the direct rendering context to the drawable */ 365 if (gc && gc->driContext) { 366 __GLXDRIdrawable *pdraw = FetchDRIDrawable(dpy, draw, gc); 367 __GLXDRIdrawable *pread = FetchDRIDrawable(dpy, read, gc); 368 369 if ((pdraw == NULL) || (pread == NULL)) { 370 __glXGenerateError(dpy, gc, (pdraw == NULL) ? draw : read, 371 GLXBadDrawable, X_GLXMakeContextCurrent); 372 return False; 373 } 374 375 bindReturnValue = 376 (gc->driContext->bindContext) (gc->driContext, pdraw, pread); 377 } 378 else if (!gc && oldGC && oldGC->driContext) { 379 bindReturnValue = True; 380 } 381 else 382#endif 383 { 384 /* Send a glXMakeCurrent request to bind the new context. */ 385 bindReturnValue = 386 SendMakeCurrentRequest(dpy, opcode, gc ? gc->xid : None, 387 ((dpy != oldGC->currentDpy) 388 || oldGC->isDirect) 389 ? None : oldGC->currentContextTag, draw, read, 390 &reply); 391 } 392 393 394 if (!bindReturnValue) { 395 return False; 396 } 397 398#ifdef GLX_DIRECT_RENDERING 399 if ((dpy != oldGC->currentDpy || (gc && gc->driContext)) && 400 !oldGC->isDirect && oldGC != &dummyContext) { 401#else 402 if ((dpy != oldGC->currentDpy) && oldGC != &dummyContext) { 403#endif 404 xGLXMakeCurrentReply dummy_reply; 405 406 /* We are either switching from one dpy to another and have to 407 * send a request to the previous dpy to unbind the previous 408 * context, or we are switching away from a indirect context to 409 * a direct context and have to send a request to the dpy to 410 * unbind the previous context. 411 */ 412 (void) SendMakeCurrentRequest(oldGC->currentDpy, oldOpcode, None, 413 oldGC->currentContextTag, None, None, 414 &dummy_reply); 415 } 416#ifdef GLX_DIRECT_RENDERING 417 else if (oldGC->driContext && oldGC != gc) { 418 oldGC->driContext->unbindContext(oldGC->driContext); 419 } 420#endif 421 422 423 /* Update our notion of what is current */ 424 __glXLock(); 425 if (gc == oldGC) { 426 /* Even though the contexts are the same the drawable might have 427 * changed. Note that gc cannot be the dummy, and that oldGC 428 * cannot be NULL, therefore if they are the same, gc is not 429 * NULL and not the dummy. 430 */ 431 gc->currentDrawable = draw; 432 gc->currentReadable = read; 433 } 434 else { 435 if (oldGC != &dummyContext) { 436 /* Old current context is no longer current to anybody */ 437 oldGC->currentDpy = 0; 438 oldGC->currentDrawable = None; 439 oldGC->currentReadable = None; 440 oldGC->currentContextTag = 0; 441 oldGC->thread_id = 0; 442 443 if (oldGC->xid == None) { 444 /* We are switching away from a context that was 445 * previously destroyed, so we need to free the memory 446 * for the old handle. 447 */ 448#ifdef GLX_DIRECT_RENDERING 449 /* Destroy the old direct rendering context */ 450 if (oldGC->driContext) { 451 oldGC->driContext->destroyContext(oldGC->driContext, 452 oldGC->psc, 453 oldGC->createDpy); 454 oldGC->driContext = NULL; 455 } 456#endif 457 __glXFreeContext(oldGC); 458 } 459 } 460 if (gc) { 461 __glXSetCurrentContext(gc); 462 463 gc->currentDpy = dpy; 464 gc->currentDrawable = draw; 465 gc->currentReadable = read; 466 gc->thread_id = _glthread_GetID(); 467 468#ifdef GLX_DIRECT_RENDERING 469 if (!gc->driContext) { 470#endif 471 if (!IndirectAPI) 472 IndirectAPI = __glXNewIndirectAPI(); 473 _glapi_set_dispatch(IndirectAPI); 474 475 state = (__GLXattribute *) (gc->client_state_private); 476 477 gc->currentContextTag = reply.contextTag; 478 if (state->array_state == NULL) { 479 (void) glGetString(GL_EXTENSIONS); 480 (void) glGetString(GL_VERSION); 481 __glXInitVertexArrayState(gc); 482 } 483#ifdef GLX_DIRECT_RENDERING 484 } 485 else { 486 gc->currentContextTag = -1; 487 } 488#endif 489 } 490 else { 491 __glXSetCurrentContextNull(); 492 } 493 } 494 __glXUnlock(); 495 return GL_TRUE; 496} 497 498 499PUBLIC Bool 500glXMakeCurrent(Display * dpy, GLXDrawable draw, GLXContext gc) 501{ 502 return MakeContextCurrent(dpy, draw, draw, gc); 503} 504 505PUBLIC 506GLX_ALIAS(Bool, glXMakeCurrentReadSGI, 507 (Display * dpy, GLXDrawable d, GLXDrawable r, GLXContext ctx), 508 (dpy, d, r, ctx), MakeContextCurrent) 509 510PUBLIC 511GLX_ALIAS(Bool, glXMakeContextCurrent, 512 (Display * dpy, GLXDrawable d, GLXDrawable r, 513 GLXContext ctx), (dpy, d, r, ctx), MakeContextCurrent) 514