summaryrefslogtreecommitdiff
path: root/src/glx/x11/glxcurrent.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/glx/x11/glxcurrent.c')
-rw-r--r--src/glx/x11/glxcurrent.c532
1 files changed, 532 insertions, 0 deletions
diff --git a/src/glx/x11/glxcurrent.c b/src/glx/x11/glxcurrent.c
new file mode 100644
index 0000000000..89be63c5fa
--- /dev/null
+++ b/src/glx/x11/glxcurrent.c
@@ -0,0 +1,532 @@
+/* -*- mode: c; tab-width: 3; indent-tabs-mode: nil; c-basic-offset: 3; coding: utf-8-unix -*- */
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * shall be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+
+/**
+ * \file glxcurrent.c
+ * Client-side GLX interface for current context management.
+ */
+
+#include "glxclient.h"
+#include "glapi.h"
+#include "indirect_init.h"
+
+#ifdef GLX_DIRECT_RENDERING
+#include "xf86dri.h"
+#endif
+
+/*
+** We setup some dummy structures here so that the API can be used
+** even if no context is current.
+*/
+
+static GLubyte dummyBuffer[__GLX_BUFFER_LIMIT_SIZE];
+
+/*
+** Dummy context used by small commands when there is no current context.
+** All the
+** gl and glx entry points are designed to operate as nop's when using
+** the dummy context structure.
+*/
+static __GLXcontext dummyContext = {
+ &dummyBuffer[0],
+ &dummyBuffer[0],
+ &dummyBuffer[0],
+ &dummyBuffer[__GLX_BUFFER_LIMIT_SIZE],
+ sizeof(dummyBuffer),
+};
+
+
+/*
+** All indirect rendering contexts will share the same indirect dispatch table.
+*/
+static __GLapi *IndirectAPI = NULL;
+
+
+/*
+ * Current context management and locking
+ */
+
+#if defined( USE_XTHREADS )
+
+/* thread safe */
+static GLboolean TSDinitialized = GL_FALSE;
+static xthread_key_t ContextTSD;
+
+_X_HIDDEN __GLXcontext *
+__glXGetCurrentContext(void)
+{
+ if (!TSDinitialized) {
+ xthread_key_create(&ContextTSD, NULL);
+ TSDinitialized = GL_TRUE;
+ return &dummyContext;
+ }
+ else {
+ void *p;
+ xthread_get_specific(ContextTSD, &p);
+ if (!p)
+ return &dummyContext;
+ else
+ return (__GLXcontext *) p;
+ }
+}
+
+_X_HIDDEN void
+__glXSetCurrentContext(__GLXcontext * c)
+{
+ if (!TSDinitialized) {
+ xthread_key_create(&ContextTSD, NULL);
+ TSDinitialized = GL_TRUE;
+ }
+ xthread_set_specific(ContextTSD, c);
+}
+
+
+/* Used by the __glXLock() and __glXUnlock() macros */
+_X_HIDDEN xmutex_rec __glXmutex;
+
+#elif defined( PTHREADS )
+
+_X_HIDDEN pthread_mutex_t __glXmutex = PTHREAD_MUTEX_INITIALIZER;
+
+# if defined( GLX_USE_TLS )
+
+/**
+ * Per-thread GLX context pointer.
+ *
+ * \c __glXSetCurrentContext is written is such a way that this pointer can
+ * \b never be \c NULL. This is important! Because of this
+ * \c __glXGetCurrentContext can be implemented as trivial macro.
+ */
+__thread void *__glX_tls_Context __attribute__ ((tls_model("initial-exec")))
+ = &dummyContext;
+
+_X_HIDDEN void
+__glXSetCurrentContext(__GLXcontext * c)
+{
+ __glX_tls_Context = (c != NULL) ? c : &dummyContext;
+}
+
+# else
+
+static pthread_once_t once_control = PTHREAD_ONCE_INIT;
+
+/**
+ * Per-thread data key.
+ *
+ * Once \c init_thread_data has been called, the per-thread data key will
+ * take a value of \c NULL. As each new thread is created the default
+ * value, in that thread, will be \c NULL.
+ */
+static pthread_key_t ContextTSD;
+
+/**
+ * Initialize the per-thread data key.
+ *
+ * This function is called \b exactly once per-process (not per-thread!) to
+ * initialize the per-thread data key. This is ideally done using the
+ * \c pthread_once mechanism.
+ */
+static void
+init_thread_data(void)
+{
+ if (pthread_key_create(&ContextTSD, NULL) != 0) {
+ perror("pthread_key_create");
+ exit(-1);
+ }
+}
+
+_X_HIDDEN void
+__glXSetCurrentContext(__GLXcontext * c)
+{
+ pthread_once(&once_control, init_thread_data);
+ pthread_setspecific(ContextTSD, c);
+}
+
+_X_HIDDEN __GLXcontext *
+__glXGetCurrentContext(void)
+{
+ void *v;
+
+ pthread_once(&once_control, init_thread_data);
+
+ v = pthread_getspecific(ContextTSD);
+ return (v == NULL) ? &dummyContext : (__GLXcontext *) v;
+}
+
+# endif /* defined( GLX_USE_TLS ) */
+
+#elif defined( THREADS )
+
+#error Unknown threading method specified.
+
+#else
+
+/* not thread safe */
+_X_HIDDEN __GLXcontext *__glXcurrentContext = &dummyContext;
+
+#endif
+
+
+_X_HIDDEN void
+__glXSetCurrentContextNull(void)
+{
+ __glXSetCurrentContext(&dummyContext);
+#ifdef GLX_DIRECT_RENDERING
+ _glapi_set_dispatch(NULL); /* no-op functions */
+#endif
+}
+
+
+/************************************************************************/
+
+PUBLIC GLXContext
+glXGetCurrentContext(void)
+{
+ GLXContext cx = __glXGetCurrentContext();
+
+ if (cx == &dummyContext) {
+ return NULL;
+ }
+ else {
+ return cx;
+ }
+}
+
+PUBLIC GLXDrawable
+glXGetCurrentDrawable(void)
+{
+ GLXContext gc = __glXGetCurrentContext();
+ return gc->currentDrawable;
+}
+
+
+/************************************************************************/
+
+/**
+ * Sends a GLX protocol message to the specified display to make the context
+ * and the drawables current.
+ *
+ * \param dpy Display to send the message to.
+ * \param opcode Major opcode value for the display.
+ * \param gc_id Context tag for the context to be made current.
+ * \param draw Drawable ID for the "draw" drawable.
+ * \param read Drawable ID for the "read" drawable.
+ * \param reply Space to store the X-server's reply.
+ *
+ * \warning
+ * This function assumes that \c dpy is locked with \c LockDisplay on entry.
+ */
+static Bool
+SendMakeCurrentRequest(Display * dpy, CARD8 opcode,
+ GLXContextID gc_id, GLXContextTag gc_tag,
+ GLXDrawable draw, GLXDrawable read,
+ xGLXMakeCurrentReply * reply)
+{
+ Bool ret;
+
+
+ LockDisplay(dpy);
+
+ if (draw == read) {
+ xGLXMakeCurrentReq *req;
+
+ GetReq(GLXMakeCurrent, req);
+ req->reqType = opcode;
+ req->glxCode = X_GLXMakeCurrent;
+ req->drawable = draw;
+ req->context = gc_id;
+ req->oldContextTag = gc_tag;
+ }
+ else {
+ __GLXdisplayPrivate *priv = __glXInitialize(dpy);
+
+ /* If the server can support the GLX 1.3 version, we should
+ * perfer that. Not only that, some servers support GLX 1.3 but
+ * not the SGI extension.
+ */
+
+ if ((priv->majorVersion > 1) || (priv->minorVersion >= 3)) {
+ xGLXMakeContextCurrentReq *req;
+
+ GetReq(GLXMakeContextCurrent, req);
+ req->reqType = opcode;
+ req->glxCode = X_GLXMakeContextCurrent;
+ req->drawable = draw;
+ req->readdrawable = read;
+ req->context = gc_id;
+ req->oldContextTag = gc_tag;
+ }
+ else {
+ xGLXVendorPrivateWithReplyReq *vpreq;
+ xGLXMakeCurrentReadSGIReq *req;
+
+ GetReqExtra(GLXVendorPrivateWithReply,
+ sz_xGLXMakeCurrentReadSGIReq -
+ sz_xGLXVendorPrivateWithReplyReq, vpreq);
+ req = (xGLXMakeCurrentReadSGIReq *) vpreq;
+ req->reqType = opcode;
+ req->glxCode = X_GLXVendorPrivateWithReply;
+ req->vendorCode = X_GLXvop_MakeCurrentReadSGI;
+ req->drawable = draw;
+ req->readable = read;
+ req->context = gc_id;
+ req->oldContextTag = gc_tag;
+ }
+ }
+
+ ret = _XReply(dpy, (xReply *) reply, 0, False);
+
+ UnlockDisplay(dpy);
+ SyncHandle();
+
+ return ret;
+}
+
+
+#ifdef GLX_DIRECT_RENDERING
+static __GLXDRIdrawable *
+FetchDRIDrawable(Display * dpy,
+ GLXDrawable glxDrawable, GLXContext gc, Bool pre13)
+{
+ __GLXdisplayPrivate *const priv = __glXInitialize(dpy);
+ __GLXDRIdrawable *pdraw;
+ __GLXscreenConfigs *psc;
+ XID drawable;
+
+ if (priv == NULL)
+ return NULL;
+
+ psc = &priv->screenConfigs[gc->screen];
+ if (psc->drawHash == NULL)
+ return NULL;
+
+ if (__glxHashLookup(psc->drawHash, glxDrawable, (void *) &pdraw) == 0)
+ return pdraw;
+
+ /* If this is glXMakeCurrent (pre GLX 1.3) we allow creating the
+ * GLX drawable on the fly. Otherwise we pass None as the X
+ * drawable */
+ if (pre13)
+ drawable = glxDrawable;
+ else
+ drawable = None;
+
+ pdraw = psc->driScreen->createDrawable(psc, drawable,
+ glxDrawable, gc->mode);
+ if (__glxHashInsert(psc->drawHash, glxDrawable, pdraw)) {
+ (*pdraw->destroyDrawable) (pdraw);
+ return NULL;
+ }
+
+ return pdraw;
+}
+#endif /* GLX_DIRECT_RENDERING */
+
+
+/**
+ * Make a particular context current.
+ *
+ * \note This is in this file so that it can access dummyContext.
+ */
+static Bool
+MakeContextCurrent(Display * dpy, GLXDrawable draw,
+ GLXDrawable read, GLXContext gc, Bool pre13)
+{
+ xGLXMakeCurrentReply reply;
+ const GLXContext oldGC = __glXGetCurrentContext();
+ const CARD8 opcode = __glXSetupForCommand(dpy);
+ const CARD8 oldOpcode = ((gc == oldGC) || (oldGC == &dummyContext))
+ ? opcode : __glXSetupForCommand(oldGC->currentDpy);
+ Bool bindReturnValue;
+
+
+ if (!opcode || !oldOpcode) {
+ return GL_FALSE;
+ }
+
+ /* Make sure that the new context has a nonzero ID. In the request,
+ * a zero context ID is used only to mean that we bind to no current
+ * context.
+ */
+ if ((gc != NULL) && (gc->xid == None)) {
+ return GL_FALSE;
+ }
+
+ _glapi_check_multithread();
+
+#ifdef GLX_DIRECT_RENDERING
+ /* Bind the direct rendering context to the drawable */
+ if (gc && gc->driContext) {
+ __GLXDRIdrawable *pdraw = FetchDRIDrawable(dpy, draw, gc, pre13);
+ __GLXDRIdrawable *pread = FetchDRIDrawable(dpy, read, gc, pre13);
+
+ bindReturnValue =
+ (gc->driContext->bindContext) (gc->driContext, pdraw, pread);
+ }
+ else
+#endif
+ {
+ /* Send a glXMakeCurrent request to bind the new context. */
+ bindReturnValue =
+ SendMakeCurrentRequest(dpy, opcode, gc ? gc->xid : None,
+ ((dpy != oldGC->currentDpy)
+ || oldGC->isDirect)
+ ? None : oldGC->currentContextTag, draw, read,
+ &reply);
+ }
+
+
+ if (!bindReturnValue) {
+ return False;
+ }
+
+#ifdef GLX_DIRECT_RENDERING
+ if ((dpy != oldGC->currentDpy || (gc && gc->driContext)) &&
+ !oldGC->isDirect && oldGC != &dummyContext) {
+#else
+ if ((dpy != oldGC->currentDpy) && oldGC != &dummyContext) {
+#endif
+ xGLXMakeCurrentReply dummy_reply;
+
+ /* We are either switching from one dpy to another and have to
+ * send a request to the previous dpy to unbind the previous
+ * context, or we are switching away from a indirect context to
+ * a direct context and have to send a request to the dpy to
+ * unbind the previous context.
+ */
+ (void) SendMakeCurrentRequest(oldGC->currentDpy, oldOpcode, None,
+ oldGC->currentContextTag, None, None,
+ &dummy_reply);
+ }
+#ifdef GLX_DIRECT_RENDERING
+ else if (oldGC->driContext) {
+ oldGC->driContext->unbindContext(oldGC->driContext);
+ }
+#endif
+
+
+ /* Update our notion of what is current */
+ __glXLock();
+ if (gc == oldGC) {
+ /* Even though the contexts are the same the drawable might have
+ * changed. Note that gc cannot be the dummy, and that oldGC
+ * cannot be NULL, therefore if they are the same, gc is not
+ * NULL and not the dummy.
+ */
+ gc->currentDrawable = draw;
+ gc->currentReadable = read;
+ }
+ else {
+ if (oldGC != &dummyContext) {
+ /* Old current context is no longer current to anybody */
+ oldGC->currentDpy = 0;
+ oldGC->currentDrawable = None;
+ oldGC->currentReadable = None;
+ oldGC->currentContextTag = 0;
+
+ if (oldGC->xid == None) {
+ /* We are switching away from a context that was
+ * previously destroyed, so we need to free the memory
+ * for the old handle.
+ */
+#ifdef GLX_DIRECT_RENDERING
+ /* Destroy the old direct rendering context */
+ if (oldGC->driContext) {
+ oldGC->driContext->destroyContext(oldGC->driContext,
+ oldGC->psc,
+ oldGC->createDpy);
+ oldGC->driContext = NULL;
+ }
+#endif
+ __glXFreeContext(oldGC);
+ }
+ }
+ if (gc) {
+ __glXSetCurrentContext(gc);
+
+ gc->currentDpy = dpy;
+ gc->currentDrawable = draw;
+ gc->currentReadable = read;
+
+#ifdef GLX_DIRECT_RENDERING
+ if (!gc->driContext) {
+#endif
+ if (!IndirectAPI)
+ IndirectAPI = __glXNewIndirectAPI();
+ _glapi_set_dispatch(IndirectAPI);
+
+#ifdef GLX_USE_APPLEGL
+ do {
+ extern void XAppleDRIUseIndirectDispatch(void);
+ XAppleDRIUseIndirectDispatch();
+ } while (0);
+#endif
+
+ __GLXattribute *state =
+ (__GLXattribute *) (gc->client_state_private);
+
+ gc->currentContextTag = reply.contextTag;
+ if (state->array_state == NULL) {
+ (void) glGetString(GL_EXTENSIONS);
+ (void) glGetString(GL_VERSION);
+ __glXInitVertexArrayState(gc);
+ }
+#ifdef GLX_DIRECT_RENDERING
+ }
+ else {
+ gc->currentContextTag = -1;
+ }
+#endif
+ }
+ else {
+ __glXSetCurrentContextNull();
+ }
+ }
+ __glXUnlock();
+ return GL_TRUE;
+}
+
+
+PUBLIC Bool
+glXMakeCurrent(Display * dpy, GLXDrawable draw, GLXContext gc)
+{
+ return MakeContextCurrent(dpy, draw, draw, gc, True);
+}
+
+PUBLIC
+GLX_ALIAS(Bool, glXMakeCurrentReadSGI,
+ (Display * dpy, GLXDrawable d, GLXDrawable r, GLXContext ctx),
+ (dpy, d, r, ctx, False), MakeContextCurrent)
+
+ PUBLIC GLX_ALIAS(Bool, glXMakeContextCurrent,
+ (Display * dpy, GLXDrawable d, GLXDrawable r,
+ GLXContext ctx), (dpy, d, r, ctx, False),
+ MakeContextCurrent)