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