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