glxcurrent.c revision b8e80941
1848b8605Smrg/*
2848b8605Smrg * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
3848b8605Smrg * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
4848b8605Smrg *
5848b8605Smrg * Permission is hereby granted, free of charge, to any person obtaining a
6848b8605Smrg * copy of this software and associated documentation files (the "Software"),
7848b8605Smrg * to deal in the Software without restriction, including without limitation
8848b8605Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9848b8605Smrg * and/or sell copies of the Software, and to permit persons to whom the
10848b8605Smrg * Software is furnished to do so, subject to the following conditions:
11848b8605Smrg *
12848b8605Smrg * The above copyright notice including the dates of first publication and
13848b8605Smrg * either this permission notice or a reference to
14848b8605Smrg * http://oss.sgi.com/projects/FreeB/
15848b8605Smrg * shall be included in all copies or substantial portions of the Software.
16848b8605Smrg *
17848b8605Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18848b8605Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19848b8605Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20848b8605Smrg * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21848b8605Smrg * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
22848b8605Smrg * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23848b8605Smrg * SOFTWARE.
24848b8605Smrg *
25848b8605Smrg * Except as contained in this notice, the name of Silicon Graphics, Inc.
26848b8605Smrg * shall not be used in advertising or otherwise to promote the sale, use or
27848b8605Smrg * other dealings in this Software without prior written authorization from
28848b8605Smrg * Silicon Graphics, Inc.
29848b8605Smrg */
30848b8605Smrg
31848b8605Smrg/**
32848b8605Smrg * \file glxcurrent.c
33848b8605Smrg * Client-side GLX interface for current context management.
34848b8605Smrg */
35848b8605Smrg
36848b8605Smrg#include <pthread.h>
37848b8605Smrg
38848b8605Smrg#include "glxclient.h"
39848b8605Smrg#include "glapi.h"
40b8e80941Smrg#include "glx_error.h"
41b8e80941Smrg
42b8e80941Smrg/*
43b8e80941Smrg * MASSIVE KLUDGE!
44b8e80941Smrg * We need these to not be extern in libGL.so because of
45b8e80941Smrg * PR toolchain/50277
46b8e80941Smrg */
47b8e80941Smrg#if defined(GLX_USE_TLS) && defined(__NetBSD__)
48b8e80941Smrg_X_EXPORT __thread struct _glapi_table * _glapi_tls_Dispatch
49b8e80941Smrg    __attribute__((tls_model("initial-exec"))) = NULL;
50b8e80941Smrg_X_EXPORT __thread void * _glapi_tls_Context
51b8e80941Smrg    __attribute__((tls_model("initial-exec")));
52b8e80941Smrg#endif
53848b8605Smrg
54848b8605Smrg/*
55848b8605Smrg** We setup some dummy structures here so that the API can be used
56848b8605Smrg** even if no context is current.
57848b8605Smrg*/
58848b8605Smrg
59848b8605Smrgstatic GLubyte dummyBuffer[__GLX_BUFFER_LIMIT_SIZE];
60848b8605Smrgstatic struct glx_context_vtable dummyVtable;
61848b8605Smrg/*
62848b8605Smrg** Dummy context used by small commands when there is no current context.
63848b8605Smrg** All the
64848b8605Smrg** gl and glx entry points are designed to operate as nop's when using
65848b8605Smrg** the dummy context structure.
66848b8605Smrg*/
67848b8605Smrgstruct glx_context dummyContext = {
68848b8605Smrg   &dummyBuffer[0],
69848b8605Smrg   &dummyBuffer[0],
70848b8605Smrg   &dummyBuffer[0],
71848b8605Smrg   &dummyBuffer[__GLX_BUFFER_LIMIT_SIZE],
72848b8605Smrg   sizeof(dummyBuffer),
73848b8605Smrg   &dummyVtable
74848b8605Smrg};
75848b8605Smrg
76848b8605Smrg/*
77848b8605Smrg * Current context management and locking
78848b8605Smrg */
79848b8605Smrg
80848b8605Smrg_X_HIDDEN pthread_mutex_t __glXmutex = PTHREAD_MUTEX_INITIALIZER;
81848b8605Smrg
82848b8605Smrg# if defined( GLX_USE_TLS )
83848b8605Smrg
84848b8605Smrg/**
85848b8605Smrg * Per-thread GLX context pointer.
86848b8605Smrg *
87848b8605Smrg * \c __glXSetCurrentContext is written is such a way that this pointer can
88848b8605Smrg * \b never be \c NULL.  This is important!  Because of this
89848b8605Smrg * \c __glXGetCurrentContext can be implemented as trivial macro.
90848b8605Smrg */
91848b8605Smrg__thread void *__glX_tls_Context __attribute__ ((tls_model("initial-exec")))
92b8e80941Smrg#if defined(__NetBSD__)
93b8e80941Smrg   = NULL; /* non-zero initializers not supported with dlopen */
94b8e80941Smrg#else
95848b8605Smrg   = &dummyContext;
96b8e80941Smrg#endif
97848b8605Smrg
98848b8605Smrg_X_HIDDEN void
99848b8605Smrg__glXSetCurrentContext(struct glx_context * c)
100848b8605Smrg{
101848b8605Smrg   __glX_tls_Context = (c != NULL) ? c : &dummyContext;
102848b8605Smrg}
103848b8605Smrg
104848b8605Smrg# else
105848b8605Smrg
106848b8605Smrgstatic pthread_once_t once_control = PTHREAD_ONCE_INIT;
107848b8605Smrg
108848b8605Smrg/**
109848b8605Smrg * Per-thread data key.
110848b8605Smrg *
111848b8605Smrg * Once \c init_thread_data has been called, the per-thread data key will
112848b8605Smrg * take a value of \c NULL.  As each new thread is created the default
113848b8605Smrg * value, in that thread, will be \c NULL.
114848b8605Smrg */
115848b8605Smrgstatic pthread_key_t ContextTSD;
116848b8605Smrg
117848b8605Smrg/**
118848b8605Smrg * Initialize the per-thread data key.
119848b8605Smrg *
120848b8605Smrg * This function is called \b exactly once per-process (not per-thread!) to
121848b8605Smrg * initialize the per-thread data key.  This is ideally done using the
122848b8605Smrg * \c pthread_once mechanism.
123848b8605Smrg */
124848b8605Smrgstatic void
125848b8605Smrginit_thread_data(void)
126848b8605Smrg{
127848b8605Smrg   if (pthread_key_create(&ContextTSD, NULL) != 0) {
128848b8605Smrg      perror("pthread_key_create");
129848b8605Smrg      exit(-1);
130848b8605Smrg   }
131848b8605Smrg}
132848b8605Smrg
133848b8605Smrg_X_HIDDEN void
134848b8605Smrg__glXSetCurrentContext(struct glx_context * c)
135848b8605Smrg{
136848b8605Smrg   pthread_once(&once_control, init_thread_data);
137848b8605Smrg   pthread_setspecific(ContextTSD, c);
138848b8605Smrg}
139848b8605Smrg
140848b8605Smrg_X_HIDDEN struct glx_context *
141848b8605Smrg__glXGetCurrentContext(void)
142848b8605Smrg{
143848b8605Smrg   void *v;
144848b8605Smrg
145848b8605Smrg   pthread_once(&once_control, init_thread_data);
146848b8605Smrg
147848b8605Smrg   v = pthread_getspecific(ContextTSD);
148848b8605Smrg   return (v == NULL) ? &dummyContext : (struct glx_context *) v;
149848b8605Smrg}
150848b8605Smrg
151848b8605Smrg# endif /* defined( GLX_USE_TLS ) */
152848b8605Smrg
153848b8605Smrg
154848b8605Smrg_X_HIDDEN void
155848b8605Smrg__glXSetCurrentContextNull(void)
156848b8605Smrg{
157848b8605Smrg   __glXSetCurrentContext(&dummyContext);
158848b8605Smrg#if defined(GLX_DIRECT_RENDERING)
159848b8605Smrg   _glapi_set_dispatch(NULL);   /* no-op functions */
160848b8605Smrg   _glapi_set_context(NULL);
161848b8605Smrg#endif
162848b8605Smrg}
163848b8605Smrg
164b8e80941Smrg_GLX_PUBLIC GLXContext
165848b8605SmrgglXGetCurrentContext(void)
166848b8605Smrg{
167848b8605Smrg   struct glx_context *cx = __glXGetCurrentContext();
168848b8605Smrg
169848b8605Smrg   if (cx == &dummyContext) {
170848b8605Smrg      return NULL;
171848b8605Smrg   }
172848b8605Smrg   else {
173848b8605Smrg      return (GLXContext) cx;
174848b8605Smrg   }
175848b8605Smrg}
176848b8605Smrg
177b8e80941Smrg_GLX_PUBLIC GLXDrawable
178848b8605SmrgglXGetCurrentDrawable(void)
179848b8605Smrg{
180848b8605Smrg   struct glx_context *gc = __glXGetCurrentContext();
181848b8605Smrg   return gc->currentDrawable;
182848b8605Smrg}
183848b8605Smrg
184848b8605Smrg/**
185848b8605Smrg * Make a particular context current.
186848b8605Smrg *
187848b8605Smrg * \note This is in this file so that it can access dummyContext.
188848b8605Smrg */
189848b8605Smrgstatic Bool
190848b8605SmrgMakeContextCurrent(Display * dpy, GLXDrawable draw,
191848b8605Smrg                   GLXDrawable read, GLXContext gc_user)
192848b8605Smrg{
193848b8605Smrg   struct glx_context *gc = (struct glx_context *) gc_user;
194848b8605Smrg   struct glx_context *oldGC = __glXGetCurrentContext();
195848b8605Smrg
196848b8605Smrg   /* Make sure that the new context has a nonzero ID.  In the request,
197848b8605Smrg    * a zero context ID is used only to mean that we bind to no current
198848b8605Smrg    * context.
199848b8605Smrg    */
200848b8605Smrg   if ((gc != NULL) && (gc->xid == None)) {
201848b8605Smrg      return GL_FALSE;
202848b8605Smrg   }
203848b8605Smrg
204848b8605Smrg   _glapi_check_multithread();
205848b8605Smrg
206848b8605Smrg   __glXLock();
207848b8605Smrg   if (oldGC == gc &&
208848b8605Smrg       gc->currentDrawable == draw && gc->currentReadable == read) {
209848b8605Smrg      __glXUnlock();
210848b8605Smrg      return True;
211848b8605Smrg   }
212848b8605Smrg
213b8e80941Smrg   /* can't have only one be 0 */
214b8e80941Smrg   if (!!draw != !!read) {
215b8e80941Smrg      __glXUnlock();
216b8e80941Smrg      __glXSendError(dpy, BadMatch, None, X_GLXMakeContextCurrent, True);
217b8e80941Smrg      return False;
218b8e80941Smrg   }
219b8e80941Smrg
220848b8605Smrg   if (oldGC != &dummyContext) {
221848b8605Smrg      if (--oldGC->thread_refcount == 0) {
222848b8605Smrg	 oldGC->vtable->unbind(oldGC, gc);
223848b8605Smrg	 oldGC->currentDpy = 0;
224848b8605Smrg      }
225848b8605Smrg   }
226848b8605Smrg
227848b8605Smrg   if (gc) {
228848b8605Smrg      /* Attempt to bind the context.  We do this before mucking with
229848b8605Smrg       * gc and __glXSetCurrentContext to properly handle our state in
230848b8605Smrg       * case of an error.
231848b8605Smrg       *
232848b8605Smrg       * If an error occurs, set the Null context since we've already
233848b8605Smrg       * blown away our old context.  The caller is responsible for
234848b8605Smrg       * figuring out how to handle setting a valid context.
235848b8605Smrg       */
236848b8605Smrg      if (gc->vtable->bind(gc, oldGC, draw, read) != Success) {
237848b8605Smrg         __glXSetCurrentContextNull();
238848b8605Smrg         __glXUnlock();
239b8e80941Smrg         __glXSendError(dpy, GLXBadContext, None, X_GLXMakeContextCurrent,
240b8e80941Smrg                        False);
241848b8605Smrg         return GL_FALSE;
242848b8605Smrg      }
243848b8605Smrg
244848b8605Smrg      if (gc->thread_refcount == 0) {
245848b8605Smrg         gc->currentDpy = dpy;
246848b8605Smrg         gc->currentDrawable = draw;
247848b8605Smrg         gc->currentReadable = read;
248848b8605Smrg      }
249848b8605Smrg      gc->thread_refcount++;
250848b8605Smrg      __glXSetCurrentContext(gc);
251848b8605Smrg   } else {
252848b8605Smrg      __glXSetCurrentContextNull();
253848b8605Smrg   }
254848b8605Smrg
255848b8605Smrg   if (oldGC->thread_refcount == 0 && oldGC != &dummyContext && oldGC->xid == None) {
256848b8605Smrg      /* We are switching away from a context that was
257848b8605Smrg       * previously destroyed, so we need to free the memory
258848b8605Smrg       * for the old handle. */
259848b8605Smrg      oldGC->vtable->destroy(oldGC);
260848b8605Smrg   }
261848b8605Smrg
262848b8605Smrg   __glXUnlock();
263848b8605Smrg
264b8e80941Smrg   /* The indirect vertex array state must to be initialised after we
265b8e80941Smrg    * have setup the context, as it needs to query server attributes.
266b8e80941Smrg    */
267b8e80941Smrg   if (gc && !gc->isDirect) {
268b8e80941Smrg      __GLXattribute *state = gc->client_state_private;
269b8e80941Smrg      if (state && state->array_state == NULL) {
270b8e80941Smrg         glGetString(GL_EXTENSIONS);
271b8e80941Smrg         glGetString(GL_VERSION);
272b8e80941Smrg         __glXInitVertexArrayState(gc);
273b8e80941Smrg      }
274b8e80941Smrg   }
275b8e80941Smrg
276848b8605Smrg   return GL_TRUE;
277848b8605Smrg}
278848b8605Smrg
279848b8605Smrg
280b8e80941Smrg_GLX_PUBLIC Bool
281848b8605SmrgglXMakeCurrent(Display * dpy, GLXDrawable draw, GLXContext gc)
282848b8605Smrg{
283848b8605Smrg   return MakeContextCurrent(dpy, draw, draw, gc);
284848b8605Smrg}
285848b8605Smrg
286b8e80941Smrg_GLX_PUBLIC
287848b8605SmrgGLX_ALIAS(Bool, glXMakeCurrentReadSGI,
288848b8605Smrg          (Display * dpy, GLXDrawable d, GLXDrawable r, GLXContext ctx),
289848b8605Smrg          (dpy, d, r, ctx), MakeContextCurrent)
290848b8605Smrg
291b8e80941Smrg_GLX_PUBLIC
292848b8605SmrgGLX_ALIAS(Bool, glXMakeContextCurrent,
293848b8605Smrg          (Display * dpy, GLXDrawable d, GLXDrawable r,
294848b8605Smrg           GLXContext ctx), (dpy, d, r, ctx), MakeContextCurrent)
295