Merge branch 'r500test' of git://people.freedesktop.org/~airlied/mesa into r345-cleanup
[mesa.git] / src / glx / x11 / glxcurrent.c
1 /*
2 ** License Applicability. Except to the extent portions of this file are
3 ** made subject to an alternative license as permitted in the SGI Free
4 ** Software License B, Version 1.1 (the "License"), the contents of this
5 ** file are subject only to the provisions of the License. You may not use
6 ** this file except in compliance with the License. You may obtain a copy
7 ** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
8 ** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
9 **
10 ** http://oss.sgi.com/projects/FreeB
11 **
12 ** Note that, as provided in the License, the Software is distributed on an
13 ** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
14 ** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
15 ** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
16 ** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
17 **
18 ** Original Code. The Original Code is: OpenGL Sample Implementation,
19 ** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
20 ** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
21 ** Copyright in any portions created by third parties is as indicated
22 ** elsewhere herein. All Rights Reserved.
23 **
24 ** Additional Notice Provisions: The application programming interfaces
25 ** established by SGI in conjunction with the Original Code are The
26 ** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
27 ** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
28 ** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
29 ** Window System(R) (Version 1.3), released October 19, 1998. This software
30 ** was created using the OpenGL(R) version 1.2.1 Sample Implementation
31 ** published by SGI, but has not been independently verified as being
32 ** compliant with the OpenGL(R) version 1.2.1 Specification.
33 **
34 */
35
36 /**
37 * \file glxcurrent.c
38 * Client-side GLX interface for current context management.
39 */
40
41 #include "glxclient.h"
42 #include "glapi.h"
43 #include "glheader.h"
44 #include "indirect_init.h"
45
46 #ifdef GLX_DIRECT_RENDERING
47 #include "xf86dri.h"
48 #endif
49
50 /*
51 ** We setup some dummy structures here so that the API can be used
52 ** even if no context is current.
53 */
54
55 static GLubyte dummyBuffer[__GLX_BUFFER_LIMIT_SIZE];
56
57 /*
58 ** Dummy context used by small commands when there is no current context.
59 ** All the
60 ** gl and glx entry points are designed to operate as nop's when using
61 ** the dummy context structure.
62 */
63 static __GLXcontext dummyContext = {
64 &dummyBuffer[0],
65 &dummyBuffer[0],
66 &dummyBuffer[0],
67 &dummyBuffer[__GLX_BUFFER_LIMIT_SIZE],
68 sizeof(dummyBuffer),
69 };
70
71
72 /*
73 ** All indirect rendering contexts will share the same indirect dispatch table.
74 */
75 static __GLapi *IndirectAPI = NULL;
76
77
78 /*
79 * Current context management and locking
80 */
81
82 #if defined( USE_XTHREADS )
83
84 /* thread safe */
85 static GLboolean TSDinitialized = GL_FALSE;
86 static xthread_key_t ContextTSD;
87
88 _X_HIDDEN __GLXcontext *__glXGetCurrentContext(void)
89 {
90 if (!TSDinitialized) {
91 xthread_key_create(&ContextTSD, NULL);
92 TSDinitialized = GL_TRUE;
93 return &dummyContext;
94 }
95 else {
96 void *p;
97 xthread_get_specific(ContextTSD, &p);
98 if (!p)
99 return &dummyContext;
100 else
101 return (__GLXcontext *) p;
102 }
103 }
104
105 _X_HIDDEN void __glXSetCurrentContext(__GLXcontext *c)
106 {
107 if (!TSDinitialized) {
108 xthread_key_create(&ContextTSD, NULL);
109 TSDinitialized = GL_TRUE;
110 }
111 xthread_set_specific(ContextTSD, c);
112 }
113
114
115 /* Used by the __glXLock() and __glXUnlock() macros */
116 _X_HIDDEN xmutex_rec __glXmutex;
117
118 #elif defined( PTHREADS )
119
120 _X_HIDDEN pthread_mutex_t __glXmutex = PTHREAD_MUTEX_INITIALIZER;
121
122 # if defined( GLX_USE_TLS )
123
124 /**
125 * Per-thread GLX context pointer.
126 *
127 * \c __glXSetCurrentContext is written is such a way that this pointer can
128 * \b never be \c NULL. This is important! Because of this
129 * \c __glXGetCurrentContext can be implemented as trivial macro.
130 */
131 __thread void * __glX_tls_Context __attribute__((tls_model("initial-exec")))
132 = &dummyContext;
133
134 _X_HIDDEN void __glXSetCurrentContext( __GLXcontext * c )
135 {
136 __glX_tls_Context = (c != NULL) ? c : &dummyContext;
137 }
138
139 # else
140
141 static pthread_once_t once_control = PTHREAD_ONCE_INIT;
142
143 /**
144 * Per-thread data key.
145 *
146 * Once \c init_thread_data has been called, the per-thread data key will
147 * take a value of \c NULL. As each new thread is created the default
148 * value, in that thread, will be \c NULL.
149 */
150 static pthread_key_t ContextTSD;
151
152 /**
153 * Initialize the per-thread data key.
154 *
155 * This function is called \b exactly once per-process (not per-thread!) to
156 * initialize the per-thread data key. This is ideally done using the
157 * \c pthread_once mechanism.
158 */
159 static void init_thread_data( void )
160 {
161 if ( pthread_key_create( & ContextTSD, NULL ) != 0 ) {
162 perror( "pthread_key_create" );
163 exit( -1 );
164 }
165 }
166
167 _X_HIDDEN void __glXSetCurrentContext( __GLXcontext * c )
168 {
169 pthread_once( & once_control, init_thread_data );
170 pthread_setspecific( ContextTSD, c );
171 }
172
173 _X_HIDDEN __GLXcontext * __glXGetCurrentContext( void )
174 {
175 void * v;
176
177 pthread_once( & once_control, init_thread_data );
178
179 v = pthread_getspecific( ContextTSD );
180 return (v == NULL) ? & dummyContext : (__GLXcontext *) v;
181 }
182
183 # endif /* defined( GLX_USE_TLS ) */
184
185 #elif defined( THREADS )
186
187 #error Unknown threading method specified.
188
189 #else
190
191 /* not thread safe */
192 _X_HIDDEN __GLXcontext *__glXcurrentContext = &dummyContext;
193
194 #endif
195
196
197 _X_HIDDEN void __glXSetCurrentContextNull(void)
198 {
199 __glXSetCurrentContext(&dummyContext);
200 #ifdef GLX_DIRECT_RENDERING
201 _glapi_set_dispatch(NULL); /* no-op functions */
202 #endif
203 }
204
205
206 /************************************************************************/
207
208 PUBLIC GLXContext glXGetCurrentContext(void)
209 {
210 GLXContext cx = __glXGetCurrentContext();
211
212 if (cx == &dummyContext) {
213 return NULL;
214 } else {
215 return cx;
216 }
217 }
218
219 PUBLIC GLXDrawable glXGetCurrentDrawable(void)
220 {
221 GLXContext gc = __glXGetCurrentContext();
222 return gc->currentDrawable;
223 }
224
225
226 /************************************************************************/
227
228 /**
229 * Sends a GLX protocol message to the specified display to make the context
230 * and the drawables current.
231 *
232 * \param dpy Display to send the message to.
233 * \param opcode Major opcode value for the display.
234 * \param gc_id Context tag for the context to be made current.
235 * \param draw Drawable ID for the "draw" drawable.
236 * \param read Drawable ID for the "read" drawable.
237 * \param reply Space to store the X-server's reply.
238 *
239 * \warning
240 * This function assumes that \c dpy is locked with \c LockDisplay on entry.
241 */
242 static Bool SendMakeCurrentRequest(Display *dpy, CARD8 opcode,
243 GLXContextID gc_id, GLXContextTag gc_tag,
244 GLXDrawable draw, GLXDrawable read,
245 xGLXMakeCurrentReply *reply)
246 {
247 Bool ret;
248
249
250 LockDisplay(dpy);
251
252 if (draw == read) {
253 xGLXMakeCurrentReq *req;
254
255 GetReq(GLXMakeCurrent,req);
256 req->reqType = opcode;
257 req->glxCode = X_GLXMakeCurrent;
258 req->drawable = draw;
259 req->context = gc_id;
260 req->oldContextTag = gc_tag;
261 }
262 else {
263 __GLXdisplayPrivate *priv = __glXInitialize(dpy);
264
265 /* If the server can support the GLX 1.3 version, we should
266 * perfer that. Not only that, some servers support GLX 1.3 but
267 * not the SGI extension.
268 */
269
270 if ((priv->majorVersion > 1) || (priv->minorVersion >= 3)) {
271 xGLXMakeContextCurrentReq *req;
272
273 GetReq(GLXMakeContextCurrent,req);
274 req->reqType = opcode;
275 req->glxCode = X_GLXMakeContextCurrent;
276 req->drawable = draw;
277 req->readdrawable = read;
278 req->context = gc_id;
279 req->oldContextTag = gc_tag;
280 }
281 else {
282 xGLXVendorPrivateWithReplyReq *vpreq;
283 xGLXMakeCurrentReadSGIReq *req;
284
285 GetReqExtra(GLXVendorPrivateWithReply,
286 sz_xGLXMakeCurrentReadSGIReq-sz_xGLXVendorPrivateWithReplyReq,vpreq);
287 req = (xGLXMakeCurrentReadSGIReq *)vpreq;
288 req->reqType = opcode;
289 req->glxCode = X_GLXVendorPrivateWithReply;
290 req->vendorCode = X_GLXvop_MakeCurrentReadSGI;
291 req->drawable = draw;
292 req->readable = read;
293 req->context = gc_id;
294 req->oldContextTag = gc_tag;
295 }
296 }
297
298 ret = _XReply(dpy, (xReply*) reply, 0, False);
299
300 UnlockDisplay(dpy);
301 SyncHandle();
302
303 return ret;
304 }
305
306
307 #ifdef GLX_DIRECT_RENDERING
308 static __GLXDRIdrawable *
309 FetchDRIDrawable(Display *dpy,
310 GLXDrawable glxDrawable, GLXContext gc, Bool pre13)
311 {
312 __GLXdisplayPrivate * const priv = __glXInitialize(dpy);
313 __GLXDRIdrawable *pdraw;
314 __GLXscreenConfigs *psc;
315 XID drawable;
316
317 if (priv == NULL)
318 return NULL;
319
320 psc = &priv->screenConfigs[gc->screen];
321 if (psc->drawHash == NULL)
322 return NULL;
323
324 if (__glxHashLookup(psc->drawHash, glxDrawable, (void *) &pdraw) == 0)
325 return pdraw;
326
327 /* If this is glXMakeCurrent (pre GLX 1.3) we allow creating the
328 * GLX drawable on the fly. Otherwise we pass None as the X
329 * drawable */
330 if (pre13)
331 drawable = glxDrawable;
332 else
333 drawable = None;
334
335 pdraw = psc->driScreen->createDrawable(psc, drawable,
336 glxDrawable, gc->mode);
337 if (__glxHashInsert(psc->drawHash, glxDrawable, pdraw)) {
338 (*pdraw->destroyDrawable)(pdraw);
339 return NULL;
340 }
341
342 return pdraw;
343 }
344 #endif /* GLX_DIRECT_RENDERING */
345
346
347 /**
348 * Make a particular context current.
349 *
350 * \note This is in this file so that it can access dummyContext.
351 */
352 static Bool MakeContextCurrent(Display *dpy, GLXDrawable draw,
353 GLXDrawable read, GLXContext gc,
354 Bool pre13)
355 {
356 xGLXMakeCurrentReply reply;
357 const GLXContext oldGC = __glXGetCurrentContext();
358 const CARD8 opcode = __glXSetupForCommand(dpy);
359 const CARD8 oldOpcode = ((gc == oldGC) || (oldGC == &dummyContext))
360 ? opcode : __glXSetupForCommand(oldGC->currentDpy);
361 Bool bindReturnValue;
362
363
364 if (!opcode || !oldOpcode) {
365 return GL_FALSE;
366 }
367
368 /* Make sure that the new context has a nonzero ID. In the request,
369 * a zero context ID is used only to mean that we bind to no current
370 * context.
371 */
372 if ((gc != NULL) && (gc->xid == None)) {
373 return GL_FALSE;
374 }
375
376 _glapi_check_multithread();
377
378 #ifdef GLX_DIRECT_RENDERING
379 /* Bind the direct rendering context to the drawable */
380 if (gc && gc->driContext) {
381 __GLXDRIdrawable *pdraw = FetchDRIDrawable(dpy, draw, gc, pre13);
382 __GLXDRIdrawable *pread = FetchDRIDrawable(dpy, read, gc, pre13);
383
384 bindReturnValue =
385 (gc->driContext->bindContext) (gc->driContext, pdraw, pread);
386 } else
387 #endif
388 {
389 /* Send a glXMakeCurrent request to bind the new context. */
390 bindReturnValue =
391 SendMakeCurrentRequest(dpy, opcode, gc ? gc->xid : None,
392 ((dpy != oldGC->currentDpy) || oldGC->isDirect)
393 ? None : oldGC->currentContextTag,
394 draw, read, &reply);
395 }
396
397
398 if (!bindReturnValue) {
399 return False;
400 }
401
402 if ((dpy != oldGC->currentDpy || (gc && gc->driContext)) &&
403 !oldGC->isDirect && oldGC != &dummyContext) {
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) {
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 } else {
434 if (oldGC != &dummyContext) {
435 /* Old current context is no longer current to anybody */
436 oldGC->currentDpy = 0;
437 oldGC->currentDrawable = None;
438 oldGC->currentReadable = None;
439 oldGC->currentContextTag = 0;
440
441 if (oldGC->xid == None) {
442 /* We are switching away from a context that was
443 * previously destroyed, so we need to free the memory
444 * for the old handle.
445 */
446 #ifdef GLX_DIRECT_RENDERING
447 /* Destroy the old direct rendering context */
448 if (oldGC->driContext) {
449 oldGC->driContext->destroyContext(oldGC->driContext,
450 oldGC->psc,
451 oldGC->createDpy);
452 oldGC->driContext = NULL;
453 }
454 #endif
455 __glXFreeContext(oldGC);
456 }
457 }
458 if (gc) {
459 __glXSetCurrentContext(gc);
460
461 gc->currentDpy = dpy;
462 gc->currentDrawable = draw;
463 gc->currentReadable = read;
464
465 if (!gc->driContext) {
466 if (!IndirectAPI)
467 IndirectAPI = __glXNewIndirectAPI();
468 _glapi_set_dispatch(IndirectAPI);
469
470 #ifdef GLX_USE_APPLEGL
471 do {
472 extern void XAppleDRIUseIndirectDispatch(void);
473 XAppleDRIUseIndirectDispatch();
474 } while (0);
475 #endif
476
477 __GLXattribute *state =
478 (__GLXattribute *)(gc->client_state_private);
479
480 gc->currentContextTag = reply.contextTag;
481 if (state->array_state == NULL) {
482 (void) glGetString(GL_EXTENSIONS);
483 (void) glGetString(GL_VERSION);
484 __glXInitVertexArrayState(gc);
485 }
486 }
487 else {
488 gc->currentContextTag = -1;
489 }
490 } else {
491 __glXSetCurrentContextNull();
492 }
493 }
494 __glXUnlock();
495 return GL_TRUE;
496 }
497
498
499 PUBLIC Bool glXMakeCurrent(Display *dpy, GLXDrawable draw, GLXContext gc)
500 {
501 return MakeContextCurrent(dpy, draw, draw, gc, True);
502 }
503
504 PUBLIC GLX_ALIAS(Bool, glXMakeCurrentReadSGI,
505 (Display *dpy, GLXDrawable d, GLXDrawable r, GLXContext ctx),
506 (dpy, d, r, ctx, False), MakeContextCurrent)
507
508 PUBLIC GLX_ALIAS(Bool, glXMakeContextCurrent,
509 (Display *dpy, GLXDrawable d, GLXDrawable r, GLXContext ctx),
510 (dpy, d, r, ctx, False), MakeContextCurrent)