glxcurrent.c revision 3464ebd5
1cdc920a0Smrg/*
2cdc920a0Smrg * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
3cdc920a0Smrg * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
4cdc920a0Smrg *
5cdc920a0Smrg * Permission is hereby granted, free of charge, to any person obtaining a
6cdc920a0Smrg * copy of this software and associated documentation files (the "Software"),
7cdc920a0Smrg * to deal in the Software without restriction, including without limitation
8cdc920a0Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9cdc920a0Smrg * and/or sell copies of the Software, and to permit persons to whom the
10cdc920a0Smrg * Software is furnished to do so, subject to the following conditions:
11cdc920a0Smrg *
12cdc920a0Smrg * The above copyright notice including the dates of first publication and
13cdc920a0Smrg * either this permission notice or a reference to
14cdc920a0Smrg * http://oss.sgi.com/projects/FreeB/
15cdc920a0Smrg * shall be included in all copies or substantial portions of the Software.
16cdc920a0Smrg *
17cdc920a0Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18cdc920a0Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19cdc920a0Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20cdc920a0Smrg * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21cdc920a0Smrg * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
22cdc920a0Smrg * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23cdc920a0Smrg * SOFTWARE.
24cdc920a0Smrg *
25cdc920a0Smrg * Except as contained in this notice, the name of Silicon Graphics, Inc.
26cdc920a0Smrg * shall not be used in advertising or otherwise to promote the sale, use or
27cdc920a0Smrg * other dealings in this Software without prior written authorization from
28cdc920a0Smrg * Silicon Graphics, Inc.
29cdc920a0Smrg */
30cdc920a0Smrg
31cdc920a0Smrg/**
32cdc920a0Smrg * \file glxcurrent.c
33cdc920a0Smrg * Client-side GLX interface for current context management.
34cdc920a0Smrg */
35cdc920a0Smrg
36cdc920a0Smrg#ifdef PTHREADS
37cdc920a0Smrg#include <pthread.h>
38cdc920a0Smrg#endif
39cdc920a0Smrg
40cdc920a0Smrg#include "glxclient.h"
41cdc920a0Smrg#ifdef GLX_USE_APPLEGL
42cdc920a0Smrg#include <stdlib.h>
43cdc920a0Smrg
44cdc920a0Smrg#include "apple_glx.h"
45cdc920a0Smrg#include "apple_glx_context.h"
46cdc920a0Smrg#endif
47cdc920a0Smrg
483464ebd5Sriastradh#include "glapi.h"
493464ebd5Sriastradh
50cdc920a0Smrg/*
51cdc920a0Smrg** We setup some dummy structures here so that the API can be used
52cdc920a0Smrg** even if no context is current.
53cdc920a0Smrg*/
54cdc920a0Smrg
55cdc920a0Smrgstatic GLubyte dummyBuffer[__GLX_BUFFER_LIMIT_SIZE];
563464ebd5Sriastradhstatic struct glx_context_vtable dummyVtable;
57cdc920a0Smrg/*
58cdc920a0Smrg** Dummy context used by small commands when there is no current context.
59cdc920a0Smrg** All the
60cdc920a0Smrg** gl and glx entry points are designed to operate as nop's when using
61cdc920a0Smrg** the dummy context structure.
62cdc920a0Smrg*/
633464ebd5Sriastradhstruct glx_context dummyContext = {
64cdc920a0Smrg   &dummyBuffer[0],
65cdc920a0Smrg   &dummyBuffer[0],
66cdc920a0Smrg   &dummyBuffer[0],
67cdc920a0Smrg   &dummyBuffer[__GLX_BUFFER_LIMIT_SIZE],
68cdc920a0Smrg   sizeof(dummyBuffer),
693464ebd5Sriastradh   &dummyVtable
70cdc920a0Smrg};
71cdc920a0Smrg
72cdc920a0Smrg/*
73cdc920a0Smrg * Current context management and locking
74cdc920a0Smrg */
75cdc920a0Smrg
76cdc920a0Smrg#if defined( PTHREADS )
77cdc920a0Smrg
78cdc920a0Smrg_X_HIDDEN pthread_mutex_t __glXmutex = PTHREAD_MUTEX_INITIALIZER;
79cdc920a0Smrg
80cdc920a0Smrg# if defined( GLX_USE_TLS )
81cdc920a0Smrg
82cdc920a0Smrg/**
83cdc920a0Smrg * Per-thread GLX context pointer.
84cdc920a0Smrg *
85cdc920a0Smrg * \c __glXSetCurrentContext is written is such a way that this pointer can
86cdc920a0Smrg * \b never be \c NULL.  This is important!  Because of this
87cdc920a0Smrg * \c __glXGetCurrentContext can be implemented as trivial macro.
88cdc920a0Smrg */
89cdc920a0Smrg__thread void *__glX_tls_Context __attribute__ ((tls_model("initial-exec")))
90cdc920a0Smrg   = &dummyContext;
91cdc920a0Smrg
92cdc920a0Smrg_X_HIDDEN void
933464ebd5Sriastradh__glXSetCurrentContext(struct glx_context * c)
94cdc920a0Smrg{
95cdc920a0Smrg   __glX_tls_Context = (c != NULL) ? c : &dummyContext;
96cdc920a0Smrg}
97cdc920a0Smrg
98cdc920a0Smrg# else
99cdc920a0Smrg
100cdc920a0Smrgstatic pthread_once_t once_control = PTHREAD_ONCE_INIT;
101cdc920a0Smrg
102cdc920a0Smrg/**
103cdc920a0Smrg * Per-thread data key.
104cdc920a0Smrg *
105cdc920a0Smrg * Once \c init_thread_data has been called, the per-thread data key will
106cdc920a0Smrg * take a value of \c NULL.  As each new thread is created the default
107cdc920a0Smrg * value, in that thread, will be \c NULL.
108cdc920a0Smrg */
109cdc920a0Smrgstatic pthread_key_t ContextTSD;
110cdc920a0Smrg
111cdc920a0Smrg/**
112cdc920a0Smrg * Initialize the per-thread data key.
113cdc920a0Smrg *
114cdc920a0Smrg * This function is called \b exactly once per-process (not per-thread!) to
115cdc920a0Smrg * initialize the per-thread data key.  This is ideally done using the
116cdc920a0Smrg * \c pthread_once mechanism.
117cdc920a0Smrg */
118cdc920a0Smrgstatic void
119cdc920a0Smrginit_thread_data(void)
120cdc920a0Smrg{
121cdc920a0Smrg   if (pthread_key_create(&ContextTSD, NULL) != 0) {
122cdc920a0Smrg      perror("pthread_key_create");
123cdc920a0Smrg      exit(-1);
124cdc920a0Smrg   }
125cdc920a0Smrg}
126cdc920a0Smrg
127cdc920a0Smrg_X_HIDDEN void
1283464ebd5Sriastradh__glXSetCurrentContext(struct glx_context * c)
129cdc920a0Smrg{
130cdc920a0Smrg   pthread_once(&once_control, init_thread_data);
131cdc920a0Smrg   pthread_setspecific(ContextTSD, c);
132cdc920a0Smrg}
133cdc920a0Smrg
1343464ebd5Sriastradh_X_HIDDEN struct glx_context *
135cdc920a0Smrg__glXGetCurrentContext(void)
136cdc920a0Smrg{
137cdc920a0Smrg   void *v;
138cdc920a0Smrg
139cdc920a0Smrg   pthread_once(&once_control, init_thread_data);
140cdc920a0Smrg
141cdc920a0Smrg   v = pthread_getspecific(ContextTSD);
1423464ebd5Sriastradh   return (v == NULL) ? &dummyContext : (struct glx_context *) v;
143cdc920a0Smrg}
144cdc920a0Smrg
145cdc920a0Smrg# endif /* defined( GLX_USE_TLS ) */
146cdc920a0Smrg
147cdc920a0Smrg#elif defined( THREADS )
148cdc920a0Smrg
149cdc920a0Smrg#error Unknown threading method specified.
150cdc920a0Smrg
151cdc920a0Smrg#else
152cdc920a0Smrg
153cdc920a0Smrg/* not thread safe */
1543464ebd5Sriastradh_X_HIDDEN struct glx_context *__glXcurrentContext = &dummyContext;
155cdc920a0Smrg
156cdc920a0Smrg#endif
157cdc920a0Smrg
158cdc920a0Smrg
159cdc920a0Smrg_X_HIDDEN void
160cdc920a0Smrg__glXSetCurrentContextNull(void)
161cdc920a0Smrg{
162cdc920a0Smrg   __glXSetCurrentContext(&dummyContext);
1633464ebd5Sriastradh#if defined(GLX_DIRECT_RENDERING)
164cdc920a0Smrg   _glapi_set_dispatch(NULL);   /* no-op functions */
165cdc920a0Smrg   _glapi_set_context(NULL);
166cdc920a0Smrg#endif
167cdc920a0Smrg}
168cdc920a0Smrg
1693464ebd5Sriastradh_X_EXPORT GLXContext
170cdc920a0SmrgglXGetCurrentContext(void)
171cdc920a0Smrg{
1723464ebd5Sriastradh   struct glx_context *cx = __glXGetCurrentContext();
173cdc920a0Smrg
174cdc920a0Smrg   if (cx == &dummyContext) {
175cdc920a0Smrg      return NULL;
176cdc920a0Smrg   }
177cdc920a0Smrg   else {
1783464ebd5Sriastradh      return (GLXContext) cx;
179cdc920a0Smrg   }
180cdc920a0Smrg}
181cdc920a0Smrg
1823464ebd5Sriastradh_X_EXPORT GLXDrawable
183cdc920a0SmrgglXGetCurrentDrawable(void)
184cdc920a0Smrg{
1853464ebd5Sriastradh   struct glx_context *gc = __glXGetCurrentContext();
186cdc920a0Smrg   return gc->currentDrawable;
187cdc920a0Smrg}
188cdc920a0Smrg
189cdc920a0Smrgstatic void
1903464ebd5Sriastradh__glXGenerateError(Display * dpy, XID resource,
191cdc920a0Smrg                   BYTE errorCode, CARD16 minorCode)
192cdc920a0Smrg{
193cdc920a0Smrg   xError error;
194cdc920a0Smrg
195cdc920a0Smrg   error.errorCode = errorCode;
196cdc920a0Smrg   error.resourceID = resource;
197cdc920a0Smrg   error.sequenceNumber = dpy->request;
198cdc920a0Smrg   error.type = X_Error;
1993464ebd5Sriastradh   error.majorCode = __glXSetupForCommand(dpy);
200cdc920a0Smrg   error.minorCode = minorCode;
201cdc920a0Smrg   _XError(dpy, &error);
202cdc920a0Smrg}
203cdc920a0Smrg
204cdc920a0Smrg/**
205cdc920a0Smrg * Make a particular context current.
206cdc920a0Smrg *
207cdc920a0Smrg * \note This is in this file so that it can access dummyContext.
208cdc920a0Smrg */
209cdc920a0Smrgstatic Bool
210cdc920a0SmrgMakeContextCurrent(Display * dpy, GLXDrawable draw,
2113464ebd5Sriastradh                   GLXDrawable read, GLXContext gc_user)
212cdc920a0Smrg{
2133464ebd5Sriastradh   struct glx_context *gc = (struct glx_context *) gc_user;
2143464ebd5Sriastradh   struct glx_context *oldGC = __glXGetCurrentContext();
2153464ebd5Sriastradh
2163464ebd5Sriastradh   /* XXX: If this is left out, then libGL ends up not having this
2173464ebd5Sriastradh    * symbol, and drivers using it fail to load.  Compare the
2183464ebd5Sriastradh    * implementation of this symbol to _glapi_noop_enable_warnings(),
2193464ebd5Sriastradh    * though, which gets into the library despite no callers, the same
2203464ebd5Sriastradh    * prototypes, and the same compile flags to the files containing
2213464ebd5Sriastradh    * them.  Moving the definition to glapi_nop.c gets it into the
2223464ebd5Sriastradh    * library, though.
2233464ebd5Sriastradh    */
2243464ebd5Sriastradh   (void)_glthread_GetID();
225cdc920a0Smrg
226cdc920a0Smrg   /* Make sure that the new context has a nonzero ID.  In the request,
227cdc920a0Smrg    * a zero context ID is used only to mean that we bind to no current
228cdc920a0Smrg    * context.
229cdc920a0Smrg    */
230cdc920a0Smrg   if ((gc != NULL) && (gc->xid == None)) {
231cdc920a0Smrg      return GL_FALSE;
232cdc920a0Smrg   }
233cdc920a0Smrg
234cdc920a0Smrg   if (gc == NULL && (draw != None || read != None)) {
2353464ebd5Sriastradh      __glXGenerateError(dpy, (draw != None) ? draw : read,
236cdc920a0Smrg                         BadMatch, X_GLXMakeContextCurrent);
237cdc920a0Smrg      return False;
238cdc920a0Smrg   }
239cdc920a0Smrg   if (gc != NULL && (draw == None || read == None)) {
2403464ebd5Sriastradh      __glXGenerateError(dpy, None, BadMatch, X_GLXMakeContextCurrent);
241cdc920a0Smrg      return False;
242cdc920a0Smrg   }
243cdc920a0Smrg
244cdc920a0Smrg   _glapi_check_multithread();
245cdc920a0Smrg
2463464ebd5Sriastradh   __glXLock();
2473464ebd5Sriastradh   if (oldGC == gc &&
2483464ebd5Sriastradh       gc->currentDrawable == draw && gc->currentReadable == read) {
2493464ebd5Sriastradh      __glXUnlock();
2503464ebd5Sriastradh      return True;
251cdc920a0Smrg   }
252cdc920a0Smrg
2533464ebd5Sriastradh   if (oldGC != &dummyContext) {
2543464ebd5Sriastradh      if (--oldGC->thread_refcount == 0) {
2553464ebd5Sriastradh	 oldGC->vtable->unbind(oldGC, gc);
2563464ebd5Sriastradh	 oldGC->currentDpy = 0;
257cdc920a0Smrg      }
258cdc920a0Smrg   }
259cdc920a0Smrg
2603464ebd5Sriastradh   if (gc) {
2613464ebd5Sriastradh      /* Attempt to bind the context.  We do this before mucking with
2623464ebd5Sriastradh       * gc and __glXSetCurrentContext to properly handle our state in
2633464ebd5Sriastradh       * case of an error.
2643464ebd5Sriastradh       *
2653464ebd5Sriastradh       * If an error occurs, set the Null context since we've already
2663464ebd5Sriastradh       * blown away our old context.  The caller is responsible for
2673464ebd5Sriastradh       * figuring out how to handle setting a valid context.
268cdc920a0Smrg       */
2693464ebd5Sriastradh      if (gc->vtable->bind(gc, oldGC, draw, read) != Success) {
2703464ebd5Sriastradh         __glXSetCurrentContextNull();
2713464ebd5Sriastradh         __glXUnlock();
2723464ebd5Sriastradh         __glXGenerateError(dpy, None, GLXBadContext, X_GLXMakeContextCurrent);
2733464ebd5Sriastradh         return GL_FALSE;
274cdc920a0Smrg      }
275cdc920a0Smrg
2763464ebd5Sriastradh      if (gc->thread_refcount == 0) {
277cdc920a0Smrg         gc->currentDpy = dpy;
278cdc920a0Smrg         gc->currentDrawable = draw;
279cdc920a0Smrg         gc->currentReadable = read;
280cdc920a0Smrg      }
2813464ebd5Sriastradh      gc->thread_refcount++;
2823464ebd5Sriastradh      __glXSetCurrentContext(gc);
2833464ebd5Sriastradh   } else {
2843464ebd5Sriastradh      __glXSetCurrentContextNull();
2853464ebd5Sriastradh   }
2863464ebd5Sriastradh
2873464ebd5Sriastradh   if (oldGC->thread_refcount == 0 && oldGC != &dummyContext && oldGC->xid == None) {
2883464ebd5Sriastradh      /* We are switching away from a context that was
2893464ebd5Sriastradh       * previously destroyed, so we need to free the memory
2903464ebd5Sriastradh       * for the old handle. */
2913464ebd5Sriastradh      oldGC->vtable->destroy(oldGC);
292cdc920a0Smrg   }
2933464ebd5Sriastradh
294cdc920a0Smrg   __glXUnlock();
2953464ebd5Sriastradh
296cdc920a0Smrg   return GL_TRUE;
297cdc920a0Smrg}
298cdc920a0Smrg
299cdc920a0Smrg
3003464ebd5Sriastradh_X_EXPORT Bool
301cdc920a0SmrgglXMakeCurrent(Display * dpy, GLXDrawable draw, GLXContext gc)
302cdc920a0Smrg{
303cdc920a0Smrg   return MakeContextCurrent(dpy, draw, draw, gc);
304cdc920a0Smrg}
305cdc920a0Smrg
3063464ebd5Sriastradh_X_EXPORT
307cdc920a0SmrgGLX_ALIAS(Bool, glXMakeCurrentReadSGI,
308cdc920a0Smrg          (Display * dpy, GLXDrawable d, GLXDrawable r, GLXContext ctx),
309cdc920a0Smrg          (dpy, d, r, ctx), MakeContextCurrent)
310cdc920a0Smrg
3113464ebd5Sriastradh_X_EXPORT
312cdc920a0SmrgGLX_ALIAS(Bool, glXMakeContextCurrent,
313cdc920a0Smrg          (Display * dpy, GLXDrawable d, GLXDrawable r,
314cdc920a0Smrg           GLXContext ctx), (dpy, d, r, ctx), MakeContextCurrent)
315