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
42848b8605Smrg/*
43848b8605Smrg** We setup some dummy structures here so that the API can be used
44848b8605Smrg** even if no context is current.
45848b8605Smrg*/
46848b8605Smrg
47848b8605Smrgstatic GLubyte dummyBuffer[__GLX_BUFFER_LIMIT_SIZE];
48848b8605Smrgstatic struct glx_context_vtable dummyVtable;
49848b8605Smrg/*
50848b8605Smrg** Dummy context used by small commands when there is no current context.
51848b8605Smrg** All the
52848b8605Smrg** gl and glx entry points are designed to operate as nop's when using
53848b8605Smrg** the dummy context structure.
54848b8605Smrg*/
55848b8605Smrgstruct glx_context dummyContext = {
56848b8605Smrg   &dummyBuffer[0],
57848b8605Smrg   &dummyBuffer[0],
58848b8605Smrg   &dummyBuffer[0],
59848b8605Smrg   &dummyBuffer[__GLX_BUFFER_LIMIT_SIZE],
60848b8605Smrg   sizeof(dummyBuffer),
61848b8605Smrg   &dummyVtable
62848b8605Smrg};
63848b8605Smrg
64848b8605Smrg/*
65848b8605Smrg * Current context management and locking
66848b8605Smrg */
67848b8605Smrg
68848b8605Smrg_X_HIDDEN pthread_mutex_t __glXmutex = PTHREAD_MUTEX_INITIALIZER;
69848b8605Smrg
70848b8605Smrg# if defined( GLX_USE_TLS )
71848b8605Smrg
72848b8605Smrg/**
73848b8605Smrg * Per-thread GLX context pointer.
74848b8605Smrg *
75848b8605Smrg * \c __glXSetCurrentContext is written is such a way that this pointer can
76848b8605Smrg * \b never be \c NULL.  This is important!  Because of this
77848b8605Smrg * \c __glXGetCurrentContext can be implemented as trivial macro.
78848b8605Smrg */
79848b8605Smrg__thread void *__glX_tls_Context __attribute__ ((tls_model("initial-exec")))
80b8e80941Smrg#if defined(__NetBSD__)
81b8e80941Smrg   = NULL; /* non-zero initializers not supported with dlopen */
82b8e80941Smrg#else
83848b8605Smrg   = &dummyContext;
84b8e80941Smrg#endif
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
142848b8605Smrg_X_HIDDEN void
143848b8605Smrg__glXSetCurrentContextNull(void)
144848b8605Smrg{
145848b8605Smrg   __glXSetCurrentContext(&dummyContext);
146848b8605Smrg#if defined(GLX_DIRECT_RENDERING)
147848b8605Smrg   _glapi_set_dispatch(NULL);   /* no-op functions */
148848b8605Smrg   _glapi_set_context(NULL);
149848b8605Smrg#endif
150848b8605Smrg}
151848b8605Smrg
152b8e80941Smrg_GLX_PUBLIC GLXContext
153848b8605SmrgglXGetCurrentContext(void)
154848b8605Smrg{
155848b8605Smrg   struct glx_context *cx = __glXGetCurrentContext();
156848b8605Smrg
157848b8605Smrg   if (cx == &dummyContext) {
158848b8605Smrg      return NULL;
159848b8605Smrg   }
160848b8605Smrg   else {
161848b8605Smrg      return (GLXContext) cx;
162848b8605Smrg   }
163848b8605Smrg}
164848b8605Smrg
165b8e80941Smrg_GLX_PUBLIC GLXDrawable
166848b8605SmrgglXGetCurrentDrawable(void)
167848b8605Smrg{
168848b8605Smrg   struct glx_context *gc = __glXGetCurrentContext();
169848b8605Smrg   return gc->currentDrawable;
170848b8605Smrg}
171848b8605Smrg
172848b8605Smrg/**
173848b8605Smrg * Make a particular context current.
174848b8605Smrg *
175848b8605Smrg * \note This is in this file so that it can access dummyContext.
176848b8605Smrg */
177848b8605Smrgstatic Bool
178848b8605SmrgMakeContextCurrent(Display * dpy, GLXDrawable draw,
179848b8605Smrg                   GLXDrawable read, GLXContext gc_user)
180848b8605Smrg{
181848b8605Smrg   struct glx_context *gc = (struct glx_context *) gc_user;
182848b8605Smrg   struct glx_context *oldGC = __glXGetCurrentContext();
183848b8605Smrg
184848b8605Smrg   /* Make sure that the new context has a nonzero ID.  In the request,
185848b8605Smrg    * a zero context ID is used only to mean that we bind to no current
186848b8605Smrg    * context.
187848b8605Smrg    */
188848b8605Smrg   if ((gc != NULL) && (gc->xid == None)) {
189848b8605Smrg      return GL_FALSE;
190848b8605Smrg   }
191848b8605Smrg
192848b8605Smrg   _glapi_check_multithread();
193848b8605Smrg
194848b8605Smrg   __glXLock();
195848b8605Smrg   if (oldGC == gc &&
196848b8605Smrg       gc->currentDrawable == draw && gc->currentReadable == read) {
197848b8605Smrg      __glXUnlock();
198848b8605Smrg      return True;
199848b8605Smrg   }
200848b8605Smrg
201b8e80941Smrg   /* can't have only one be 0 */
202b8e80941Smrg   if (!!draw != !!read) {
203b8e80941Smrg      __glXUnlock();
204b8e80941Smrg      __glXSendError(dpy, BadMatch, None, X_GLXMakeContextCurrent, True);
205b8e80941Smrg      return False;
206b8e80941Smrg   }
207b8e80941Smrg
208848b8605Smrg   if (oldGC != &dummyContext) {
209848b8605Smrg      if (--oldGC->thread_refcount == 0) {
210848b8605Smrg	 oldGC->vtable->unbind(oldGC, gc);
211848b8605Smrg	 oldGC->currentDpy = 0;
212848b8605Smrg      }
213848b8605Smrg   }
214848b8605Smrg
215848b8605Smrg   if (gc) {
216848b8605Smrg      /* Attempt to bind the context.  We do this before mucking with
217848b8605Smrg       * gc and __glXSetCurrentContext to properly handle our state in
218848b8605Smrg       * case of an error.
219848b8605Smrg       *
220848b8605Smrg       * If an error occurs, set the Null context since we've already
221848b8605Smrg       * blown away our old context.  The caller is responsible for
222848b8605Smrg       * figuring out how to handle setting a valid context.
223848b8605Smrg       */
224848b8605Smrg      if (gc->vtable->bind(gc, oldGC, draw, read) != Success) {
225848b8605Smrg         __glXSetCurrentContextNull();
226848b8605Smrg         __glXUnlock();
227b8e80941Smrg         __glXSendError(dpy, GLXBadContext, None, X_GLXMakeContextCurrent,
228b8e80941Smrg                        False);
229848b8605Smrg         return GL_FALSE;
230848b8605Smrg      }
231848b8605Smrg
232848b8605Smrg      if (gc->thread_refcount == 0) {
233848b8605Smrg         gc->currentDpy = dpy;
234848b8605Smrg         gc->currentDrawable = draw;
235848b8605Smrg         gc->currentReadable = read;
236848b8605Smrg      }
237848b8605Smrg      gc->thread_refcount++;
238848b8605Smrg      __glXSetCurrentContext(gc);
239848b8605Smrg   } else {
240848b8605Smrg      __glXSetCurrentContextNull();
241848b8605Smrg   }
242848b8605Smrg
243848b8605Smrg   if (oldGC->thread_refcount == 0 && oldGC != &dummyContext && oldGC->xid == None) {
244848b8605Smrg      /* We are switching away from a context that was
245848b8605Smrg       * previously destroyed, so we need to free the memory
246848b8605Smrg       * for the old handle. */
247848b8605Smrg      oldGC->vtable->destroy(oldGC);
248848b8605Smrg   }
249848b8605Smrg
250848b8605Smrg   __glXUnlock();
251848b8605Smrg
252b8e80941Smrg   /* The indirect vertex array state must to be initialised after we
253b8e80941Smrg    * have setup the context, as it needs to query server attributes.
254b8e80941Smrg    */
255b8e80941Smrg   if (gc && !gc->isDirect) {
256b8e80941Smrg      __GLXattribute *state = gc->client_state_private;
257b8e80941Smrg      if (state && state->array_state == NULL) {
258b8e80941Smrg         glGetString(GL_EXTENSIONS);
259b8e80941Smrg         glGetString(GL_VERSION);
260b8e80941Smrg         __glXInitVertexArrayState(gc);
261b8e80941Smrg      }
262b8e80941Smrg   }
263b8e80941Smrg
264848b8605Smrg   return GL_TRUE;
265848b8605Smrg}
266848b8605Smrg
267848b8605Smrg
268b8e80941Smrg_GLX_PUBLIC Bool
269848b8605SmrgglXMakeCurrent(Display * dpy, GLXDrawable draw, GLXContext gc)
270848b8605Smrg{
271848b8605Smrg   return MakeContextCurrent(dpy, draw, draw, gc);
272848b8605Smrg}
273848b8605Smrg
274b8e80941Smrg_GLX_PUBLIC
275848b8605SmrgGLX_ALIAS(Bool, glXMakeCurrentReadSGI,
276848b8605Smrg          (Display * dpy, GLXDrawable d, GLXDrawable r, GLXContext ctx),
277848b8605Smrg          (dpy, d, r, ctx), MakeContextCurrent)
278848b8605Smrg
279b8e80941Smrg_GLX_PUBLIC
280848b8605SmrgGLX_ALIAS(Bool, glXMakeContextCurrent,
281848b8605Smrg          (Display * dpy, GLXDrawable d, GLXDrawable r,
282848b8605Smrg           GLXContext ctx), (dpy, d, r, ctx), MakeContextCurrent)
283