xref: /aosp_15_r20/external/mesa3d/src/glx/glxcurrent.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
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