1 /* -*- mode: c; tab-width: 3; indent-tabs-mode: nil; c-basic-offset: 3; coding: utf-8-unix -*- */
3 * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
4 * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
13 * The above copyright notice including the dates of first publication and
14 * either this permission notice or a reference to
15 * http://oss.sgi.com/projects/FreeB/
16 * shall be included in all copies or substantial portions of the Software.
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
23 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26 * Except as contained in this notice, the name of Silicon Graphics, Inc.
27 * shall not be used in advertising or otherwise to promote the sale, use or
28 * other dealings in this Software without prior written authorization from
29 * Silicon Graphics, Inc.
34 * Client-side GLX interface for current context management.
37 #include "glxclient.h"
39 #include "indirect_init.h"
41 #ifdef GLX_DIRECT_RENDERING
46 ** We setup some dummy structures here so that the API can be used
47 ** even if no context is current.
50 static GLubyte dummyBuffer
[__GLX_BUFFER_LIMIT_SIZE
];
53 ** Dummy context used by small commands when there is no current context.
55 ** gl and glx entry points are designed to operate as nop's when using
56 ** the dummy context structure.
58 static __GLXcontext dummyContext
= {
62 &dummyBuffer
[__GLX_BUFFER_LIMIT_SIZE
],
68 ** All indirect rendering contexts will share the same indirect dispatch table.
70 static __GLapi
*IndirectAPI
= NULL
;
74 * Current context management and locking
77 #if defined( USE_XTHREADS )
80 static GLboolean TSDinitialized
= GL_FALSE
;
81 static xthread_key_t ContextTSD
;
83 _X_HIDDEN __GLXcontext
*
84 __glXGetCurrentContext(void)
86 if (!TSDinitialized
) {
87 xthread_key_create(&ContextTSD
, NULL
);
88 TSDinitialized
= GL_TRUE
;
93 xthread_get_specific(ContextTSD
, &p
);
97 return (__GLXcontext
*) p
;
102 __glXSetCurrentContext(__GLXcontext
* c
)
104 if (!TSDinitialized
) {
105 xthread_key_create(&ContextTSD
, NULL
);
106 TSDinitialized
= GL_TRUE
;
108 xthread_set_specific(ContextTSD
, c
);
112 /* Used by the __glXLock() and __glXUnlock() macros */
113 _X_HIDDEN xmutex_rec __glXmutex
;
115 #elif defined( PTHREADS )
117 _X_HIDDEN pthread_mutex_t __glXmutex
= PTHREAD_MUTEX_INITIALIZER
;
119 # if defined( GLX_USE_TLS )
122 * Per-thread GLX context pointer.
124 * \c __glXSetCurrentContext is written is such a way that this pointer can
125 * \b never be \c NULL. This is important! Because of this
126 * \c __glXGetCurrentContext can be implemented as trivial macro.
128 __thread
void *__glX_tls_Context
__attribute__ ((tls_model("initial-exec")))
132 __glXSetCurrentContext(__GLXcontext
* c
)
134 __glX_tls_Context
= (c
!= NULL
) ? c
: &dummyContext
;
139 static pthread_once_t once_control
= PTHREAD_ONCE_INIT
;
142 * Per-thread data key.
144 * Once \c init_thread_data has been called, the per-thread data key will
145 * take a value of \c NULL. As each new thread is created the default
146 * value, in that thread, will be \c NULL.
148 static pthread_key_t ContextTSD
;
151 * Initialize the per-thread data key.
153 * This function is called \b exactly once per-process (not per-thread!) to
154 * initialize the per-thread data key. This is ideally done using the
155 * \c pthread_once mechanism.
158 init_thread_data(void)
160 if (pthread_key_create(&ContextTSD
, NULL
) != 0) {
161 perror("pthread_key_create");
167 __glXSetCurrentContext(__GLXcontext
* c
)
169 pthread_once(&once_control
, init_thread_data
);
170 pthread_setspecific(ContextTSD
, c
);
173 _X_HIDDEN __GLXcontext
*
174 __glXGetCurrentContext(void)
178 pthread_once(&once_control
, init_thread_data
);
180 v
= pthread_getspecific(ContextTSD
);
181 return (v
== NULL
) ? &dummyContext
: (__GLXcontext
*) v
;
184 # endif /* defined( GLX_USE_TLS ) */
186 #elif defined( THREADS )
188 #error Unknown threading method specified.
192 /* not thread safe */
193 _X_HIDDEN __GLXcontext
*__glXcurrentContext
= &dummyContext
;
199 __glXSetCurrentContextNull(void)
201 __glXSetCurrentContext(&dummyContext
);
202 #ifdef GLX_DIRECT_RENDERING
203 _glapi_set_dispatch(NULL
); /* no-op functions */
208 /************************************************************************/
211 glXGetCurrentContext(void)
213 GLXContext cx
= __glXGetCurrentContext();
215 if (cx
== &dummyContext
) {
224 glXGetCurrentDrawable(void)
226 GLXContext gc
= __glXGetCurrentContext();
227 return gc
->currentDrawable
;
231 /************************************************************************/
234 * Sends a GLX protocol message to the specified display to make the context
235 * and the drawables current.
237 * \param dpy Display to send the message to.
238 * \param opcode Major opcode value for the display.
239 * \param gc_id Context tag for the context to be made current.
240 * \param draw Drawable ID for the "draw" drawable.
241 * \param read Drawable ID for the "read" drawable.
242 * \param reply Space to store the X-server's reply.
245 * This function assumes that \c dpy is locked with \c LockDisplay on entry.
248 SendMakeCurrentRequest(Display
* dpy
, CARD8 opcode
,
249 GLXContextID gc_id
, GLXContextTag gc_tag
,
250 GLXDrawable draw
, GLXDrawable read
,
251 xGLXMakeCurrentReply
* reply
)
259 xGLXMakeCurrentReq
*req
;
261 GetReq(GLXMakeCurrent
, req
);
262 req
->reqType
= opcode
;
263 req
->glxCode
= X_GLXMakeCurrent
;
264 req
->drawable
= draw
;
265 req
->context
= gc_id
;
266 req
->oldContextTag
= gc_tag
;
269 __GLXdisplayPrivate
*priv
= __glXInitialize(dpy
);
271 /* If the server can support the GLX 1.3 version, we should
272 * perfer that. Not only that, some servers support GLX 1.3 but
273 * not the SGI extension.
276 if ((priv
->majorVersion
> 1) || (priv
->minorVersion
>= 3)) {
277 xGLXMakeContextCurrentReq
*req
;
279 GetReq(GLXMakeContextCurrent
, req
);
280 req
->reqType
= opcode
;
281 req
->glxCode
= X_GLXMakeContextCurrent
;
282 req
->drawable
= draw
;
283 req
->readdrawable
= read
;
284 req
->context
= gc_id
;
285 req
->oldContextTag
= gc_tag
;
288 xGLXVendorPrivateWithReplyReq
*vpreq
;
289 xGLXMakeCurrentReadSGIReq
*req
;
291 GetReqExtra(GLXVendorPrivateWithReply
,
292 sz_xGLXMakeCurrentReadSGIReq
-
293 sz_xGLXVendorPrivateWithReplyReq
, vpreq
);
294 req
= (xGLXMakeCurrentReadSGIReq
*) vpreq
;
295 req
->reqType
= opcode
;
296 req
->glxCode
= X_GLXVendorPrivateWithReply
;
297 req
->vendorCode
= X_GLXvop_MakeCurrentReadSGI
;
298 req
->drawable
= draw
;
299 req
->readable
= read
;
300 req
->context
= gc_id
;
301 req
->oldContextTag
= gc_tag
;
305 ret
= _XReply(dpy
, (xReply
*) reply
, 0, False
);
314 #ifdef GLX_DIRECT_RENDERING
315 static __GLXDRIdrawable
*
316 FetchDRIDrawable(Display
* dpy
,
317 GLXDrawable glxDrawable
, GLXContext gc
, Bool pre13
)
319 __GLXdisplayPrivate
*const priv
= __glXInitialize(dpy
);
320 __GLXDRIdrawable
*pdraw
;
321 __GLXscreenConfigs
*psc
;
327 psc
= &priv
->screenConfigs
[gc
->screen
];
328 if (psc
->drawHash
== NULL
)
331 if (__glxHashLookup(psc
->drawHash
, glxDrawable
, (void *) &pdraw
) == 0)
334 /* If this is glXMakeCurrent (pre GLX 1.3) we allow creating the
335 * GLX drawable on the fly. Otherwise we pass None as the X
338 drawable
= glxDrawable
;
342 pdraw
= psc
->driScreen
->createDrawable(psc
, drawable
,
343 glxDrawable
, gc
->mode
);
344 if (__glxHashInsert(psc
->drawHash
, glxDrawable
, pdraw
)) {
345 (*pdraw
->destroyDrawable
) (pdraw
);
351 #endif /* GLX_DIRECT_RENDERING */
355 * Make a particular context current.
357 * \note This is in this file so that it can access dummyContext.
360 MakeContextCurrent(Display
* dpy
, GLXDrawable draw
,
361 GLXDrawable read
, GLXContext gc
, Bool pre13
)
363 xGLXMakeCurrentReply reply
;
364 const GLXContext oldGC
= __glXGetCurrentContext();
365 const CARD8 opcode
= __glXSetupForCommand(dpy
);
366 const CARD8 oldOpcode
= ((gc
== oldGC
) || (oldGC
== &dummyContext
))
367 ? opcode
: __glXSetupForCommand(oldGC
->currentDpy
);
368 Bool bindReturnValue
;
371 if (!opcode
|| !oldOpcode
) {
375 /* Make sure that the new context has a nonzero ID. In the request,
376 * a zero context ID is used only to mean that we bind to no current
379 if ((gc
!= NULL
) && (gc
->xid
== None
)) {
383 _glapi_check_multithread();
385 #ifdef GLX_DIRECT_RENDERING
386 /* Bind the direct rendering context to the drawable */
387 if (gc
&& gc
->driContext
) {
388 __GLXDRIdrawable
*pdraw
= FetchDRIDrawable(dpy
, draw
, gc
, pre13
);
389 __GLXDRIdrawable
*pread
= FetchDRIDrawable(dpy
, read
, gc
, pre13
);
392 (gc
->driContext
->bindContext
) (gc
->driContext
, pdraw
, pread
);
397 /* Send a glXMakeCurrent request to bind the new context. */
399 SendMakeCurrentRequest(dpy
, opcode
, gc
? gc
->xid
: None
,
400 ((dpy
!= oldGC
->currentDpy
)
402 ? None
: oldGC
->currentContextTag
, draw
, read
,
407 if (!bindReturnValue
) {
411 #ifdef GLX_DIRECT_RENDERING
412 if ((dpy
!= oldGC
->currentDpy
|| (gc
&& gc
->driContext
)) &&
413 !oldGC
->isDirect
&& oldGC
!= &dummyContext
) {
415 if ((dpy
!= oldGC
->currentDpy
) && oldGC
!= &dummyContext
) {
417 xGLXMakeCurrentReply dummy_reply
;
419 /* We are either switching from one dpy to another and have to
420 * send a request to the previous dpy to unbind the previous
421 * context, or we are switching away from a indirect context to
422 * a direct context and have to send a request to the dpy to
423 * unbind the previous context.
425 (void) SendMakeCurrentRequest(oldGC
->currentDpy
, oldOpcode
, None
,
426 oldGC
->currentContextTag
, None
, None
,
429 #ifdef GLX_DIRECT_RENDERING
430 else if (oldGC
->driContext
) {
431 oldGC
->driContext
->unbindContext(oldGC
->driContext
);
436 /* Update our notion of what is current */
439 /* Even though the contexts are the same the drawable might have
440 * changed. Note that gc cannot be the dummy, and that oldGC
441 * cannot be NULL, therefore if they are the same, gc is not
442 * NULL and not the dummy.
444 gc
->currentDrawable
= draw
;
445 gc
->currentReadable
= read
;
448 if (oldGC
!= &dummyContext
) {
449 /* Old current context is no longer current to anybody */
450 oldGC
->currentDpy
= 0;
451 oldGC
->currentDrawable
= None
;
452 oldGC
->currentReadable
= None
;
453 oldGC
->currentContextTag
= 0;
455 if (oldGC
->xid
== None
) {
456 /* We are switching away from a context that was
457 * previously destroyed, so we need to free the memory
458 * for the old handle.
460 #ifdef GLX_DIRECT_RENDERING
461 /* Destroy the old direct rendering context */
462 if (oldGC
->driContext
) {
463 oldGC
->driContext
->destroyContext(oldGC
->driContext
,
466 oldGC
->driContext
= NULL
;
469 __glXFreeContext(oldGC
);
473 __glXSetCurrentContext(gc
);
475 gc
->currentDpy
= dpy
;
476 gc
->currentDrawable
= draw
;
477 gc
->currentReadable
= read
;
479 #ifdef GLX_DIRECT_RENDERING
480 if (!gc
->driContext
) {
483 IndirectAPI
= __glXNewIndirectAPI();
484 _glapi_set_dispatch(IndirectAPI
);
486 #ifdef GLX_USE_APPLEGL
488 extern void XAppleDRIUseIndirectDispatch(void);
489 XAppleDRIUseIndirectDispatch();
493 __GLXattribute
*state
=
494 (__GLXattribute
*) (gc
->client_state_private
);
496 gc
->currentContextTag
= reply
.contextTag
;
497 if (state
->array_state
== NULL
) {
498 (void) glGetString(GL_EXTENSIONS
);
499 (void) glGetString(GL_VERSION
);
500 __glXInitVertexArrayState(gc
);
502 #ifdef GLX_DIRECT_RENDERING
505 gc
->currentContextTag
= -1;
510 __glXSetCurrentContextNull();
519 glXMakeCurrent(Display
* dpy
, GLXDrawable draw
, GLXContext gc
)
521 return MakeContextCurrent(dpy
, draw
, draw
, gc
, True
);
525 GLX_ALIAS(Bool
, glXMakeCurrentReadSGI
,
526 (Display
* dpy
, GLXDrawable d
, GLXDrawable r
, GLXContext ctx
),
527 (dpy
, d
, r
, ctx
, False
), MakeContextCurrent
)
529 PUBLIC
GLX_ALIAS(Bool
, glXMakeContextCurrent
,
530 (Display
* dpy
, GLXDrawable d
, GLXDrawable r
,
531 GLXContext ctx
), (dpy
, d
, r
, ctx
, False
),