1 /*
2 * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
3 * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
4 *
5 * SPDX-License-Identifier: SGI-B-2.0
6 */
7
8 /**
9 * \file glxcurrent.c
10 * Client-side GLX interface for current context management.
11 */
12
13 #include <pthread.h>
14
15 #include "glxclient.h"
16 #include "glapi.h"
17 #include "glx_error.h"
18
19 /*
20 ** We setup some dummy structures here so that the API can be used
21 ** even if no context is current.
22 */
23
24 static GLubyte dummyBuffer[__GLX_BUFFER_LIMIT_SIZE];
25 static struct glx_context_vtable dummyVtable;
26 /*
27 ** Dummy context used by small commands when there is no current context.
28 ** All the
29 ** gl and glx entry points are designed to operate as nop's when using
30 ** the dummy context structure.
31 */
32 struct glx_context dummyContext = {
33 &dummyBuffer[0],
34 &dummyBuffer[0],
35 &dummyBuffer[0],
36 &dummyBuffer[__GLX_BUFFER_LIMIT_SIZE],
37 sizeof(dummyBuffer),
38 &dummyVtable
39 };
40
41 /*
42 * Current context management and locking
43 */
44
45 _X_HIDDEN pthread_mutex_t __glXmutex = PTHREAD_MUTEX_INITIALIZER;
46
47 /**
48 * Per-thread GLX context pointer.
49 *
50 * \c __glXSetCurrentContext is written is such a way that this pointer can
51 * \b never be \c NULL. This is important! Because of this
52 * \c __glXGetCurrentContext can be implemented as trivial macro.
53 */
54 __THREAD_INITIAL_EXEC void *__glX_tls_Context = &dummyContext;
55
56 _X_HIDDEN void
__glXSetCurrentContext(struct glx_context * c)57 __glXSetCurrentContext(struct glx_context * c)
58 {
59 __glX_tls_Context = (c != NULL) ? c : &dummyContext;
60 }
61
62 _X_HIDDEN void
__glXSetCurrentContextNull(void)63 __glXSetCurrentContextNull(void)
64 {
65 __glXSetCurrentContext(&dummyContext);
66 #if defined(GLX_DIRECT_RENDERING)
67 _glapi_set_dispatch(NULL); /* no-op functions */
68 _glapi_set_context(NULL);
69 #endif
70 }
71
72 _GLX_PUBLIC GLXContext
glXGetCurrentContext(void)73 glXGetCurrentContext(void)
74 {
75 struct glx_context *cx = __glXGetCurrentContext();
76
77 if (cx == &dummyContext) {
78 return NULL;
79 }
80 else {
81 return (GLXContext) cx;
82 }
83 }
84
85 _GLX_PUBLIC GLXDrawable
glXGetCurrentDrawable(void)86 glXGetCurrentDrawable(void)
87 {
88 struct glx_context *gc = __glXGetCurrentContext();
89 return gc->currentDrawable;
90 }
91
92 /**
93 * Make a particular context current.
94 *
95 * \note This is in this file so that it can access dummyContext.
96 */
97 static Bool
MakeContextCurrent(Display * dpy,GLXDrawable draw,GLXDrawable read,GLXContext gc_user,int opcode)98 MakeContextCurrent(Display * dpy, GLXDrawable draw,
99 GLXDrawable read, GLXContext gc_user,
100 int opcode)
101 {
102 struct glx_context *gc = (struct glx_context *) gc_user;
103 struct glx_context *oldGC = __glXGetCurrentContext();
104 int ret = GL_TRUE;
105
106 /* Make sure that the new context has a nonzero ID. In the request,
107 * a zero context ID is used only to mean that we bind to no current
108 * context.
109 */
110 if ((gc != NULL) && (gc->xid == None)) {
111 return GL_FALSE;
112 }
113
114 /* can't have only one be 0 */
115 if (!!draw != !!read) {
116 __glXSendError(dpy, BadMatch, None, opcode, True);
117 return False;
118 }
119
120 if (oldGC == gc &&
121 gc->currentDrawable == draw && gc->currentReadable == read)
122 return True;
123
124 __glXLock();
125
126 if (oldGC != &dummyContext) {
127 oldGC->vtable->unbind(oldGC);
128 oldGC->currentDpy = NULL;
129
130 if (oldGC->xid == None) {
131 /* We are switching away from a context that was
132 * previously destroyed, so we need to free the memory
133 * for the old handle. */
134 oldGC->vtable->destroy(oldGC);
135 }
136 }
137
138 __glXSetCurrentContextNull();
139
140 if (gc) {
141 /* GLX spec 3.3: If ctx is current to some other thread, then
142 * glXMakeContextCurrent will generate a BadAccess error
143 */
144 if (gc->currentDpy)
145 {
146 __glXUnlock();
147 __glXSendError(dpy, BadAccess, None, opcode, True);
148 return False;
149 }
150 /* Attempt to bind the context. We do this before mucking with
151 * gc and __glXSetCurrentContext to properly handle our state in
152 * case of an error.
153 *
154 * If an error occurs, set the Null context since we've already
155 * blown away our old context. The caller is responsible for
156 * figuring out how to handle setting a valid context.
157 */
158 if (gc->vtable->bind(gc, draw, read) != Success) {
159 ret = GL_FALSE;
160 } else {
161 gc->currentDpy = dpy;
162 gc->currentDrawable = draw;
163 gc->currentReadable = read;
164 __glXSetCurrentContext(gc);
165 }
166 }
167
168 __glXUnlock();
169
170 if (!ret)
171 __glXSendError(dpy, GLXBadContext, None, opcode, False);
172
173 return ret;
174 }
175
176 _GLX_PUBLIC Bool
glXMakeCurrent(Display * dpy,GLXDrawable draw,GLXContext gc)177 glXMakeCurrent(Display * dpy, GLXDrawable draw, GLXContext gc)
178 {
179 return MakeContextCurrent(dpy, draw, draw, gc, X_GLXMakeCurrent);
180 }
181
182 _GLX_PUBLIC Bool
glXMakeContextCurrent(Display * dpy,GLXDrawable d,GLXDrawable r,GLXContext ctx)183 glXMakeContextCurrent(Display *dpy, GLXDrawable d, GLXDrawable r,
184 GLXContext ctx)
185 {
186 return MakeContextCurrent(dpy, d, r, ctx, X_GLXMakeContextCurrent);
187 }
188
189 _GLX_PUBLIC Bool
glXMakeCurrentReadSGI(Display * dpy,GLXDrawable d,GLXDrawable r,GLXContext ctx)190 glXMakeCurrentReadSGI(Display *dpy, GLXDrawable d, GLXDrawable r,
191 GLXContext ctx)
192 {
193 return MakeContextCurrent(dpy, d, r, ctx, X_GLXvop_MakeCurrentReadSGI);
194 }
195