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 struct glx_context 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 struct _glapi_table
*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(struct glx_context
* 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(struct glx_context
* c
)
138 pthread_once(&once_control
, init_thread_data
);
139 pthread_setspecific(ContextTSD
, c
);
142 _X_HIDDEN
struct glx_context
*
143 __glXGetCurrentContext(void)
147 pthread_once(&once_control
, init_thread_data
);
149 v
= pthread_getspecific(ContextTSD
);
150 return (v
== NULL
) ? &dummyContext
: (struct glx_context
*) v
;
153 # endif /* defined( GLX_USE_TLS ) */
155 #elif defined( THREADS )
157 #error Unknown threading method specified.
161 /* not thread safe */
162 _X_HIDDEN
struct glx_context
*__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 struct glx_context
*cx
= __glXGetCurrentContext();
187 if (cx
== &dummyContext
) {
191 return (GLXContext
) cx
;
195 _X_EXPORT GLXDrawable
196 glXGetCurrentDrawable(void)
198 struct glx_context
*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 struct glx_display
*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
,
290 GLXDrawable glxDrawable
, struct glx_context
*gc
)
292 struct glx_display
*const priv
= __glXInitialize(dpy
);
293 __GLXDRIdrawable
*pdraw
;
294 struct glx_screen
*psc
;
299 psc
= priv
->screens
[gc
->screen
];
300 if (priv
->drawHash
== NULL
)
303 if (__glxHashLookup(priv
->drawHash
, glxDrawable
, (void *) &pdraw
) == 0)
306 pdraw
= psc
->driScreen
->createDrawable(psc
, glxDrawable
,
307 glxDrawable
, gc
->config
);
308 if (__glxHashInsert(priv
->drawHash
, glxDrawable
, pdraw
)) {
309 (*pdraw
->destroyDrawable
) (pdraw
);
315 #endif /* GLX_DIRECT_RENDERING */
318 __glXGenerateError(Display
* dpy
, struct glx_context
*gc
, XID resource
,
319 BYTE errorCode
, CARD16 minorCode
)
323 error
.errorCode
= errorCode
;
324 error
.resourceID
= resource
;
325 error
.sequenceNumber
= dpy
->request
;
326 error
.type
= X_Error
;
327 error
.majorCode
= gc
->majorOpcode
;
328 error
.minorCode
= minorCode
;
329 _XError(dpy
, &error
);
332 #endif /* GLX_USE_APPLEGL */
335 * Make a particular context current.
337 * \note This is in this file so that it can access dummyContext.
340 MakeContextCurrent(Display
* dpy
, GLXDrawable draw
,
341 GLXDrawable read
, GLXContext gc_user
)
343 struct glx_context
*gc
= (struct glx_context
*) gc_user
;
344 struct glx_context
*oldGC
= __glXGetCurrentContext();
345 #ifdef GLX_USE_APPLEGL
346 bool error
= apple_glx_make_current_context(dpy
,
347 (oldGC
&& oldGC
!= &dummyContext
) ? oldGC
->driContext
: NULL
,
348 gc
? gc
->driContext
: NULL
, draw
);
350 apple_glx_diagnostic("%s: error %s\n", __func__
, error
? "YES" : "NO");
354 xGLXMakeCurrentReply reply
;
355 const CARD8 opcode
= __glXSetupForCommand(dpy
);
356 const CARD8 oldOpcode
= ((gc
== oldGC
) || (oldGC
== &dummyContext
))
357 ? opcode
: __glXSetupForCommand(oldGC
->currentDpy
);
358 Bool bindReturnValue
;
359 __GLXattribute
*state
;
361 if (!opcode
|| !oldOpcode
) {
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
369 if ((gc
!= NULL
) && (gc
->xid
== None
)) {
373 if (gc
== NULL
&& (draw
!= None
|| read
!= None
)) {
374 __glXGenerateError(dpy
, gc
, (draw
!= None
) ? draw
: read
,
375 BadMatch
, X_GLXMakeContextCurrent
);
378 if (gc
!= NULL
&& (draw
== None
|| read
== None
)) {
379 __glXGenerateError(dpy
, gc
, None
, BadMatch
, X_GLXMakeContextCurrent
);
383 _glapi_check_multithread();
385 if (gc
!= NULL
&& gc
->thread_id
!= 0 && gc
->thread_id
!= _glthread_GetID()) {
386 __glXGenerateError(dpy
, gc
, gc
->xid
,
387 BadAccess
, X_GLXMakeContextCurrent
);
391 #if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL)
392 /* Bind the direct rendering context to the drawable */
393 if (gc
&& gc
->driContext
) {
394 __GLXDRIdrawable
*pdraw
= FetchDRIDrawable(dpy
, draw
, gc
);
395 __GLXDRIdrawable
*pread
= FetchDRIDrawable(dpy
, read
, gc
);
397 if ((pdraw
== NULL
) || (pread
== NULL
)) {
398 __glXGenerateError(dpy
, gc
, (pdraw
== NULL
) ? draw
: read
,
399 GLXBadDrawable
, X_GLXMakeContextCurrent
);
404 (gc
->driContext
->bindContext
) (gc
, pdraw
, pread
);
406 else if (!gc
&& oldGC
&& oldGC
->driContext
) {
407 bindReturnValue
= True
;
412 /* Send a glXMakeCurrent request to bind the new context. */
414 SendMakeCurrentRequest(dpy
, opcode
, gc
? gc
->xid
: None
,
415 ((dpy
!= oldGC
->currentDpy
)
417 ? None
: oldGC
->currentContextTag
, draw
, read
,
422 if (!bindReturnValue
) {
426 #if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL)
427 if ((dpy
!= oldGC
->currentDpy
|| (gc
&& gc
->driContext
)) &&
428 !oldGC
->isDirect
&& oldGC
!= &dummyContext
) {
430 if ((dpy
!= oldGC
->currentDpy
) && oldGC
!= &dummyContext
) {
432 xGLXMakeCurrentReply dummy_reply
;
434 /* We are either switching from one dpy to another and have to
435 * send a request to the previous dpy to unbind the previous
436 * context, or we are switching away from a indirect context to
437 * a direct context and have to send a request to the dpy to
438 * unbind the previous context.
440 (void) SendMakeCurrentRequest(oldGC
->currentDpy
, oldOpcode
, None
,
441 oldGC
->currentContextTag
, None
, None
,
444 #if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL)
445 else if (oldGC
->driContext
&& oldGC
!= gc
) {
446 oldGC
->driContext
->unbindContext(oldGC
);
450 #endif /* GLX_USE_APPLEGL */
452 /* Update our notion of what is current */
455 /* Even though the contexts are the same the drawable might have
456 * changed. Note that gc cannot be the dummy, and that oldGC
457 * cannot be NULL, therefore if they are the same, gc is not
458 * NULL and not the dummy.
461 gc
->currentDrawable
= draw
;
462 gc
->currentReadable
= read
;
466 if (oldGC
!= &dummyContext
) {
467 /* Old current context is no longer current to anybody */
468 oldGC
->currentDpy
= 0;
469 oldGC
->currentDrawable
= None
;
470 oldGC
->currentReadable
= None
;
471 oldGC
->currentContextTag
= 0;
472 oldGC
->thread_id
= 0;
474 if (oldGC
->xid
== None
) {
475 /* We are switching away from a context that was
476 * previously destroyed, so we need to free the memory
477 * for the old handle.
479 oldGC
->vtable
->destroy(oldGC
);
483 __glXSetCurrentContext(gc
);
485 gc
->currentDpy
= dpy
;
486 gc
->currentDrawable
= draw
;
487 gc
->currentReadable
= read
;
488 #ifndef GLX_USE_APPLEGL
489 gc
->thread_id
= _glthread_GetID();
491 #if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL)
492 if (!gc
->driContext
) {
495 IndirectAPI
= __glXNewIndirectAPI();
496 _glapi_set_dispatch(IndirectAPI
);
498 state
= (__GLXattribute
*) (gc
->client_state_private
);
500 gc
->currentContextTag
= reply
.contextTag
;
501 if (state
->array_state
== NULL
) {
502 (void) glGetString(GL_EXTENSIONS
);
503 (void) glGetString(GL_VERSION
);
504 __glXInitVertexArrayState(gc
);
506 #if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL)
509 gc
->currentContextTag
= -1;
512 #endif /* GLX_USE_APPLEGL */
515 __glXSetCurrentContextNull();
524 glXMakeCurrent(Display
* dpy
, GLXDrawable draw
, GLXContext gc
)
526 return MakeContextCurrent(dpy
, draw
, draw
, gc
);
530 GLX_ALIAS(Bool
, glXMakeCurrentReadSGI
,
531 (Display
* dpy
, GLXDrawable d
, GLXDrawable r
, GLXContext ctx
),
532 (dpy
, d
, r
, ctx
), MakeContextCurrent
)
535 GLX_ALIAS(Bool
, glXMakeContextCurrent
,
536 (Display
* dpy
, GLXDrawable d
, GLXDrawable r
,
537 GLXContext ctx
), (dpy
, d
, r
, ctx
), MakeContextCurrent
)