2 * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
3 * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
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:
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.
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
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.
33 * Client-side GLX interface for current context management.
40 #include "glxclient.h"
41 #ifdef GLX_USE_APPLEGL
44 #include "apple_glx.h"
45 #include "apple_glx_context.h"
48 #include "indirect_init.h"
52 ** We setup some dummy structures here so that the API can be used
53 ** even if no context is current.
56 static GLubyte dummyBuffer
[__GLX_BUFFER_LIMIT_SIZE
];
59 ** Dummy context used by small commands when there is no current context.
61 ** gl and glx entry points are designed to operate as nop's when using
62 ** the dummy context structure.
64 static __GLXcontext dummyContext
= {
68 &dummyBuffer
[__GLX_BUFFER_LIMIT_SIZE
],
73 #ifndef GLX_USE_APPLEGL
75 ** All indirect rendering contexts will share the same indirect dispatch table.
77 static __GLapi
*IndirectAPI
= NULL
;
81 * Current context management and locking
84 #if defined( PTHREADS )
86 _X_HIDDEN pthread_mutex_t __glXmutex
= PTHREAD_MUTEX_INITIALIZER
;
88 # if defined( GLX_USE_TLS )
91 * Per-thread GLX context pointer.
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.
97 __thread
void *__glX_tls_Context
__attribute__ ((tls_model("initial-exec")))
101 __glXSetCurrentContext(__GLXcontext
* c
)
103 __glX_tls_Context
= (c
!= NULL
) ? c
: &dummyContext
;
108 static pthread_once_t once_control
= PTHREAD_ONCE_INIT
;
111 * Per-thread data key.
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.
117 static pthread_key_t ContextTSD
;
120 * Initialize the per-thread data key.
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.
127 init_thread_data(void)
129 if (pthread_key_create(&ContextTSD
, NULL
) != 0) {
130 perror("pthread_key_create");
136 __glXSetCurrentContext(__GLXcontext
* c
)
138 pthread_once(&once_control
, init_thread_data
);
139 pthread_setspecific(ContextTSD
, c
);
142 _X_HIDDEN __GLXcontext
*
143 __glXGetCurrentContext(void)
147 pthread_once(&once_control
, init_thread_data
);
149 v
= pthread_getspecific(ContextTSD
);
150 return (v
== NULL
) ? &dummyContext
: (__GLXcontext
*) v
;
153 # endif /* defined( GLX_USE_TLS ) */
155 #elif defined( THREADS )
157 #error Unknown threading method specified.
161 /* not thread safe */
162 _X_HIDDEN __GLXcontext
*__glXcurrentContext
= &dummyContext
;
168 __glXSetCurrentContextNull(void)
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
);
180 /************************************************************************/
183 glXGetCurrentContext(void)
185 GLXContext cx
= __glXGetCurrentContext();
187 if (cx
== &dummyContext
) {
196 glXGetCurrentDrawable(void)
198 GLXContext gc
= __glXGetCurrentContext();
199 return gc
->currentDrawable
;
203 #ifndef GLX_USE_APPLEGL
204 /************************************************************************/
207 * Sends a GLX protocol message to the specified display to make the context
208 * and the drawables current.
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.
218 * This function assumes that \c dpy is locked with \c LockDisplay on entry.
221 SendMakeCurrentRequest(Display
* dpy
, CARD8 opcode
,
222 GLXContextID gc_id
, GLXContextTag gc_tag
,
223 GLXDrawable draw
, GLXDrawable read
,
224 xGLXMakeCurrentReply
* reply
)
232 xGLXMakeCurrentReq
*req
;
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
;
242 __GLXdisplayPrivate
*priv
= __glXInitialize(dpy
);
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.
249 if ((priv
->majorVersion
> 1) || (priv
->minorVersion
>= 3)) {
250 xGLXMakeContextCurrentReq
*req
;
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
;
261 xGLXVendorPrivateWithReplyReq
*vpreq
;
262 xGLXMakeCurrentReadSGIReq
*req
;
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
;
278 ret
= _XReply(dpy
, (xReply
*) reply
, 0, False
);
287 #if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL)
288 static __GLXDRIdrawable
*
289 FetchDRIDrawable(Display
* dpy
, GLXDrawable glxDrawable
, GLXContext gc
)
291 __GLXdisplayPrivate
*const priv
= __glXInitialize(dpy
);
292 __GLXDRIdrawable
*pdraw
;
293 __GLXscreenConfigs
*psc
;
298 psc
= &priv
->screenConfigs
[gc
->screen
];
299 if (psc
->drawHash
== NULL
)
302 if (__glxHashLookup(psc
->drawHash
, glxDrawable
, (void *) &pdraw
) == 0)
305 pdraw
= psc
->driScreen
->createDrawable(psc
, glxDrawable
,
306 glxDrawable
, gc
->mode
);
307 if (__glxHashInsert(psc
->drawHash
, glxDrawable
, pdraw
)) {
308 (*pdraw
->destroyDrawable
) (pdraw
);
314 #endif /* GLX_DIRECT_RENDERING */
317 __glXGenerateError(Display
* dpy
, GLXContext gc
, XID resource
,
318 BYTE errorCode
, CARD16 minorCode
)
322 error
.errorCode
= errorCode
;
323 error
.resourceID
= resource
;
324 error
.sequenceNumber
= dpy
->request
;
325 error
.type
= X_Error
;
326 error
.majorCode
= gc
->majorOpcode
;
327 error
.minorCode
= minorCode
;
328 _XError(dpy
, &error
);
331 #endif /* GLX_USE_APPLEGL */
334 * Make a particular context current.
336 * \note This is in this file so that it can access dummyContext.
339 MakeContextCurrent(Display
* dpy
, GLXDrawable draw
,
340 GLXDrawable read
, GLXContext gc
)
342 const GLXContext oldGC
= __glXGetCurrentContext();
343 #ifdef GLX_USE_APPLEGL
344 bool error
= apple_glx_make_current_context(dpy
,
345 (oldGC
&& oldGC
!= &dummyContext
) ? oldGC
->driContext
: NULL
,
346 gc
? gc
->driContext
: NULL
, draw
);
348 apple_glx_diagnostic("%s: error %s\n", __func__
, error
? "YES" : "NO");
352 xGLXMakeCurrentReply reply
;
353 const CARD8 opcode
= __glXSetupForCommand(dpy
);
354 const CARD8 oldOpcode
= ((gc
== oldGC
) || (oldGC
== &dummyContext
))
355 ? opcode
: __glXSetupForCommand(oldGC
->currentDpy
);
356 Bool bindReturnValue
;
357 __GLXattribute
*state
;
359 if (!opcode
|| !oldOpcode
) {
363 /* Make sure that the new context has a nonzero ID. In the request,
364 * a zero context ID is used only to mean that we bind to no current
367 if ((gc
!= NULL
) && (gc
->xid
== None
)) {
371 if (gc
== NULL
&& (draw
!= None
|| read
!= None
)) {
372 __glXGenerateError(dpy
, gc
, (draw
!= None
) ? draw
: read
,
373 BadMatch
, X_GLXMakeContextCurrent
);
376 if (gc
!= NULL
&& (draw
== None
|| read
== None
)) {
377 __glXGenerateError(dpy
, gc
, None
, BadMatch
, X_GLXMakeContextCurrent
);
381 _glapi_check_multithread();
383 if (gc
!= NULL
&& gc
->thread_id
!= 0 && gc
->thread_id
!= _glthread_GetID()) {
384 __glXGenerateError(dpy
, gc
, gc
->xid
,
385 BadAccess
, X_GLXMakeContextCurrent
);
389 #if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL)
390 /* Bind the direct rendering context to the drawable */
391 if (gc
&& gc
->driContext
) {
392 __GLXDRIdrawable
*pdraw
= FetchDRIDrawable(dpy
, draw
, gc
);
393 __GLXDRIdrawable
*pread
= FetchDRIDrawable(dpy
, read
, gc
);
395 if ((pdraw
== NULL
) || (pread
== NULL
)) {
396 __glXGenerateError(dpy
, gc
, (pdraw
== NULL
) ? draw
: read
,
397 GLXBadDrawable
, X_GLXMakeContextCurrent
);
402 (gc
->driContext
->bindContext
) (gc
->driContext
, pdraw
, pread
);
404 else if (!gc
&& oldGC
&& oldGC
->driContext
) {
405 bindReturnValue
= True
;
410 /* Send a glXMakeCurrent request to bind the new context. */
412 SendMakeCurrentRequest(dpy
, opcode
, gc
? gc
->xid
: None
,
413 ((dpy
!= oldGC
->currentDpy
)
415 ? None
: oldGC
->currentContextTag
, draw
, read
,
420 if (!bindReturnValue
) {
424 #if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL)
425 if ((dpy
!= oldGC
->currentDpy
|| (gc
&& gc
->driContext
)) &&
426 !oldGC
->isDirect
&& oldGC
!= &dummyContext
) {
428 if ((dpy
!= oldGC
->currentDpy
) && oldGC
!= &dummyContext
) {
430 xGLXMakeCurrentReply dummy_reply
;
432 /* We are either switching from one dpy to another and have to
433 * send a request to the previous dpy to unbind the previous
434 * context, or we are switching away from a indirect context to
435 * a direct context and have to send a request to the dpy to
436 * unbind the previous context.
438 (void) SendMakeCurrentRequest(oldGC
->currentDpy
, oldOpcode
, None
,
439 oldGC
->currentContextTag
, None
, None
,
442 #if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL)
443 else if (oldGC
->driContext
&& oldGC
!= gc
) {
444 oldGC
->driContext
->unbindContext(oldGC
->driContext
);
448 #endif /* GLX_USE_APPLEGL */
450 /* Update our notion of what is current */
453 /* Even though the contexts are the same the drawable might have
454 * changed. Note that gc cannot be the dummy, and that oldGC
455 * cannot be NULL, therefore if they are the same, gc is not
456 * NULL and not the dummy.
459 gc
->currentDrawable
= draw
;
460 gc
->currentReadable
= read
;
464 if (oldGC
!= &dummyContext
) {
465 /* Old current context is no longer current to anybody */
466 oldGC
->currentDpy
= 0;
467 oldGC
->currentDrawable
= None
;
468 oldGC
->currentReadable
= None
;
469 oldGC
->currentContextTag
= 0;
470 oldGC
->thread_id
= 0;
471 #ifdef GLX_USE_APPLEGL
474 * At this point we should check if the context has been
475 * through glXDestroyContext, and redestroy it if so.
477 if(oldGC
->do_destroy
) {
479 /* glXDestroyContext uses the same global lock. */
480 glXDestroyContext(dpy
, oldGC
);
483 if (oldGC
->xid
== None
) {
484 /* We are switching away from a context that was
485 * previously destroyed, so we need to free the memory
486 * for the old handle.
488 #if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL)
489 /* Destroy the old direct rendering context */
490 if (oldGC
->driContext
) {
491 oldGC
->driContext
->destroyContext(oldGC
->driContext
,
494 oldGC
->driContext
= NULL
;
497 __glXFreeContext(oldGC
);
498 #endif /* GLX_USE_APPLEGL */
502 __glXSetCurrentContext(gc
);
504 gc
->currentDpy
= dpy
;
505 gc
->currentDrawable
= draw
;
506 gc
->currentReadable
= read
;
507 #ifndef GLX_USE_APPLEGL
508 gc
->thread_id
= _glthread_GetID();
510 #if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL)
511 if (!gc
->driContext
) {
514 IndirectAPI
= __glXNewIndirectAPI();
515 _glapi_set_dispatch(IndirectAPI
);
517 state
= (__GLXattribute
*) (gc
->client_state_private
);
519 gc
->currentContextTag
= reply
.contextTag
;
520 if (state
->array_state
== NULL
) {
521 (void) glGetString(GL_EXTENSIONS
);
522 (void) glGetString(GL_VERSION
);
523 __glXInitVertexArrayState(gc
);
525 #if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL)
528 gc
->currentContextTag
= -1;
531 #endif /* GLX_USE_APPLEGL */
534 __glXSetCurrentContextNull();
543 glXMakeCurrent(Display
* dpy
, GLXDrawable draw
, GLXContext gc
)
545 return MakeContextCurrent(dpy
, draw
, draw
, gc
);
549 GLX_ALIAS(Bool
, glXMakeCurrentReadSGI
,
550 (Display
* dpy
, GLXDrawable d
, GLXDrawable r
, GLXContext ctx
),
551 (dpy
, d
, r
, ctx
), MakeContextCurrent
)
554 GLX_ALIAS(Bool
, glXMakeContextCurrent
,
555 (Display
* dpy
, GLXDrawable d
, GLXDrawable r
,
556 GLXContext ctx
), (dpy
, d
, r
, ctx
), MakeContextCurrent
)