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.
36 #include "glxclient.h"
38 #include "indirect_init.h"
41 ** We setup some dummy structures here so that the API can be used
42 ** even if no context is current.
45 static GLubyte dummyBuffer
[__GLX_BUFFER_LIMIT_SIZE
];
48 ** Dummy context used by small commands when there is no current context.
50 ** gl and glx entry points are designed to operate as nop's when using
51 ** the dummy context structure.
53 static __GLXcontext dummyContext
= {
57 &dummyBuffer
[__GLX_BUFFER_LIMIT_SIZE
],
63 ** All indirect rendering contexts will share the same indirect dispatch table.
65 static __GLapi
*IndirectAPI
= NULL
;
69 * Current context management and locking
72 #if defined( PTHREADS )
74 _X_HIDDEN pthread_mutex_t __glXmutex
= PTHREAD_MUTEX_INITIALIZER
;
76 # if defined( GLX_USE_TLS )
79 * Per-thread GLX context pointer.
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.
85 __thread
void *__glX_tls_Context
__attribute__ ((tls_model("initial-exec")))
89 __glXSetCurrentContext(__GLXcontext
* c
)
91 __glX_tls_Context
= (c
!= NULL
) ? c
: &dummyContext
;
96 static pthread_once_t once_control
= PTHREAD_ONCE_INIT
;
99 * Per-thread data key.
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.
105 static pthread_key_t ContextTSD
;
108 * Initialize the per-thread data key.
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.
115 init_thread_data(void)
117 if (pthread_key_create(&ContextTSD
, NULL
) != 0) {
118 perror("pthread_key_create");
124 __glXSetCurrentContext(__GLXcontext
* c
)
126 pthread_once(&once_control
, init_thread_data
);
127 pthread_setspecific(ContextTSD
, c
);
130 _X_HIDDEN __GLXcontext
*
131 __glXGetCurrentContext(void)
135 pthread_once(&once_control
, init_thread_data
);
137 v
= pthread_getspecific(ContextTSD
);
138 return (v
== NULL
) ? &dummyContext
: (__GLXcontext
*) v
;
141 # endif /* defined( GLX_USE_TLS ) */
143 #elif defined( THREADS )
145 #error Unknown threading method specified.
149 /* not thread safe */
150 _X_HIDDEN __GLXcontext
*__glXcurrentContext
= &dummyContext
;
156 __glXSetCurrentContextNull(void)
158 __glXSetCurrentContext(&dummyContext
);
159 #ifdef GLX_DIRECT_RENDERING
160 _glapi_set_dispatch(NULL
); /* no-op functions */
161 _glapi_set_context(NULL
);
166 /************************************************************************/
169 glXGetCurrentContext(void)
171 GLXContext cx
= __glXGetCurrentContext();
173 if (cx
== &dummyContext
) {
182 glXGetCurrentDrawable(void)
184 GLXContext gc
= __glXGetCurrentContext();
185 return gc
->currentDrawable
;
189 /************************************************************************/
192 * Sends a GLX protocol message to the specified display to make the context
193 * and the drawables current.
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.
203 * This function assumes that \c dpy is locked with \c LockDisplay on entry.
206 SendMakeCurrentRequest(Display
* dpy
, CARD8 opcode
,
207 GLXContextID gc_id
, GLXContextTag gc_tag
,
208 GLXDrawable draw
, GLXDrawable read
,
209 xGLXMakeCurrentReply
* reply
)
217 xGLXMakeCurrentReq
*req
;
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
;
227 __GLXdisplayPrivate
*priv
= __glXInitialize(dpy
);
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.
234 if ((priv
->majorVersion
> 1) || (priv
->minorVersion
>= 3)) {
235 xGLXMakeContextCurrentReq
*req
;
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
;
246 xGLXVendorPrivateWithReplyReq
*vpreq
;
247 xGLXMakeCurrentReadSGIReq
*req
;
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
;
263 ret
= _XReply(dpy
, (xReply
*) reply
, 0, False
);
272 #ifdef GLX_DIRECT_RENDERING
273 static __GLXDRIdrawable
*
274 FetchDRIDrawable(Display
* dpy
, GLXDrawable glxDrawable
, GLXContext gc
)
276 __GLXdisplayPrivate
*const priv
= __glXInitialize(dpy
);
277 __GLXDRIdrawable
*pdraw
;
278 __GLXscreenConfigs
*psc
;
283 psc
= &priv
->screenConfigs
[gc
->screen
];
284 if (psc
->drawHash
== NULL
)
287 if (__glxHashLookup(psc
->drawHash
, glxDrawable
, (void *) &pdraw
) == 0)
290 pdraw
= psc
->driScreen
->createDrawable(psc
, glxDrawable
,
291 glxDrawable
, gc
->mode
);
292 if (__glxHashInsert(psc
->drawHash
, glxDrawable
, pdraw
)) {
293 (*pdraw
->destroyDrawable
) (pdraw
);
299 #endif /* GLX_DIRECT_RENDERING */
302 __glXGenerateError(Display
* dpy
, GLXContext gc
, XID resource
,
303 BYTE errorCode
, CARD16 minorCode
)
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
);
317 * Make a particular context current.
319 * \note This is in this file so that it can access dummyContext.
322 MakeContextCurrent(Display
* dpy
, GLXDrawable draw
,
323 GLXDrawable read
, GLXContext gc
)
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
;
333 if (!opcode
|| !oldOpcode
) {
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
341 if ((gc
!= NULL
) && (gc
->xid
== None
)) {
345 if (gc
== NULL
&& (draw
!= None
|| read
!= None
)) {
346 __glXGenerateError(dpy
, gc
, (draw
!= None
) ? draw
: read
,
347 BadMatch
, X_GLXMakeContextCurrent
);
350 if (gc
!= NULL
&& (draw
== None
|| read
== None
)) {
351 __glXGenerateError(dpy
, gc
, None
, BadMatch
, X_GLXMakeContextCurrent
);
355 _glapi_check_multithread();
357 if (gc
!= NULL
&& gc
->thread_id
!= 0 && gc
->thread_id
!= _glthread_GetID()) {
358 __glXGenerateError(dpy
, gc
, gc
->xid
,
359 BadAccess
, X_GLXMakeContextCurrent
);
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
);
369 if ((pdraw
== NULL
) || (pread
== NULL
)) {
370 __glXGenerateError(dpy
, gc
, (pdraw
== NULL
) ? draw
: read
,
371 GLXBadDrawable
, X_GLXMakeContextCurrent
);
376 (gc
->driContext
->bindContext
) (gc
->driContext
, pdraw
, pread
);
378 else if (!gc
&& oldGC
&& oldGC
->driContext
) {
379 bindReturnValue
= True
;
384 /* Send a glXMakeCurrent request to bind the new context. */
386 SendMakeCurrentRequest(dpy
, opcode
, gc
? gc
->xid
: None
,
387 ((dpy
!= oldGC
->currentDpy
)
389 ? None
: oldGC
->currentContextTag
, draw
, read
,
394 if (!bindReturnValue
) {
398 #ifdef GLX_DIRECT_RENDERING
399 if ((dpy
!= oldGC
->currentDpy
|| (gc
&& gc
->driContext
)) &&
400 !oldGC
->isDirect
&& oldGC
!= &dummyContext
) {
402 if ((dpy
!= oldGC
->currentDpy
) && 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
&& oldGC
!= gc
) {
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
;
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;
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.
448 #ifdef GLX_DIRECT_RENDERING
449 /* Destroy the old direct rendering context */
450 if (oldGC
->driContext
) {
451 oldGC
->driContext
->destroyContext(oldGC
->driContext
,
454 oldGC
->driContext
= NULL
;
457 __glXFreeContext(oldGC
);
461 __glXSetCurrentContext(gc
);
463 gc
->currentDpy
= dpy
;
464 gc
->currentDrawable
= draw
;
465 gc
->currentReadable
= read
;
466 gc
->thread_id
= _glthread_GetID();
468 #ifdef GLX_DIRECT_RENDERING
469 if (!gc
->driContext
) {
472 IndirectAPI
= __glXNewIndirectAPI();
473 _glapi_set_dispatch(IndirectAPI
);
475 state
= (__GLXattribute
*) (gc
->client_state_private
);
477 gc
->currentContextTag
= reply
.contextTag
;
478 if (state
->array_state
== NULL
) {
479 (void) glGetString(GL_EXTENSIONS
);
480 (void) glGetString(GL_VERSION
);
481 __glXInitVertexArrayState(gc
);
483 #ifdef GLX_DIRECT_RENDERING
486 gc
->currentContextTag
= -1;
491 __glXSetCurrentContextNull();
500 glXMakeCurrent(Display
* dpy
, GLXDrawable draw
, GLXContext gc
)
502 return MakeContextCurrent(dpy
, draw
, draw
, gc
);
506 GLX_ALIAS(Bool
, glXMakeCurrentReadSGI
,
507 (Display
* dpy
, GLXDrawable d
, GLXDrawable r
, GLXContext ctx
),
508 (dpy
, d
, r
, ctx
), MakeContextCurrent
)
511 GLX_ALIAS(Bool
, glXMakeContextCurrent
,
512 (Display
* dpy
, GLXDrawable d
, GLXDrawable r
,
513 GLXContext ctx
), (dpy
, d
, r
, ctx
), MakeContextCurrent
)