glxcurrent.c revision 848b8605
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#ifdef HAVE_PTHREAD
37848b8605Smrg#include <pthread.h>
38848b8605Smrg#endif
39848b8605Smrg
40848b8605Smrg#include "glxclient.h"
41848b8605Smrg
42848b8605Smrg#include "glapi.h"
43848b8605Smrg
44848b8605Smrg/*
45848b8605Smrg** We setup some dummy structures here so that the API can be used
46848b8605Smrg** even if no context is current.
47848b8605Smrg*/
48848b8605Smrg
49848b8605Smrgstatic GLubyte dummyBuffer[__GLX_BUFFER_LIMIT_SIZE];
50848b8605Smrgstatic struct glx_context_vtable dummyVtable;
51848b8605Smrg/*
52848b8605Smrg** Dummy context used by small commands when there is no current context.
53848b8605Smrg** All the
54848b8605Smrg** gl and glx entry points are designed to operate as nop's when using
55848b8605Smrg** the dummy context structure.
56848b8605Smrg*/
57848b8605Smrgstruct glx_context dummyContext = {
58848b8605Smrg   &dummyBuffer[0],
59848b8605Smrg   &dummyBuffer[0],
60848b8605Smrg   &dummyBuffer[0],
61848b8605Smrg   &dummyBuffer[__GLX_BUFFER_LIMIT_SIZE],
62848b8605Smrg   sizeof(dummyBuffer),
63848b8605Smrg   &dummyVtable
64848b8605Smrg};
65848b8605Smrg
66848b8605Smrg/*
67848b8605Smrg * Current context management and locking
68848b8605Smrg */
69848b8605Smrg
70848b8605Smrg#if defined( HAVE_PTHREAD )
71848b8605Smrg
72848b8605Smrg_X_HIDDEN pthread_mutex_t __glXmutex = PTHREAD_MUTEX_INITIALIZER;
73848b8605Smrg
74848b8605Smrg# if defined( GLX_USE_TLS )
75848b8605Smrg
76848b8605Smrg/**
77848b8605Smrg * Per-thread GLX context pointer.
78848b8605Smrg *
79848b8605Smrg * \c __glXSetCurrentContext is written is such a way that this pointer can
80848b8605Smrg * \b never be \c NULL.  This is important!  Because of this
81848b8605Smrg * \c __glXGetCurrentContext can be implemented as trivial macro.
82848b8605Smrg */
83848b8605Smrg__thread void *__glX_tls_Context __attribute__ ((tls_model("initial-exec")))
84848b8605Smrg   = &dummyContext;
85848b8605Smrg
86848b8605Smrg_X_HIDDEN void
87848b8605Smrg__glXSetCurrentContext(struct glx_context * c)
88848b8605Smrg{
89848b8605Smrg   __glX_tls_Context = (c != NULL) ? c : &dummyContext;
90848b8605Smrg}
91848b8605Smrg
92848b8605Smrg# else
93848b8605Smrg
94848b8605Smrgstatic pthread_once_t once_control = PTHREAD_ONCE_INIT;
95848b8605Smrg
96848b8605Smrg/**
97848b8605Smrg * Per-thread data key.
98848b8605Smrg *
99848b8605Smrg * Once \c init_thread_data has been called, the per-thread data key will
100848b8605Smrg * take a value of \c NULL.  As each new thread is created the default
101848b8605Smrg * value, in that thread, will be \c NULL.
102848b8605Smrg */
103848b8605Smrgstatic pthread_key_t ContextTSD;
104848b8605Smrg
105848b8605Smrg/**
106848b8605Smrg * Initialize the per-thread data key.
107848b8605Smrg *
108848b8605Smrg * This function is called \b exactly once per-process (not per-thread!) to
109848b8605Smrg * initialize the per-thread data key.  This is ideally done using the
110848b8605Smrg * \c pthread_once mechanism.
111848b8605Smrg */
112848b8605Smrgstatic void
113848b8605Smrginit_thread_data(void)
114848b8605Smrg{
115848b8605Smrg   if (pthread_key_create(&ContextTSD, NULL) != 0) {
116848b8605Smrg      perror("pthread_key_create");
117848b8605Smrg      exit(-1);
118848b8605Smrg   }
119848b8605Smrg}
120848b8605Smrg
121848b8605Smrg_X_HIDDEN void
122848b8605Smrg__glXSetCurrentContext(struct glx_context * c)
123848b8605Smrg{
124848b8605Smrg   pthread_once(&once_control, init_thread_data);
125848b8605Smrg   pthread_setspecific(ContextTSD, c);
126848b8605Smrg}
127848b8605Smrg
128848b8605Smrg_X_HIDDEN struct glx_context *
129848b8605Smrg__glXGetCurrentContext(void)
130848b8605Smrg{
131848b8605Smrg   void *v;
132848b8605Smrg
133848b8605Smrg   pthread_once(&once_control, init_thread_data);
134848b8605Smrg
135848b8605Smrg   v = pthread_getspecific(ContextTSD);
136848b8605Smrg   return (v == NULL) ? &dummyContext : (struct glx_context *) v;
137848b8605Smrg}
138848b8605Smrg
139848b8605Smrg# endif /* defined( GLX_USE_TLS ) */
140848b8605Smrg
141848b8605Smrg#elif defined( THREADS )
142848b8605Smrg
143848b8605Smrg#error Unknown threading method specified.
144848b8605Smrg
145848b8605Smrg#else
146848b8605Smrg
147848b8605Smrg/* not thread safe */
148848b8605Smrg_X_HIDDEN struct glx_context *__glXcurrentContext = &dummyContext;
149848b8605Smrg
150848b8605Smrg#endif
151848b8605Smrg
152848b8605Smrg
153848b8605Smrg_X_HIDDEN void
154848b8605Smrg__glXSetCurrentContextNull(void)
155848b8605Smrg{
156848b8605Smrg   __glXSetCurrentContext(&dummyContext);
157848b8605Smrg#if defined(GLX_DIRECT_RENDERING)
158848b8605Smrg   _glapi_set_dispatch(NULL);   /* no-op functions */
159848b8605Smrg   _glapi_set_context(NULL);
160848b8605Smrg#endif
161848b8605Smrg}
162848b8605Smrg
163848b8605Smrg_X_EXPORT GLXContext
164848b8605SmrgglXGetCurrentContext(void)
165848b8605Smrg{
166848b8605Smrg   struct glx_context *cx = __glXGetCurrentContext();
167848b8605Smrg
168848b8605Smrg   if (cx == &dummyContext) {
169848b8605Smrg      return NULL;
170848b8605Smrg   }
171848b8605Smrg   else {
172848b8605Smrg      return (GLXContext) cx;
173848b8605Smrg   }
174848b8605Smrg}
175848b8605Smrg
176848b8605Smrg_X_EXPORT GLXDrawable
177848b8605SmrgglXGetCurrentDrawable(void)
178848b8605Smrg{
179848b8605Smrg   struct glx_context *gc = __glXGetCurrentContext();
180848b8605Smrg   return gc->currentDrawable;
181848b8605Smrg}
182848b8605Smrg
183848b8605Smrgstatic void
184848b8605Smrg__glXGenerateError(Display * dpy, XID resource,
185848b8605Smrg                   BYTE errorCode, CARD16 minorCode)
186848b8605Smrg{
187848b8605Smrg   xError error;
188848b8605Smrg
189848b8605Smrg   error.errorCode = errorCode;
190848b8605Smrg   error.resourceID = resource;
191848b8605Smrg   error.sequenceNumber = dpy->request;
192848b8605Smrg   error.type = X_Error;
193848b8605Smrg   error.majorCode = __glXSetupForCommand(dpy);
194848b8605Smrg   error.minorCode = minorCode;
195848b8605Smrg   _XError(dpy, &error);
196848b8605Smrg}
197848b8605Smrg
198848b8605Smrg/**
199848b8605Smrg * Make a particular context current.
200848b8605Smrg *
201848b8605Smrg * \note This is in this file so that it can access dummyContext.
202848b8605Smrg */
203848b8605Smrgstatic Bool
204848b8605SmrgMakeContextCurrent(Display * dpy, GLXDrawable draw,
205848b8605Smrg                   GLXDrawable read, GLXContext gc_user)
206848b8605Smrg{
207848b8605Smrg   struct glx_context *gc = (struct glx_context *) gc_user;
208848b8605Smrg   struct glx_context *oldGC = __glXGetCurrentContext();
209848b8605Smrg
210848b8605Smrg   /* Make sure that the new context has a nonzero ID.  In the request,
211848b8605Smrg    * a zero context ID is used only to mean that we bind to no current
212848b8605Smrg    * context.
213848b8605Smrg    */
214848b8605Smrg   if ((gc != NULL) && (gc->xid == None)) {
215848b8605Smrg      return GL_FALSE;
216848b8605Smrg   }
217848b8605Smrg
218848b8605Smrg   _glapi_check_multithread();
219848b8605Smrg
220848b8605Smrg   __glXLock();
221848b8605Smrg   if (oldGC == gc &&
222848b8605Smrg       gc->currentDrawable == draw && gc->currentReadable == read) {
223848b8605Smrg      __glXUnlock();
224848b8605Smrg      return True;
225848b8605Smrg   }
226848b8605Smrg
227848b8605Smrg   if (oldGC != &dummyContext) {
228848b8605Smrg      if (--oldGC->thread_refcount == 0) {
229848b8605Smrg	 oldGC->vtable->unbind(oldGC, gc);
230848b8605Smrg	 oldGC->currentDpy = 0;
231848b8605Smrg      }
232848b8605Smrg   }
233848b8605Smrg
234848b8605Smrg   if (gc) {
235848b8605Smrg      /* Attempt to bind the context.  We do this before mucking with
236848b8605Smrg       * gc and __glXSetCurrentContext to properly handle our state in
237848b8605Smrg       * case of an error.
238848b8605Smrg       *
239848b8605Smrg       * If an error occurs, set the Null context since we've already
240848b8605Smrg       * blown away our old context.  The caller is responsible for
241848b8605Smrg       * figuring out how to handle setting a valid context.
242848b8605Smrg       */
243848b8605Smrg      if (gc->vtable->bind(gc, oldGC, draw, read) != Success) {
244848b8605Smrg         __glXSetCurrentContextNull();
245848b8605Smrg         __glXUnlock();
246848b8605Smrg         __glXGenerateError(dpy, None, GLXBadContext, X_GLXMakeContextCurrent);
247848b8605Smrg         return GL_FALSE;
248848b8605Smrg      }
249848b8605Smrg
250848b8605Smrg      if (gc->thread_refcount == 0) {
251848b8605Smrg         gc->currentDpy = dpy;
252848b8605Smrg         gc->currentDrawable = draw;
253848b8605Smrg         gc->currentReadable = read;
254848b8605Smrg      }
255848b8605Smrg      gc->thread_refcount++;
256848b8605Smrg      __glXSetCurrentContext(gc);
257848b8605Smrg   } else {
258848b8605Smrg      __glXSetCurrentContextNull();
259848b8605Smrg   }
260848b8605Smrg
261848b8605Smrg   if (oldGC->thread_refcount == 0 && oldGC != &dummyContext && oldGC->xid == None) {
262848b8605Smrg      /* We are switching away from a context that was
263848b8605Smrg       * previously destroyed, so we need to free the memory
264848b8605Smrg       * for the old handle. */
265848b8605Smrg      oldGC->vtable->destroy(oldGC);
266848b8605Smrg   }
267848b8605Smrg
268848b8605Smrg   __glXUnlock();
269848b8605Smrg
270848b8605Smrg   return GL_TRUE;
271848b8605Smrg}
272848b8605Smrg
273848b8605Smrg
274848b8605Smrg_X_EXPORT Bool
275848b8605SmrgglXMakeCurrent(Display * dpy, GLXDrawable draw, GLXContext gc)
276848b8605Smrg{
277848b8605Smrg   return MakeContextCurrent(dpy, draw, draw, gc);
278848b8605Smrg}
279848b8605Smrg
280848b8605Smrg_X_EXPORT
281848b8605SmrgGLX_ALIAS(Bool, glXMakeCurrentReadSGI,
282848b8605Smrg          (Display * dpy, GLXDrawable d, GLXDrawable r, GLXContext ctx),
283848b8605Smrg          (dpy, d, r, ctx), MakeContextCurrent)
284848b8605Smrg
285848b8605Smrg_X_EXPORT
286848b8605SmrgGLX_ALIAS(Bool, glXMakeContextCurrent,
287848b8605Smrg          (Display * dpy, GLXDrawable d, GLXDrawable r,
288848b8605Smrg           GLXContext ctx), (dpy, d, r, ctx), MakeContextCurrent)
289