egl_dri2: Fix initialization with EGL_DEFAULT_DISPLAY
[mesa.git] / src / glx / x11 / glxcurrent.c
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 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice including the dates of first publication and
13 * either this permission notice or a reference to
14 * http://oss.sgi.com/projects/FreeB/
15 * shall be included in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
22 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 * SOFTWARE.
24 *
25 * Except as contained in this notice, the name of Silicon Graphics, Inc.
26 * shall not be used in advertising or otherwise to promote the sale, use or
27 * other dealings in this Software without prior written authorization from
28 * Silicon Graphics, Inc.
29 */
30
31 /**
32 * \file glxcurrent.c
33 * Client-side GLX interface for current context management.
34 */
35
36 #include "glxclient.h"
37 #include "glapi.h"
38 #include "indirect_init.h"
39
40 /*
41 ** We setup some dummy structures here so that the API can be used
42 ** even if no context is current.
43 */
44
45 static GLubyte dummyBuffer[__GLX_BUFFER_LIMIT_SIZE];
46
47 /*
48 ** Dummy context used by small commands when there is no current context.
49 ** All the
50 ** gl and glx entry points are designed to operate as nop's when using
51 ** the dummy context structure.
52 */
53 static __GLXcontext dummyContext = {
54 &dummyBuffer[0],
55 &dummyBuffer[0],
56 &dummyBuffer[0],
57 &dummyBuffer[__GLX_BUFFER_LIMIT_SIZE],
58 sizeof(dummyBuffer),
59 };
60
61
62 /*
63 ** All indirect rendering contexts will share the same indirect dispatch table.
64 */
65 static __GLapi *IndirectAPI = NULL;
66
67
68 /*
69 * Current context management and locking
70 */
71
72 #if defined( PTHREADS )
73
74 _X_HIDDEN pthread_mutex_t __glXmutex = PTHREAD_MUTEX_INITIALIZER;
75
76 # if defined( GLX_USE_TLS )
77
78 /**
79 * Per-thread GLX context pointer.
80 *
81 * \c __glXSetCurrentContext is written is such a way that this pointer can
82 * \b never be \c NULL. This is important! Because of this
83 * \c __glXGetCurrentContext can be implemented as trivial macro.
84 */
85 __thread void *__glX_tls_Context __attribute__ ((tls_model("initial-exec")))
86 = &dummyContext;
87
88 _X_HIDDEN void
89 __glXSetCurrentContext(__GLXcontext * c)
90 {
91 __glX_tls_Context = (c != NULL) ? c : &dummyContext;
92 }
93
94 # else
95
96 static pthread_once_t once_control = PTHREAD_ONCE_INIT;
97
98 /**
99 * Per-thread data key.
100 *
101 * Once \c init_thread_data has been called, the per-thread data key will
102 * take a value of \c NULL. As each new thread is created the default
103 * value, in that thread, will be \c NULL.
104 */
105 static pthread_key_t ContextTSD;
106
107 /**
108 * Initialize the per-thread data key.
109 *
110 * This function is called \b exactly once per-process (not per-thread!) to
111 * initialize the per-thread data key. This is ideally done using the
112 * \c pthread_once mechanism.
113 */
114 static void
115 init_thread_data(void)
116 {
117 if (pthread_key_create(&ContextTSD, NULL) != 0) {
118 perror("pthread_key_create");
119 exit(-1);
120 }
121 }
122
123 _X_HIDDEN void
124 __glXSetCurrentContext(__GLXcontext * c)
125 {
126 pthread_once(&once_control, init_thread_data);
127 pthread_setspecific(ContextTSD, c);
128 }
129
130 _X_HIDDEN __GLXcontext *
131 __glXGetCurrentContext(void)
132 {
133 void *v;
134
135 pthread_once(&once_control, init_thread_data);
136
137 v = pthread_getspecific(ContextTSD);
138 return (v == NULL) ? &dummyContext : (__GLXcontext *) v;
139 }
140
141 # endif /* defined( GLX_USE_TLS ) */
142
143 #elif defined( THREADS )
144
145 #error Unknown threading method specified.
146
147 #else
148
149 /* not thread safe */
150 _X_HIDDEN __GLXcontext *__glXcurrentContext = &dummyContext;
151
152 #endif
153
154
155 _X_HIDDEN void
156 __glXSetCurrentContextNull(void)
157 {
158 __glXSetCurrentContext(&dummyContext);
159 #ifdef GLX_DIRECT_RENDERING
160 _glapi_set_dispatch(NULL); /* no-op functions */
161 _glapi_set_context(NULL);
162 #endif
163 }
164
165
166 /************************************************************************/
167
168 PUBLIC GLXContext
169 glXGetCurrentContext(void)
170 {
171 GLXContext cx = __glXGetCurrentContext();
172
173 if (cx == &dummyContext) {
174 return NULL;
175 }
176 else {
177 return cx;
178 }
179 }
180
181 PUBLIC GLXDrawable
182 glXGetCurrentDrawable(void)
183 {
184 GLXContext gc = __glXGetCurrentContext();
185 return gc->currentDrawable;
186 }
187
188
189 /************************************************************************/
190
191 /**
192 * Sends a GLX protocol message to the specified display to make the context
193 * and the drawables current.
194 *
195 * \param dpy Display to send the message to.
196 * \param opcode Major opcode value for the display.
197 * \param gc_id Context tag for the context to be made current.
198 * \param draw Drawable ID for the "draw" drawable.
199 * \param read Drawable ID for the "read" drawable.
200 * \param reply Space to store the X-server's reply.
201 *
202 * \warning
203 * This function assumes that \c dpy is locked with \c LockDisplay on entry.
204 */
205 static Bool
206 SendMakeCurrentRequest(Display * dpy, CARD8 opcode,
207 GLXContextID gc_id, GLXContextTag gc_tag,
208 GLXDrawable draw, GLXDrawable read,
209 xGLXMakeCurrentReply * reply)
210 {
211 Bool ret;
212
213
214 LockDisplay(dpy);
215
216 if (draw == read) {
217 xGLXMakeCurrentReq *req;
218
219 GetReq(GLXMakeCurrent, req);
220 req->reqType = opcode;
221 req->glxCode = X_GLXMakeCurrent;
222 req->drawable = draw;
223 req->context = gc_id;
224 req->oldContextTag = gc_tag;
225 }
226 else {
227 __GLXdisplayPrivate *priv = __glXInitialize(dpy);
228
229 /* If the server can support the GLX 1.3 version, we should
230 * perfer that. Not only that, some servers support GLX 1.3 but
231 * not the SGI extension.
232 */
233
234 if ((priv->majorVersion > 1) || (priv->minorVersion >= 3)) {
235 xGLXMakeContextCurrentReq *req;
236
237 GetReq(GLXMakeContextCurrent, req);
238 req->reqType = opcode;
239 req->glxCode = X_GLXMakeContextCurrent;
240 req->drawable = draw;
241 req->readdrawable = read;
242 req->context = gc_id;
243 req->oldContextTag = gc_tag;
244 }
245 else {
246 xGLXVendorPrivateWithReplyReq *vpreq;
247 xGLXMakeCurrentReadSGIReq *req;
248
249 GetReqExtra(GLXVendorPrivateWithReply,
250 sz_xGLXMakeCurrentReadSGIReq -
251 sz_xGLXVendorPrivateWithReplyReq, vpreq);
252 req = (xGLXMakeCurrentReadSGIReq *) vpreq;
253 req->reqType = opcode;
254 req->glxCode = X_GLXVendorPrivateWithReply;
255 req->vendorCode = X_GLXvop_MakeCurrentReadSGI;
256 req->drawable = draw;
257 req->readable = read;
258 req->context = gc_id;
259 req->oldContextTag = gc_tag;
260 }
261 }
262
263 ret = _XReply(dpy, (xReply *) reply, 0, False);
264
265 UnlockDisplay(dpy);
266 SyncHandle();
267
268 return ret;
269 }
270
271
272 #ifdef GLX_DIRECT_RENDERING
273 static __GLXDRIdrawable *
274 FetchDRIDrawable(Display * dpy, GLXDrawable glxDrawable, GLXContext gc)
275 {
276 __GLXdisplayPrivate *const priv = __glXInitialize(dpy);
277 __GLXDRIdrawable *pdraw;
278 __GLXscreenConfigs *psc;
279
280 if (priv == NULL)
281 return NULL;
282
283 psc = &priv->screenConfigs[gc->screen];
284 if (psc->drawHash == NULL)
285 return NULL;
286
287 if (__glxHashLookup(psc->drawHash, glxDrawable, (void *) &pdraw) == 0)
288 return pdraw;
289
290 pdraw = psc->driScreen->createDrawable(psc, glxDrawable,
291 glxDrawable, gc->mode);
292 if (__glxHashInsert(psc->drawHash, glxDrawable, pdraw)) {
293 (*pdraw->destroyDrawable) (pdraw);
294 return NULL;
295 }
296
297 return pdraw;
298 }
299 #endif /* GLX_DIRECT_RENDERING */
300
301 static void
302 __glXGenerateError(Display * dpy, GLXContext gc, XID resource,
303 BYTE errorCode, CARD16 minorCode)
304 {
305 xError error;
306
307 error.errorCode = errorCode;
308 error.resourceID = resource;
309 error.sequenceNumber = dpy->request;
310 error.type = X_Error;
311 error.majorCode = gc->majorOpcode;
312 error.minorCode = minorCode;
313 _XError(dpy, &error);
314 }
315
316 /**
317 * Make a particular context current.
318 *
319 * \note This is in this file so that it can access dummyContext.
320 */
321 static Bool
322 MakeContextCurrent(Display * dpy, GLXDrawable draw,
323 GLXDrawable read, GLXContext gc)
324 {
325 xGLXMakeCurrentReply reply;
326 const GLXContext oldGC = __glXGetCurrentContext();
327 const CARD8 opcode = __glXSetupForCommand(dpy);
328 const CARD8 oldOpcode = ((gc == oldGC) || (oldGC == &dummyContext))
329 ? opcode : __glXSetupForCommand(oldGC->currentDpy);
330 Bool bindReturnValue;
331 __GLXattribute *state;
332
333 if (!opcode || !oldOpcode) {
334 return GL_FALSE;
335 }
336
337 /* Make sure that the new context has a nonzero ID. In the request,
338 * a zero context ID is used only to mean that we bind to no current
339 * context.
340 */
341 if ((gc != NULL) && (gc->xid == None)) {
342 return GL_FALSE;
343 }
344
345 if (gc == NULL && (draw != None || read != None)) {
346 __glXGenerateError(dpy, gc, (draw != None) ? draw : read,
347 BadMatch, X_GLXMakeContextCurrent);
348 return False;
349 }
350 if (gc != NULL && (draw == None || read == None)) {
351 __glXGenerateError(dpy, gc, None, BadMatch, X_GLXMakeContextCurrent);
352 return False;
353 }
354
355 _glapi_check_multithread();
356
357 if (gc != NULL && gc->thread_id != 0 && gc->thread_id != _glthread_GetID()) {
358 __glXGenerateError(dpy, gc, gc->xid,
359 BadAccess, X_GLXMakeContextCurrent);
360 return False;
361 }
362
363 #ifdef GLX_DIRECT_RENDERING
364 /* Bind the direct rendering context to the drawable */
365 if (gc && gc->driContext) {
366 __GLXDRIdrawable *pdraw = FetchDRIDrawable(dpy, draw, gc);
367 __GLXDRIdrawable *pread = FetchDRIDrawable(dpy, read, gc);
368
369 if ((pdraw == NULL) || (pread == NULL)) {
370 __glXGenerateError(dpy, gc, (pdraw == NULL) ? draw : read,
371 GLXBadDrawable, X_GLXMakeContextCurrent);
372 return False;
373 }
374
375 bindReturnValue =
376 (gc->driContext->bindContext) (gc->driContext, pdraw, pread);
377 }
378 else if (!gc && oldGC && oldGC->driContext) {
379 bindReturnValue = True;
380 }
381 else
382 #endif
383 {
384 /* Send a glXMakeCurrent request to bind the new context. */
385 bindReturnValue =
386 SendMakeCurrentRequest(dpy, opcode, gc ? gc->xid : None,
387 ((dpy != oldGC->currentDpy)
388 || oldGC->isDirect)
389 ? None : oldGC->currentContextTag, draw, read,
390 &reply);
391 }
392
393
394 if (!bindReturnValue) {
395 return False;
396 }
397
398 #ifdef GLX_DIRECT_RENDERING
399 if ((dpy != oldGC->currentDpy || (gc && gc->driContext)) &&
400 !oldGC->isDirect && oldGC != &dummyContext) {
401 #else
402 if ((dpy != oldGC->currentDpy) && oldGC != &dummyContext) {
403 #endif
404 xGLXMakeCurrentReply dummy_reply;
405
406 /* We are either switching from one dpy to another and have to
407 * send a request to the previous dpy to unbind the previous
408 * context, or we are switching away from a indirect context to
409 * a direct context and have to send a request to the dpy to
410 * unbind the previous context.
411 */
412 (void) SendMakeCurrentRequest(oldGC->currentDpy, oldOpcode, None,
413 oldGC->currentContextTag, None, None,
414 &dummy_reply);
415 }
416 #ifdef GLX_DIRECT_RENDERING
417 else if (oldGC->driContext && oldGC != gc) {
418 oldGC->driContext->unbindContext(oldGC->driContext);
419 }
420 #endif
421
422
423 /* Update our notion of what is current */
424 __glXLock();
425 if (gc == oldGC) {
426 /* Even though the contexts are the same the drawable might have
427 * changed. Note that gc cannot be the dummy, and that oldGC
428 * cannot be NULL, therefore if they are the same, gc is not
429 * NULL and not the dummy.
430 */
431 gc->currentDrawable = draw;
432 gc->currentReadable = read;
433 }
434 else {
435 if (oldGC != &dummyContext) {
436 /* Old current context is no longer current to anybody */
437 oldGC->currentDpy = 0;
438 oldGC->currentDrawable = None;
439 oldGC->currentReadable = None;
440 oldGC->currentContextTag = 0;
441 oldGC->thread_id = 0;
442
443 if (oldGC->xid == None) {
444 /* We are switching away from a context that was
445 * previously destroyed, so we need to free the memory
446 * for the old handle.
447 */
448 #ifdef GLX_DIRECT_RENDERING
449 /* Destroy the old direct rendering context */
450 if (oldGC->driContext) {
451 oldGC->driContext->destroyContext(oldGC->driContext,
452 oldGC->psc,
453 oldGC->createDpy);
454 oldGC->driContext = NULL;
455 }
456 #endif
457 __glXFreeContext(oldGC);
458 }
459 }
460 if (gc) {
461 __glXSetCurrentContext(gc);
462
463 gc->currentDpy = dpy;
464 gc->currentDrawable = draw;
465 gc->currentReadable = read;
466 gc->thread_id = _glthread_GetID();
467
468 #ifdef GLX_DIRECT_RENDERING
469 if (!gc->driContext) {
470 #endif
471 if (!IndirectAPI)
472 IndirectAPI = __glXNewIndirectAPI();
473 _glapi_set_dispatch(IndirectAPI);
474
475 state = (__GLXattribute *) (gc->client_state_private);
476
477 gc->currentContextTag = reply.contextTag;
478 if (state->array_state == NULL) {
479 (void) glGetString(GL_EXTENSIONS);
480 (void) glGetString(GL_VERSION);
481 __glXInitVertexArrayState(gc);
482 }
483 #ifdef GLX_DIRECT_RENDERING
484 }
485 else {
486 gc->currentContextTag = -1;
487 }
488 #endif
489 }
490 else {
491 __glXSetCurrentContextNull();
492 }
493 }
494 __glXUnlock();
495 return GL_TRUE;
496 }
497
498
499 PUBLIC Bool
500 glXMakeCurrent(Display * dpy, GLXDrawable draw, GLXContext gc)
501 {
502 return MakeContextCurrent(dpy, draw, draw, gc);
503 }
504
505 PUBLIC
506 GLX_ALIAS(Bool, glXMakeCurrentReadSGI,
507 (Display * dpy, GLXDrawable d, GLXDrawable r, GLXContext ctx),
508 (dpy, d, r, ctx), MakeContextCurrent)
509
510 PUBLIC
511 GLX_ALIAS(Bool, glXMakeContextCurrent,
512 (Display * dpy, GLXDrawable d, GLXDrawable r,
513 GLXContext ctx), (dpy, d, r, ctx), MakeContextCurrent)