2 ** License Applicability. Except to the extent portions of this file are
3 ** made subject to an alternative license as permitted in the SGI Free
4 ** Software License B, Version 1.1 (the "License"), the contents of this
5 ** file are subject only to the provisions of the License. You may not use
6 ** this file except in compliance with the License. You may obtain a copy
7 ** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
8 ** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
10 ** http://oss.sgi.com/projects/FreeB
12 ** Note that, as provided in the License, the Software is distributed on an
13 ** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
14 ** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
15 ** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
16 ** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
18 ** Original Code. The Original Code is: OpenGL Sample Implementation,
19 ** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
20 ** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
21 ** Copyright in any portions created by third parties is as indicated
22 ** elsewhere herein. All Rights Reserved.
24 ** Additional Notice Provisions: The application programming interfaces
25 ** established by SGI in conjunction with the Original Code are The
26 ** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
27 ** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
28 ** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
29 ** Window System(R) (Version 1.3), released October 19, 1998. This software
30 ** was created using the OpenGL(R) version 1.2.1 Sample Implementation
31 ** published by SGI, but has not been independently verified as being
32 ** compliant with the OpenGL(R) version 1.2.1 Specification.
38 * Client-side GLX interface for current context management.
41 #include "glxclient.h"
44 #include "indirect_init.h"
46 #ifdef GLX_DIRECT_RENDERING
51 ** We setup some dummy structures here so that the API can be used
52 ** even if no context is current.
55 static GLubyte dummyBuffer
[__GLX_BUFFER_LIMIT_SIZE
];
58 ** Dummy context used by small commands when there is no current context.
60 ** gl and glx entry points are designed to operate as nop's when using
61 ** the dummy context structure.
63 static __GLXcontext dummyContext
= {
67 &dummyBuffer
[__GLX_BUFFER_LIMIT_SIZE
],
73 ** All indirect rendering contexts will share the same indirect dispatch table.
75 static __GLapi
*IndirectAPI
= NULL
;
79 * Current context management and locking
82 #if defined( USE_XTHREADS )
85 static GLboolean TSDinitialized
= GL_FALSE
;
86 static xthread_key_t ContextTSD
;
88 _X_HIDDEN __GLXcontext
*__glXGetCurrentContext(void)
90 if (!TSDinitialized
) {
91 xthread_key_create(&ContextTSD
, NULL
);
92 TSDinitialized
= GL_TRUE
;
97 xthread_get_specific(ContextTSD
, &p
);
101 return (__GLXcontext
*) p
;
105 _X_HIDDEN
void __glXSetCurrentContext(__GLXcontext
*c
)
107 if (!TSDinitialized
) {
108 xthread_key_create(&ContextTSD
, NULL
);
109 TSDinitialized
= GL_TRUE
;
111 xthread_set_specific(ContextTSD
, c
);
115 /* Used by the __glXLock() and __glXUnlock() macros */
116 _X_HIDDEN xmutex_rec __glXmutex
;
118 #elif defined( PTHREADS )
120 _X_HIDDEN pthread_mutex_t __glXmutex
= PTHREAD_MUTEX_INITIALIZER
;
122 # if defined( GLX_USE_TLS )
125 * Per-thread GLX context pointer.
127 * \c __glXSetCurrentContext is written is such a way that this pointer can
128 * \b never be \c NULL. This is important! Because of this
129 * \c __glXGetCurrentContext can be implemented as trivial macro.
131 __thread
void * __glX_tls_Context
__attribute__((tls_model("initial-exec")))
134 _X_HIDDEN
void __glXSetCurrentContext( __GLXcontext
* c
)
136 __glX_tls_Context
= (c
!= NULL
) ? c
: &dummyContext
;
141 static pthread_once_t once_control
= PTHREAD_ONCE_INIT
;
144 * Per-thread data key.
146 * Once \c init_thread_data has been called, the per-thread data key will
147 * take a value of \c NULL. As each new thread is created the default
148 * value, in that thread, will be \c NULL.
150 static pthread_key_t ContextTSD
;
153 * Initialize the per-thread data key.
155 * This function is called \b exactly once per-process (not per-thread!) to
156 * initialize the per-thread data key. This is ideally done using the
157 * \c pthread_once mechanism.
159 static void init_thread_data( void )
161 if ( pthread_key_create( & ContextTSD
, NULL
) != 0 ) {
162 perror( "pthread_key_create" );
167 _X_HIDDEN
void __glXSetCurrentContext( __GLXcontext
* c
)
169 pthread_once( & once_control
, init_thread_data
);
170 pthread_setspecific( ContextTSD
, c
);
173 _X_HIDDEN __GLXcontext
* __glXGetCurrentContext( void )
177 pthread_once( & once_control
, init_thread_data
);
179 v
= pthread_getspecific( ContextTSD
);
180 return (v
== NULL
) ? & dummyContext
: (__GLXcontext
*) v
;
183 # endif /* defined( GLX_USE_TLS ) */
185 #elif defined( THREADS )
187 #error Unknown threading method specified.
191 /* not thread safe */
192 _X_HIDDEN __GLXcontext
*__glXcurrentContext
= &dummyContext
;
197 _X_HIDDEN
void __glXSetCurrentContextNull(void)
199 __glXSetCurrentContext(&dummyContext
);
200 #ifdef GLX_DIRECT_RENDERING
201 _glapi_set_dispatch(NULL
); /* no-op functions */
206 /************************************************************************/
208 PUBLIC GLXContext
glXGetCurrentContext(void)
210 GLXContext cx
= __glXGetCurrentContext();
212 if (cx
== &dummyContext
) {
219 PUBLIC GLXDrawable
glXGetCurrentDrawable(void)
221 GLXContext gc
= __glXGetCurrentContext();
222 return gc
->currentDrawable
;
226 /************************************************************************/
229 * Sends a GLX protocol message to the specified display to make the context
230 * and the drawables current.
232 * \param dpy Display to send the message to.
233 * \param opcode Major opcode value for the display.
234 * \param gc_id Context tag for the context to be made current.
235 * \param draw Drawable ID for the "draw" drawable.
236 * \param read Drawable ID for the "read" drawable.
237 * \param reply Space to store the X-server's reply.
240 * This function assumes that \c dpy is locked with \c LockDisplay on entry.
242 static Bool
SendMakeCurrentRequest(Display
*dpy
, CARD8 opcode
,
243 GLXContextID gc_id
, GLXContextTag gc_tag
,
244 GLXDrawable draw
, GLXDrawable read
,
245 xGLXMakeCurrentReply
*reply
)
253 xGLXMakeCurrentReq
*req
;
255 GetReq(GLXMakeCurrent
,req
);
256 req
->reqType
= opcode
;
257 req
->glxCode
= X_GLXMakeCurrent
;
258 req
->drawable
= draw
;
259 req
->context
= gc_id
;
260 req
->oldContextTag
= gc_tag
;
263 __GLXdisplayPrivate
*priv
= __glXInitialize(dpy
);
265 /* If the server can support the GLX 1.3 version, we should
266 * perfer that. Not only that, some servers support GLX 1.3 but
267 * not the SGI extension.
270 if ((priv
->majorVersion
> 1) || (priv
->minorVersion
>= 3)) {
271 xGLXMakeContextCurrentReq
*req
;
273 GetReq(GLXMakeContextCurrent
,req
);
274 req
->reqType
= opcode
;
275 req
->glxCode
= X_GLXMakeContextCurrent
;
276 req
->drawable
= draw
;
277 req
->readdrawable
= read
;
278 req
->context
= gc_id
;
279 req
->oldContextTag
= gc_tag
;
282 xGLXVendorPrivateWithReplyReq
*vpreq
;
283 xGLXMakeCurrentReadSGIReq
*req
;
285 GetReqExtra(GLXVendorPrivateWithReply
,
286 sz_xGLXMakeCurrentReadSGIReq
-sz_xGLXVendorPrivateWithReplyReq
,vpreq
);
287 req
= (xGLXMakeCurrentReadSGIReq
*)vpreq
;
288 req
->reqType
= opcode
;
289 req
->glxCode
= X_GLXVendorPrivateWithReply
;
290 req
->vendorCode
= X_GLXvop_MakeCurrentReadSGI
;
291 req
->drawable
= draw
;
292 req
->readable
= read
;
293 req
->context
= gc_id
;
294 req
->oldContextTag
= gc_tag
;
298 ret
= _XReply(dpy
, (xReply
*) reply
, 0, False
);
307 #ifdef GLX_DIRECT_RENDERING
308 static __GLXDRIdrawable
*
309 FetchDRIDrawable(Display
*dpy
,
310 GLXDrawable glxDrawable
, GLXContext gc
, Bool pre13
)
312 __GLXdisplayPrivate
* const priv
= __glXInitialize(dpy
);
313 __GLXDRIdrawable
*pdraw
;
314 __GLXscreenConfigs
*psc
;
320 psc
= &priv
->screenConfigs
[gc
->screen
];
321 if (psc
->drawHash
== NULL
)
324 if (__glxHashLookup(psc
->drawHash
, glxDrawable
, (void *) &pdraw
) == 0)
327 /* If this is glXMakeCurrent (pre GLX 1.3) we allow creating the
328 * GLX drawable on the fly. Otherwise we pass None as the X
331 drawable
= glxDrawable
;
335 pdraw
= psc
->driScreen
->createDrawable(psc
, drawable
,
336 glxDrawable
, gc
->mode
);
337 if (__glxHashInsert(psc
->drawHash
, glxDrawable
, pdraw
)) {
338 (*pdraw
->destroyDrawable
)(pdraw
);
344 #endif /* GLX_DIRECT_RENDERING */
348 * Make a particular context current.
350 * \note This is in this file so that it can access dummyContext.
352 static Bool
MakeContextCurrent(Display
*dpy
, GLXDrawable draw
,
353 GLXDrawable read
, GLXContext gc
,
356 xGLXMakeCurrentReply reply
;
357 const GLXContext oldGC
= __glXGetCurrentContext();
358 const CARD8 opcode
= __glXSetupForCommand(dpy
);
359 const CARD8 oldOpcode
= ((gc
== oldGC
) || (oldGC
== &dummyContext
))
360 ? opcode
: __glXSetupForCommand(oldGC
->currentDpy
);
361 Bool bindReturnValue
;
364 if (!opcode
|| !oldOpcode
) {
368 /* Make sure that the new context has a nonzero ID. In the request,
369 * a zero context ID is used only to mean that we bind to no current
372 if ((gc
!= NULL
) && (gc
->xid
== None
)) {
376 _glapi_check_multithread();
378 #ifdef GLX_DIRECT_RENDERING
379 /* Bind the direct rendering context to the drawable */
380 if (gc
&& gc
->driContext
) {
381 __GLXDRIdrawable
*pdraw
= FetchDRIDrawable(dpy
, draw
, gc
, pre13
);
382 __GLXDRIdrawable
*pread
= FetchDRIDrawable(dpy
, read
, gc
, pre13
);
385 (gc
->driContext
->bindContext
) (gc
->driContext
, pdraw
, pread
);
389 /* Send a glXMakeCurrent request to bind the new context. */
391 SendMakeCurrentRequest(dpy
, opcode
, gc
? gc
->xid
: None
,
392 ((dpy
!= oldGC
->currentDpy
) || oldGC
->isDirect
)
393 ? None
: oldGC
->currentContextTag
,
398 if (!bindReturnValue
) {
402 if ((dpy
!= oldGC
->currentDpy
|| (gc
&& gc
->driContext
)) &&
403 !oldGC
->isDirect
&& oldGC
!= &dummyContext
) {
404 xGLXMakeCurrentReply dummy_reply
;
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.
412 (void) SendMakeCurrentRequest(oldGC
->currentDpy
, oldOpcode
, None
,
413 oldGC
->currentContextTag
, None
, None
,
416 #ifdef GLX_DIRECT_RENDERING
417 else if (oldGC
->driContext
) {
418 oldGC
->driContext
->unbindContext(oldGC
->driContext
);
423 /* Update our notion of what is current */
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.
431 gc
->currentDrawable
= draw
;
432 gc
->currentReadable
= read
;
434 if (oldGC
!= &dummyContext
) {
435 /* Old current context is no longer current to anybody */
436 oldGC
->currentDpy
= 0;
437 oldGC
->currentDrawable
= None
;
438 oldGC
->currentReadable
= None
;
439 oldGC
->currentContextTag
= 0;
441 if (oldGC
->xid
== None
) {
442 /* We are switching away from a context that was
443 * previously destroyed, so we need to free the memory
444 * for the old handle.
446 #ifdef GLX_DIRECT_RENDERING
447 /* Destroy the old direct rendering context */
448 if (oldGC
->driContext
) {
449 oldGC
->driContext
->destroyContext(oldGC
->driContext
,
452 oldGC
->driContext
= NULL
;
455 __glXFreeContext(oldGC
);
459 __glXSetCurrentContext(gc
);
461 gc
->currentDpy
= dpy
;
462 gc
->currentDrawable
= draw
;
463 gc
->currentReadable
= read
;
465 if (!gc
->driContext
) {
467 IndirectAPI
= __glXNewIndirectAPI();
468 _glapi_set_dispatch(IndirectAPI
);
470 #ifdef GLX_USE_APPLEGL
472 extern void XAppleDRIUseIndirectDispatch(void);
473 XAppleDRIUseIndirectDispatch();
477 __GLXattribute
*state
=
478 (__GLXattribute
*)(gc
->client_state_private
);
480 gc
->currentContextTag
= reply
.contextTag
;
481 if (state
->array_state
== NULL
) {
482 (void) glGetString(GL_EXTENSIONS
);
483 (void) glGetString(GL_VERSION
);
484 __glXInitVertexArrayState(gc
);
488 gc
->currentContextTag
= -1;
491 __glXSetCurrentContextNull();
499 PUBLIC Bool
glXMakeCurrent(Display
*dpy
, GLXDrawable draw
, GLXContext gc
)
501 return MakeContextCurrent(dpy
, draw
, draw
, gc
, True
);
504 PUBLIC
GLX_ALIAS(Bool
, glXMakeCurrentReadSGI
,
505 (Display
*dpy
, GLXDrawable d
, GLXDrawable r
, GLXContext ctx
),
506 (dpy
, d
, r
, ctx
, False
), MakeContextCurrent
)
508 PUBLIC
GLX_ALIAS(Bool
, glXMakeContextCurrent
,
509 (Display
*dpy
, GLXDrawable d
, GLXDrawable r
, GLXContext ctx
),
510 (dpy
, d
, r
, ctx
, False
), MakeContextCurrent
)