i965g: Fix after context transfers
[mesa/mesa-lb.git] / src / glx / glxcurrent.c
blobc28360bdde94ad3deffea14f232d4dd4306008ed
1 /*
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
23 * SOFTWARE.
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.
31 /**
32 * \file glxcurrent.c
33 * Client-side GLX interface for current context management.
36 #include "glxclient.h"
37 #include "glapi.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.
49 ** All the
50 ** gl and glx entry points are designed to operate as nop's when using
51 ** the dummy context structure.
53 static __GLXcontext dummyContext = {
54 &dummyBuffer[0],
55 &dummyBuffer[0],
56 &dummyBuffer[0],
57 &dummyBuffer[__GLX_BUFFER_LIMIT_SIZE],
58 sizeof(dummyBuffer),
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 )
78 /**
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")))
86 = &dummyContext;
88 _X_HIDDEN void
89 __glXSetCurrentContext(__GLXcontext * c)
91 __glX_tls_Context = (c != NULL) ? c : &dummyContext;
94 # else
96 static pthread_once_t once_control = PTHREAD_ONCE_INIT;
98 /**
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.
114 static void
115 init_thread_data(void)
117 if (pthread_key_create(&ContextTSD, NULL) != 0) {
118 perror("pthread_key_create");
119 exit(-1);
123 _X_HIDDEN void
124 __glXSetCurrentContext(__GLXcontext * c)
126 pthread_once(&once_control, init_thread_data);
127 pthread_setspecific(ContextTSD, c);
130 _X_HIDDEN __GLXcontext *
131 __glXGetCurrentContext(void)
133 void *v;
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.
147 #else
149 /* not thread safe */
150 _X_HIDDEN __GLXcontext *__glXcurrentContext = &dummyContext;
152 #endif
155 _X_HIDDEN void
156 __glXSetCurrentContextNull(void)
158 __glXSetCurrentContext(&dummyContext);
159 #ifdef GLX_DIRECT_RENDERING
160 _glapi_set_dispatch(NULL); /* no-op functions */
161 _glapi_set_context(NULL);
162 #endif
166 /************************************************************************/
168 PUBLIC GLXContext
169 glXGetCurrentContext(void)
171 GLXContext cx = __glXGetCurrentContext();
173 if (cx == &dummyContext) {
174 return NULL;
176 else {
177 return cx;
181 PUBLIC GLXDrawable
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.
202 * \warning
203 * This function assumes that \c dpy is locked with \c LockDisplay on entry.
205 static Bool
206 SendMakeCurrentRequest(Display * dpy, CARD8 opcode,
207 GLXContextID gc_id, GLXContextTag gc_tag,
208 GLXDrawable draw, GLXDrawable read,
209 xGLXMakeCurrentReply * reply)
211 Bool ret;
214 LockDisplay(dpy);
216 if (draw == read) {
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;
226 else {
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;
245 else {
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);
265 UnlockDisplay(dpy);
266 SyncHandle();
268 return ret;
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;
280 if (priv == NULL)
281 return NULL;
283 psc = &priv->screenConfigs[gc->screen];
284 if (psc->drawHash == NULL)
285 return NULL;
287 if (__glxHashLookup(psc->drawHash, glxDrawable, (void *) &pdraw) == 0)
288 return pdraw;
290 pdraw = psc->driScreen->createDrawable(psc, glxDrawable,
291 glxDrawable, gc->mode);
292 if (__glxHashInsert(psc->drawHash, glxDrawable, pdraw)) {
293 (*pdraw->destroyDrawable) (pdraw);
294 return NULL;
297 return pdraw;
299 #endif /* GLX_DIRECT_RENDERING */
301 static void
302 __glXGenerateError(Display * dpy, GLXContext gc, XID resource,
303 BYTE errorCode, CARD16 minorCode)
305 xError error;
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.
321 static Bool
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) {
334 return GL_FALSE;
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
339 * context.
341 if ((gc != NULL) && (gc->xid == None)) {
342 return GL_FALSE;
345 if (gc == NULL && (draw != None || read != None)) {
346 __glXGenerateError(dpy, gc, (draw != None) ? draw : read,
347 BadMatch, X_GLXMakeContextCurrent);
348 return False;
350 if (gc != NULL && (draw == None || read == None)) {
351 __glXGenerateError(dpy, gc, None, BadMatch, X_GLXMakeContextCurrent);
352 return False;
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);
360 return False;
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);
372 return False;
375 bindReturnValue =
376 (gc->driContext->bindContext) (gc->driContext, pdraw, pread);
378 else if (!gc && oldGC && oldGC->driContext) {
379 bindReturnValue = True;
381 else
382 #endif
384 /* Send a glXMakeCurrent request to bind the new context. */
385 bindReturnValue =
386 SendMakeCurrentRequest(dpy, opcode, gc ? gc->xid : None,
387 ((dpy != oldGC->currentDpy)
388 || oldGC->isDirect)
389 ? None : oldGC->currentContextTag, draw, read,
390 &reply);
394 if (!bindReturnValue) {
395 return False;
398 #ifdef GLX_DIRECT_RENDERING
399 if ((dpy != oldGC->currentDpy || (gc && gc->driContext)) &&
400 !oldGC->isDirect && oldGC != &dummyContext) {
401 #else
402 if ((dpy != oldGC->currentDpy) && oldGC != &dummyContext) {
403 #endif
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,
414 &dummy_reply);
416 #ifdef GLX_DIRECT_RENDERING
417 else if (oldGC->driContext && oldGC != gc) {
418 oldGC->driContext->unbindContext(oldGC->driContext);
420 #endif
423 /* Update our notion of what is current */
424 __glXLock();
425 if (gc == oldGC) {
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 else {
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,
452 oldGC->psc,
453 oldGC->createDpy);
454 oldGC->driContext = NULL;
456 #endif
457 __glXFreeContext(oldGC);
460 if (gc) {
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) {
470 #endif
471 if (!IndirectAPI)
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
485 else {
486 gc->currentContextTag = -1;
488 #endif
490 else {
491 __glXSetCurrentContextNull();
494 __glXUnlock();
495 return GL_TRUE;
499 PUBLIC Bool
500 glXMakeCurrent(Display * dpy, GLXDrawable draw, GLXContext gc)
502 return MakeContextCurrent(dpy, draw, draw, gc);
505 PUBLIC
506 GLX_ALIAS(Bool, glXMakeCurrentReadSGI,
507 (Display * dpy, GLXDrawable d, GLXDrawable r, GLXContext ctx),
508 (dpy, d, r, ctx), MakeContextCurrent)
510 PUBLIC
511 GLX_ALIAS(Bool, glXMakeContextCurrent,
512 (Display * dpy, GLXDrawable d, GLXDrawable r,
513 GLXContext ctx), (dpy, d, r, ctx), MakeContextCurrent)