glxcurrent.c revision 1463c08d
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#include <pthread.h>
37cdc920a0Smrg
38cdc920a0Smrg#include "glxclient.h"
393464ebd5Sriastradh#include "glapi.h"
4001e04c3fSmrg#include "glx_error.h"
413464ebd5Sriastradh
42e81a0f50Smaya/*
43e81a0f50Smaya * MASSIVE KLUDGE!
44e81a0f50Smaya * We need these to not be extern in libGL.so because of
45e81a0f50Smaya * PR toolchain/50277
46e81a0f50Smaya */
47e81a0f50Smaya#if defined(GLX_USE_TLS) && defined(__NetBSD__)
48e81a0f50Smaya_X_EXPORT __thread struct _glapi_table * _glapi_tls_Dispatch
49e81a0f50Smaya    __attribute__((tls_model("initial-exec"))) = NULL;
50e81a0f50Smaya_X_EXPORT __thread void * _glapi_tls_Context
51e81a0f50Smaya    __attribute__((tls_model("initial-exec")));
52e81a0f50Smaya#endif
53e81a0f50Smaya
54cdc920a0Smrg/*
55cdc920a0Smrg** We setup some dummy structures here so that the API can be used
56cdc920a0Smrg** even if no context is current.
57cdc920a0Smrg*/
58cdc920a0Smrg
59cdc920a0Smrgstatic GLubyte dummyBuffer[__GLX_BUFFER_LIMIT_SIZE];
603464ebd5Sriastradhstatic struct glx_context_vtable dummyVtable;
61cdc920a0Smrg/*
62cdc920a0Smrg** Dummy context used by small commands when there is no current context.
63cdc920a0Smrg** All the
64cdc920a0Smrg** gl and glx entry points are designed to operate as nop's when using
65cdc920a0Smrg** the dummy context structure.
66cdc920a0Smrg*/
673464ebd5Sriastradhstruct glx_context dummyContext = {
68cdc920a0Smrg   &dummyBuffer[0],
69cdc920a0Smrg   &dummyBuffer[0],
70cdc920a0Smrg   &dummyBuffer[0],
71cdc920a0Smrg   &dummyBuffer[__GLX_BUFFER_LIMIT_SIZE],
72cdc920a0Smrg   sizeof(dummyBuffer),
733464ebd5Sriastradh   &dummyVtable
74cdc920a0Smrg};
75cdc920a0Smrg
76cdc920a0Smrg/*
77cdc920a0Smrg * Current context management and locking
78cdc920a0Smrg */
79cdc920a0Smrg
80cdc920a0Smrg_X_HIDDEN pthread_mutex_t __glXmutex = PTHREAD_MUTEX_INITIALIZER;
81cdc920a0Smrg
821463c08dSmrg# if defined( USE_ELF_TLS )
83cdc920a0Smrg
84cdc920a0Smrg/**
85cdc920a0Smrg * Per-thread GLX context pointer.
86cdc920a0Smrg *
87cdc920a0Smrg * \c __glXSetCurrentContext is written is such a way that this pointer can
88cdc920a0Smrg * \b never be \c NULL.  This is important!  Because of this
89cdc920a0Smrg * \c __glXGetCurrentContext can be implemented as trivial macro.
90cdc920a0Smrg */
911463c08dSmrg__THREAD_INITIAL_EXEC void *__glX_tls_Context
92e81a0f50Smaya#if defined(__NetBSD__)
93e81a0f50Smaya   = NULL; /* non-zero initializers not supported with dlopen */
94e81a0f50Smaya#else
95cdc920a0Smrg   = &dummyContext;
96e81a0f50Smaya#endif
97cdc920a0Smrg
98cdc920a0Smrg_X_HIDDEN void
993464ebd5Sriastradh__glXSetCurrentContext(struct glx_context * c)
100cdc920a0Smrg{
101cdc920a0Smrg   __glX_tls_Context = (c != NULL) ? c : &dummyContext;
102cdc920a0Smrg}
103cdc920a0Smrg
104cdc920a0Smrg# else
105cdc920a0Smrg
106cdc920a0Smrgstatic pthread_once_t once_control = PTHREAD_ONCE_INIT;
107cdc920a0Smrg
108cdc920a0Smrg/**
109cdc920a0Smrg * Per-thread data key.
110cdc920a0Smrg *
111cdc920a0Smrg * Once \c init_thread_data has been called, the per-thread data key will
112cdc920a0Smrg * take a value of \c NULL.  As each new thread is created the default
113cdc920a0Smrg * value, in that thread, will be \c NULL.
114cdc920a0Smrg */
115cdc920a0Smrgstatic pthread_key_t ContextTSD;
116cdc920a0Smrg
117cdc920a0Smrg/**
118cdc920a0Smrg * Initialize the per-thread data key.
119cdc920a0Smrg *
120cdc920a0Smrg * This function is called \b exactly once per-process (not per-thread!) to
121cdc920a0Smrg * initialize the per-thread data key.  This is ideally done using the
122cdc920a0Smrg * \c pthread_once mechanism.
123cdc920a0Smrg */
124cdc920a0Smrgstatic void
125cdc920a0Smrginit_thread_data(void)
126cdc920a0Smrg{
127cdc920a0Smrg   if (pthread_key_create(&ContextTSD, NULL) != 0) {
128cdc920a0Smrg      perror("pthread_key_create");
129cdc920a0Smrg      exit(-1);
130cdc920a0Smrg   }
131cdc920a0Smrg}
132cdc920a0Smrg
133cdc920a0Smrg_X_HIDDEN void
1343464ebd5Sriastradh__glXSetCurrentContext(struct glx_context * c)
135cdc920a0Smrg{
136cdc920a0Smrg   pthread_once(&once_control, init_thread_data);
137cdc920a0Smrg   pthread_setspecific(ContextTSD, c);
138cdc920a0Smrg}
139cdc920a0Smrg
1403464ebd5Sriastradh_X_HIDDEN struct glx_context *
141cdc920a0Smrg__glXGetCurrentContext(void)
142cdc920a0Smrg{
143cdc920a0Smrg   void *v;
144cdc920a0Smrg
145cdc920a0Smrg   pthread_once(&once_control, init_thread_data);
146cdc920a0Smrg
147cdc920a0Smrg   v = pthread_getspecific(ContextTSD);
1483464ebd5Sriastradh   return (v == NULL) ? &dummyContext : (struct glx_context *) v;
149cdc920a0Smrg}
150cdc920a0Smrg
1511463c08dSmrg# endif /* defined( USE_ELF_TLS ) */
152cdc920a0Smrg
153cdc920a0Smrg
154cdc920a0Smrg_X_HIDDEN void
155cdc920a0Smrg__glXSetCurrentContextNull(void)
156cdc920a0Smrg{
157cdc920a0Smrg   __glXSetCurrentContext(&dummyContext);
1583464ebd5Sriastradh#if defined(GLX_DIRECT_RENDERING)
159cdc920a0Smrg   _glapi_set_dispatch(NULL);   /* no-op functions */
160cdc920a0Smrg   _glapi_set_context(NULL);
161cdc920a0Smrg#endif
162cdc920a0Smrg}
163cdc920a0Smrg
16401e04c3fSmrg_GLX_PUBLIC GLXContext
165cdc920a0SmrgglXGetCurrentContext(void)
166cdc920a0Smrg{
1673464ebd5Sriastradh   struct glx_context *cx = __glXGetCurrentContext();
168cdc920a0Smrg
169cdc920a0Smrg   if (cx == &dummyContext) {
170cdc920a0Smrg      return NULL;
171cdc920a0Smrg   }
172cdc920a0Smrg   else {
1733464ebd5Sriastradh      return (GLXContext) cx;
174cdc920a0Smrg   }
175cdc920a0Smrg}
176cdc920a0Smrg
17701e04c3fSmrg_GLX_PUBLIC GLXDrawable
178cdc920a0SmrgglXGetCurrentDrawable(void)
179cdc920a0Smrg{
1803464ebd5Sriastradh   struct glx_context *gc = __glXGetCurrentContext();
181cdc920a0Smrg   return gc->currentDrawable;
182cdc920a0Smrg}
183cdc920a0Smrg
184cdc920a0Smrg/**
185cdc920a0Smrg * Make a particular context current.
186cdc920a0Smrg *
187cdc920a0Smrg * \note This is in this file so that it can access dummyContext.
188cdc920a0Smrg */
189cdc920a0Smrgstatic Bool
190cdc920a0SmrgMakeContextCurrent(Display * dpy, GLXDrawable draw,
1911463c08dSmrg                   GLXDrawable read, GLXContext gc_user,
1921463c08dSmrg                   int opcode)
193cdc920a0Smrg{
1943464ebd5Sriastradh   struct glx_context *gc = (struct glx_context *) gc_user;
1953464ebd5Sriastradh   struct glx_context *oldGC = __glXGetCurrentContext();
1963464ebd5Sriastradh
197cdc920a0Smrg   /* Make sure that the new context has a nonzero ID.  In the request,
198cdc920a0Smrg    * a zero context ID is used only to mean that we bind to no current
199cdc920a0Smrg    * context.
200cdc920a0Smrg    */
201cdc920a0Smrg   if ((gc != NULL) && (gc->xid == None)) {
202cdc920a0Smrg      return GL_FALSE;
203cdc920a0Smrg   }
204cdc920a0Smrg
205cdc920a0Smrg   _glapi_check_multithread();
206cdc920a0Smrg
2073464ebd5Sriastradh   __glXLock();
2083464ebd5Sriastradh   if (oldGC == gc &&
2093464ebd5Sriastradh       gc->currentDrawable == draw && gc->currentReadable == read) {
2103464ebd5Sriastradh      __glXUnlock();
2113464ebd5Sriastradh      return True;
212cdc920a0Smrg   }
213cdc920a0Smrg
21401e04c3fSmrg   /* can't have only one be 0 */
21501e04c3fSmrg   if (!!draw != !!read) {
21601e04c3fSmrg      __glXUnlock();
2171463c08dSmrg      __glXSendError(dpy, BadMatch, None, opcode, True);
21801e04c3fSmrg      return False;
21901e04c3fSmrg   }
22001e04c3fSmrg
2213464ebd5Sriastradh   if (oldGC != &dummyContext) {
2223464ebd5Sriastradh      if (--oldGC->thread_refcount == 0) {
2233464ebd5Sriastradh	 oldGC->vtable->unbind(oldGC, gc);
2243464ebd5Sriastradh	 oldGC->currentDpy = 0;
225cdc920a0Smrg      }
226cdc920a0Smrg   }
227cdc920a0Smrg
2283464ebd5Sriastradh   if (gc) {
2293464ebd5Sriastradh      /* Attempt to bind the context.  We do this before mucking with
2303464ebd5Sriastradh       * gc and __glXSetCurrentContext to properly handle our state in
2313464ebd5Sriastradh       * case of an error.
2323464ebd5Sriastradh       *
2333464ebd5Sriastradh       * If an error occurs, set the Null context since we've already
2343464ebd5Sriastradh       * blown away our old context.  The caller is responsible for
2353464ebd5Sriastradh       * figuring out how to handle setting a valid context.
236cdc920a0Smrg       */
2373464ebd5Sriastradh      if (gc->vtable->bind(gc, oldGC, draw, read) != Success) {
2383464ebd5Sriastradh         __glXSetCurrentContextNull();
2393464ebd5Sriastradh         __glXUnlock();
2401463c08dSmrg         __glXSendError(dpy, GLXBadContext, None, opcode, False);
2413464ebd5Sriastradh         return GL_FALSE;
242cdc920a0Smrg      }
243cdc920a0Smrg
2443464ebd5Sriastradh      if (gc->thread_refcount == 0) {
245cdc920a0Smrg         gc->currentDpy = dpy;
246cdc920a0Smrg         gc->currentDrawable = draw;
247cdc920a0Smrg         gc->currentReadable = read;
248cdc920a0Smrg      }
2493464ebd5Sriastradh      gc->thread_refcount++;
2503464ebd5Sriastradh      __glXSetCurrentContext(gc);
2513464ebd5Sriastradh   } else {
2523464ebd5Sriastradh      __glXSetCurrentContextNull();
2533464ebd5Sriastradh   }
2543464ebd5Sriastradh
2553464ebd5Sriastradh   if (oldGC->thread_refcount == 0 && oldGC != &dummyContext && oldGC->xid == None) {
2563464ebd5Sriastradh      /* We are switching away from a context that was
2573464ebd5Sriastradh       * previously destroyed, so we need to free the memory
2583464ebd5Sriastradh       * for the old handle. */
2593464ebd5Sriastradh      oldGC->vtable->destroy(oldGC);
260cdc920a0Smrg   }
2613464ebd5Sriastradh
262cdc920a0Smrg   __glXUnlock();
2633464ebd5Sriastradh
264cdc920a0Smrg   return GL_TRUE;
265cdc920a0Smrg}
266cdc920a0Smrg
26701e04c3fSmrg_GLX_PUBLIC Bool
268cdc920a0SmrgglXMakeCurrent(Display * dpy, GLXDrawable draw, GLXContext gc)
269cdc920a0Smrg{
2701463c08dSmrg   return MakeContextCurrent(dpy, draw, draw, gc, X_GLXMakeCurrent);
271cdc920a0Smrg}
272cdc920a0Smrg
2731463c08dSmrg_GLX_PUBLIC Bool
2741463c08dSmrgglXMakeContextCurrent(Display *dpy, GLXDrawable d, GLXDrawable r,
2751463c08dSmrg                      GLXContext ctx)
2761463c08dSmrg{
2771463c08dSmrg   return MakeContextCurrent(dpy, d, r, ctx, X_GLXMakeContextCurrent);
2781463c08dSmrg}
279cdc920a0Smrg
2801463c08dSmrg_GLX_PUBLIC Bool
2811463c08dSmrgglXMakeCurrentReadSGI(Display *dpy, GLXDrawable d, GLXDrawable r,
2821463c08dSmrg                      GLXContext ctx)
2831463c08dSmrg{
2841463c08dSmrg   return MakeContextCurrent(dpy, d, r, ctx, X_GLXvop_MakeCurrentReadSGI);
2851463c08dSmrg}
286