aboutsummaryrefslogtreecommitdiff
path: root/nx-X11/lib/GL/apple/dri_driver.c
diff options
context:
space:
mode:
Diffstat (limited to 'nx-X11/lib/GL/apple/dri_driver.c')
-rw-r--r--nx-X11/lib/GL/apple/dri_driver.c1141
1 files changed, 1141 insertions, 0 deletions
diff --git a/nx-X11/lib/GL/apple/dri_driver.c b/nx-X11/lib/GL/apple/dri_driver.c
new file mode 100644
index 000000000..ce8b0736a
--- /dev/null
+++ b/nx-X11/lib/GL/apple/dri_driver.c
@@ -0,0 +1,1141 @@
+/* $XFree86: xc/lib/GL/apple/dri_driver.c,v 1.2 2003/10/31 02:22:12 torrey Exp $ */
+/**************************************************************************
+
+Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas.
+Copyright (c) 2002 Apple Computer, Inc.
+Copyright (c) 2004 Torrey T. Lyons
+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, sub license, 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 and this permission notice (including the
+next paragraph) 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 NON-INFRINGEMENT.
+IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS 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.
+
+**************************************************************************/
+
+/*
+ * Original Authors:
+ * Kevin E. Martin <kevin@precisioninsight.com>
+ * Brian E. Paul <brian@precisioninsight.com>
+ */
+
+/*
+ * This file follows Mesa's dri_util.c closely. The code in dri_util.c
+ * gets compiled into each of the DRI 3D drivers. A typical DRI driver,
+ * is loaded dynamically by libGL, so libGL knows nothing about the
+ * internal functions here. On Mac OS X the AppleDRI driver code is
+ * statically linked into libGL, but otherwise it tries to behave like
+ * a standard DRI driver.
+ *
+ * The functions defined here are called from the GL library via function
+ * pointers in the __DRIdisplayRec, __DRIscreenRec, __DRIcontextRec,
+ * __DRIdrawableRec structures defined in glxclient.h. Those function
+ * pointers are initialized by code in this file. The process starts when
+ * libGL calls the __driCreateScreen() function at the end of this file.
+ *
+ * The above-mentioned DRI structures have no dependencies on Mesa.
+ * Each structure instead has a generic (void *) private pointer that
+ * points to a private structure. For Mesa drivers, these private
+ * structures are the __DRIdrawablePrivateRec, __DRIcontextPrivateRec,
+ * __DRIscreenPrivateRec, and __DRIvisualPrivateRec structures defined
+ * in dri_mesaint.h. We allocate and attach those structs here in
+ * this file.
+ */
+
+
+#ifdef GLX_DIRECT_RENDERING
+
+/* These are first to ensure that Apple's GL headers are used. */
+#include <OpenGL/OpenGL.h>
+#include <OpenGL/CGLContext.h>
+
+#include <unistd.h>
+#include <X11/Xlibint.h>
+#include <X11/extensions/Xext.h>
+
+#define GLAPIENTRYP *
+#include "extutil.h"
+#include "glxclient.h"
+#include "appledri.h"
+#include "dri_driver.h"
+#include "x-list.h"
+#include "x-hash.h"
+
+/**
+ * This is used in a couple of places that call \c driMesaCreateNewDrawable.
+ */
+static const int empty_attribute_list[1] = { None };
+
+/* Context binding */
+static Bool driMesaBindContext(Display *dpy, int scrn,
+ GLXDrawable draw, GLXContext gc);
+static Bool driMesaUnbindContext(Display *dpy, int scrn,
+ GLXDrawable draw, GLXContext gc,
+ int will_rebind);
+
+/* Drawable methods */
+static void *driMesaCreateNewDrawable(__DRInativeDisplay *dpy,
+ const __GLcontextModes *modes,
+ __DRIid draw, __DRIdrawable *pdraw,
+ int renderType, const int *attrs);
+static __DRIdrawable *driMesaGetDrawable(__DRInativeDisplay *dpy,
+ GLXDrawable draw,
+ void *screenPrivate);
+static void driMesaSwapBuffers(__DRInativeDisplay *dpy, void *drawPrivate);
+static void driMesaDestroyDrawable(__DRInativeDisplay *dpy, void *drawPrivate);
+
+/* Context methods */
+static void *driMesaCreateContext(Display *dpy, XVisualInfo *vis, void *shared,
+ __DRIcontext *pctx);
+static void driMesaDestroyContext(__DRInativeDisplay *dpy, int scrn,
+ void *screenPrivate);
+
+/* Screen methods */
+static void *driMesaCreateScreen(__DRInativeDisplay *dpy, int scrn,
+ __DRIscreen *psc, int numConfigs,
+ __GLXvisualConfig *config);
+static void driMesaDestroyScreen(__DRInativeDisplay *dpy, int scrn,
+ void *screenPrivate);
+
+static void driMesaCreateSurface(Display *dpy, int scrn,
+ __DRIdrawablePrivate *pdp);
+
+static void unwrap_context(__DRIcontextPrivate *pcp);
+static void wrap_context(__DRIcontextPrivate *pcp);
+
+extern const CGLContextObj XAppleDRIGetIndirectContext(void);
+
+/*****************************************************************/
+
+/* Maintain a list of drawables */
+
+static inline Bool
+__driMesaAddDrawable(x_hash_table *drawHash, __DRIdrawable *pdraw)
+{
+ __DRIdrawablePrivate *pdp = (__DRIdrawablePrivate *)pdraw->private;
+
+ assert(drawHash != NULL);
+
+ x_hash_table_insert(drawHash, (void *) pdp->draw, pdraw);
+
+ return GL_TRUE;
+}
+
+static inline __DRIdrawable *
+__driMesaFindDrawable(x_hash_table *drawHash, GLXDrawable draw)
+{
+ if (drawHash == NULL)
+ return NULL;
+
+ return x_hash_table_lookup(drawHash, (void *) draw, NULL);
+}
+
+struct find_by_uid_closure {
+ unsigned int uid;
+ __DRIdrawable *ret;
+};
+
+static void
+find_by_uid_cb(void *k, void *v, void *data)
+{
+ __DRIdrawable *pdraw = v;
+ __DRIdrawablePrivate *pdp = (__DRIdrawablePrivate *)pdraw->private;
+ struct find_by_uid_closure *c = data;
+
+ if (pdp->uid == c->uid)
+ c->ret = pdraw;
+}
+
+static __DRIdrawable *
+__driMesaFindDrawableByUID(x_hash_table *drawHash, unsigned int uid)
+{
+ struct find_by_uid_closure c;
+
+ c.uid = uid;
+ c.ret = NULL;
+ x_hash_table_foreach(drawHash, find_by_uid_cb, &c);
+
+ return c.ret;
+}
+
+static inline void
+__driMesaRemoveDrawable(x_hash_table *drawHash, __DRIdrawable *pdraw)
+{
+ __DRIdrawablePrivate *pdp = (__DRIdrawablePrivate *)pdraw->private;
+
+ if (drawHash == NULL)
+ return;
+
+ x_hash_table_remove(drawHash, (void *) pdp->draw);
+}
+
+static Bool __driMesaWindowExistsFlag;
+
+static int __driMesaWindowExistsErrorHandler(Display *dpy, XErrorEvent *xerr)
+{
+ if (xerr->error_code == BadWindow) {
+ __driMesaWindowExistsFlag = GL_FALSE;
+ }
+ return 0;
+}
+
+static Bool __driMesaWindowExists(Display *dpy, GLXDrawable draw)
+{
+ XWindowAttributes xwa;
+ int (*oldXErrorHandler)(Display *, XErrorEvent *);
+
+ __driMesaWindowExistsFlag = GL_TRUE;
+ oldXErrorHandler = XSetErrorHandler(__driMesaWindowExistsErrorHandler);
+ XGetWindowAttributes(dpy, draw, &xwa); /* dummy request */
+ XSetErrorHandler(oldXErrorHandler);
+ return __driMesaWindowExistsFlag;
+}
+
+static void __driMesaCollectCallback(void *k, void *v, void *data)
+{
+ GLXDrawable draw = (GLXDrawable) k;
+ __DRIdrawable *pdraw = v;
+ x_list **todelete = data;
+
+ __DRIdrawablePrivate *pdp = (__DRIdrawablePrivate *)pdraw->private;
+ Display *dpy;
+
+ dpy = pdp->driScreenPriv->display;
+ XSync(dpy, GL_FALSE);
+ if (!pdp->destroyed && !__driMesaWindowExists(dpy, draw)) {
+ /* Destroy the local drawable data in the hash table, if the
+ drawable no longer exists in the Xserver */
+ pdp->destroyed = TRUE;
+ *todelete = x_list_prepend(*todelete, pdraw);
+ }
+}
+
+/* pdp->mutex is held. */
+static void __driMesaGarbageCollectDrawables(void *drawHash)
+{
+ __DRIdrawable *pdraw;
+ __DRIdrawablePrivate *pdp;
+ Display *dpy;
+ x_list *todelete = NULL, *node;
+
+ x_hash_table_foreach(drawHash, __driMesaCollectCallback, &todelete);
+
+ for (node = todelete; node != NULL; node = node->next)
+ {
+ pdraw = node->data;
+ pdp = (__DRIdrawablePrivate *)pdraw->private;
+ dpy = pdp->driScreenPriv->display;
+
+ /* Destroy the local drawable data in the hash table, if the
+ drawable no longer exists in the Xserver */
+
+ __driMesaRemoveDrawable(drawHash, pdraw);
+ (*pdraw->destroyDrawable)(dpy, pdraw->private);
+ Xfree(pdraw);
+ }
+
+ x_list_free(todelete);
+}
+
+/*****************************************************************/
+
+/* returns with psp->mutex locked if successful. */
+static Bool
+driMesaFindDrawableByUID(Display *dpy,unsigned int uid,
+ __DRIscreenPrivate **psp_ret,
+ __DRIdrawablePrivate **pdp_ret)
+{
+ __DRIscreen *pDRIScreen;
+ __DRIscreenPrivate *psp;
+ __DRIdrawable *pdraw;
+ int scrn;
+
+ for (scrn = 0; scrn < ScreenCount(dpy); scrn++)
+ {
+ if (!(pDRIScreen = __glXFindDRIScreen(dpy, scrn))) {
+ /* ERROR!!! */
+ return FALSE;
+ } else if (!(psp = (__DRIscreenPrivate *)pDRIScreen->private)) {
+ /* ERROR!!! */
+ return FALSE;
+ }
+
+ xmutex_lock(psp->mutex);
+
+ pdraw = __driMesaFindDrawableByUID(psp->drawHash, uid);
+ if (pdraw != NULL) {
+ *psp_ret = psp;
+ *pdp_ret = pdraw->private;
+ return TRUE;
+ };
+
+ xmutex_unlock(psp->mutex);
+ }
+
+ return FALSE;
+}
+
+static void
+unbind_context(__DRIcontextPrivate *pcp)
+{
+ /* Unbind the context from its old drawable. */
+
+ if (pcp->driDrawablePriv != NULL)
+ {
+ if (pcp->next != NULL)
+ pcp->next->prev = pcp->prev;
+ if (pcp->prev != NULL)
+ pcp->prev->next = pcp->next;
+
+ if (pcp->driDrawablePriv->driContextPriv == pcp)
+ pcp->driDrawablePriv->driContextPriv = pcp->next;
+
+ pcp->driDrawablePriv = NULL;
+ pcp->prev = pcp->next = NULL;
+ }
+
+ if (pcp->surface_id != 0)
+ {
+ pcp->surface_id = 0;
+ pcp->pending_clear = TRUE;
+ }
+}
+
+static void
+unbind_drawable(__DRIdrawablePrivate *pdp)
+{
+ __DRIcontextPrivate *pcp, *next;
+
+ for (pcp = pdp->driContextPriv; pcp != NULL; pcp = next)
+ {
+ next = pcp->next;
+ unbind_context(pcp);
+ }
+}
+
+static void
+update_context(__DRIcontextPrivate *pcp)
+{
+ if (pcp->pending_clear)
+ {
+ CGLClearDrawable(pcp->ctx);
+ pcp->pending_clear = FALSE;
+ }
+
+ if (pcp->pending_update && pcp->surface_id != 0)
+ {
+ xp_update_gl_context(pcp->ctx);
+ pcp->pending_update = FALSE;
+ }
+}
+
+static Bool driMesaUnbindContext(Display *dpy, int scrn,
+ GLXDrawable draw, GLXContext gc,
+ int will_rebind)
+{
+ __DRIscreen *pDRIScreen;
+// __DRIdrawable *pdraw;
+ __DRIcontextPrivate *pcp;
+ __DRIscreenPrivate *psp;
+ __DRIdrawablePrivate *pdp;
+
+ /*
+ ** Assume error checking is done properly in glXMakeCurrent before
+ ** calling driMesaUnbindContext.
+ */
+
+ if (gc == NULL || draw == None) {
+ /* ERROR!!! */
+ return GL_FALSE;
+ }
+
+ if (!(pDRIScreen = __glXFindDRIScreen(dpy, scrn))) {
+ /* ERROR!!! */
+ return GL_FALSE;
+ } else if (!(psp = (__DRIscreenPrivate *)pDRIScreen->private)) {
+ /* ERROR!!! */
+ return GL_FALSE;
+ }
+
+ xmutex_lock(psp->mutex);
+
+ pcp = (__DRIcontextPrivate *)gc->driContext.private;
+
+ pdp = pcp->driDrawablePriv;
+ if (pdp == NULL) {
+ /* ERROR!!! */
+ xmutex_unlock(psp->mutex);
+ return GL_FALSE;
+ }
+
+ /* Put this thread back into normal (indirect) dispatch mode. */
+ CGLSetCurrentContext(XAppleDRIGetIndirectContext());
+ pcp->thread_id = 0;
+
+ /* Lazily unbind the drawable from the context */
+ unbind_context(pcp);
+
+ if (pdp->refcount == 0) {
+ /* ERROR!!! */
+ xmutex_unlock(psp->mutex);
+ return GL_FALSE;
+ } else if (--pdp->refcount == 0) {
+#if 0
+ /*
+ ** NOT_DONE: When a drawable is unbound from one direct
+ ** rendering context and then bound to another, we do not want
+ ** to destroy the drawable data structure each time only to
+ ** recreate it immediatly afterwards when binding to the next
+ ** context. This also causes conflicts with caching of the
+ ** drawable stamp.
+ **
+ ** In addition, we don't destroy the drawable here since Mesa
+ ** keeps private data internally (e.g., software accumulation
+ ** buffers) that should not be destroyed unless the client
+ ** explicitly requests that the window be destroyed.
+ **
+ ** When GLX 1.3 is integrated, the create and destroy drawable
+ ** functions will have user level counterparts and the memory
+ ** will be able to be recovered.
+ **
+ ** Below is an example of what needs to go into the destroy
+ ** drawable routine to support GLX 1.3.
+ */
+ __driMesaRemoveDrawable(psp->drawHash, pdraw);
+ (*pdraw->destroyDrawable)(dpy, pdraw->private);
+ Xfree(pdraw);
+#endif
+ }
+
+ xmutex_unlock(psp->mutex);
+ return GL_TRUE;
+}
+
+static Bool driMesaBindContext(Display *dpy, int scrn,
+ GLXDrawable draw, GLXContext gc)
+{
+ __DRIscreen *pDRIScreen;
+ const __GLcontextModes *modes;
+ __DRIdrawable *pdraw;
+ __DRIdrawablePrivate *pdp;
+ __DRIscreenPrivate *psp;
+ __DRIcontextPrivate *pcp;
+
+ /*
+ ** Assume error checking is done properly in glXMakeCurrent before
+ ** calling driMesaBindContext.
+ */
+
+ if (gc == NULL || draw == None) {
+ /* ERROR!!! */
+ return GL_FALSE;
+ }
+
+ if (!(pDRIScreen = __glXFindDRIScreen(dpy, scrn))) {
+ /* ERROR!!! */
+ return GL_FALSE;
+ } else if (!(psp = (__DRIscreenPrivate *)pDRIScreen->private)) {
+ /* ERROR!!! */
+ return GL_FALSE;
+ }
+
+ modes = gc->driContext.mode;
+
+ if ( modes == NULL ) {
+ /* ERROR!!! */
+ return GL_FALSE;
+ }
+
+ xmutex_lock(psp->mutex);
+
+ pdraw = __driMesaFindDrawable(psp->drawHash, draw);
+ if (!pdraw) {
+ /* Allocate a new drawable */
+ pdraw = (__DRIdrawable *)Xmalloc(sizeof(__DRIdrawable));
+ if (!pdraw) {
+ /* ERROR!!! */
+ xmutex_unlock(psp->mutex);
+ return GL_FALSE;
+ }
+
+ /* Create a new drawable */
+ pdraw->private = driMesaCreateNewDrawable(dpy, modes, draw, pdraw,
+ GLX_WINDOW_BIT,
+ empty_attribute_list);
+ if (!pdraw->private) {
+ /* ERROR!!! */
+ Xfree(pdraw);
+ xmutex_unlock(psp->mutex);
+ return GL_FALSE;
+ }
+
+ /* Add pdraw to drawable list */
+ if (!__driMesaAddDrawable(psp->drawHash, pdraw)) {
+ /* ERROR!!! */
+ (*pdraw->destroyDrawable)(dpy, pdraw->private);
+ Xfree(pdraw);
+ xmutex_unlock(psp->mutex);
+ return GL_FALSE;
+ }
+ }
+
+ pdp = (__DRIdrawablePrivate *)pdraw->private;
+ pcp = (__DRIcontextPrivate *)gc->driContext.private;
+
+ if (pdp->surface_id == 0)
+ {
+ /* Surface got destroyed. Try to create a new one. */
+
+ driMesaCreateSurface(dpy, scrn, pdp);
+ }
+
+ unbind_context(pcp);
+
+ /* Bind the drawable to the context */
+ pcp->driDrawablePriv = pdp;
+ pcp->prev = NULL;
+ pcp->next = pdp->driContextPriv;
+ pdp->driContextPriv = pcp;
+ pdp->refcount++;
+
+ /* And the physical surface to the physical context */
+ if (pcp->surface_id != pdp->surface_id)
+ {
+ pcp->surface_id = 0;
+
+ /* Attaching the drawable sets the default viewport. But we don't
+ want to catch that call to glViewport in our wrappers. */
+ unwrap_context(pcp);
+
+ if (pdp->surface_id == 0)
+ CGLClearDrawable(pcp->ctx);
+ else if (xp_attach_gl_context(pcp->ctx, pdp->surface_id) == Success)
+ pcp->surface_id = pdp->surface_id;
+ else
+ fprintf(stderr, "failed to bind to surface\n");
+
+ wrap_context(pcp);
+
+ pcp->pending_clear = FALSE;
+ pcp->pending_update = FALSE;
+ }
+ else if (pcp->pending_clear)
+ {
+ CGLClearDrawable(pcp->ctx);
+ pcp->pending_clear = FALSE;
+ }
+
+ /* Activate the CGL context and remember which thread it's current for. */
+ CGLSetCurrentContext(pcp->ctx);
+ pcp->thread_id = xthread_self();
+
+ xmutex_unlock(psp->mutex);
+ return GL_TRUE;
+}
+
+/*****************************************************************/
+
+static xp_client_id
+get_client_id(void)
+{
+ static xp_client_id id;
+
+ if (id == 0)
+ {
+ if (xp_init(XP_IN_BACKGROUND) != Success
+ || xp_get_client_id(&id) != Success)
+ {
+ return 0;
+ }
+ }
+
+ return id;
+}
+
+static void driMesaCreateSurface(Display *dpy, int scrn,
+ __DRIdrawablePrivate *pdp)
+{
+ xp_client_id client_id;
+ unsigned int key[2];
+
+ pdp->surface_id = 0;
+ pdp->uid = 0;
+
+ client_id = get_client_id();
+ if (client_id == 0)
+ return;
+
+ if (XAppleDRICreateSurface(dpy, scrn, pdp->draw,
+ client_id, key, &pdp->uid))
+ {
+ xp_import_surface(key, &pdp->surface_id);
+ }
+}
+
+/**
+ * This is called via __DRIscreenRec's createNewDrawable pointer.
+ */
+static void *driMesaCreateNewDrawable(__DRInativeDisplay *dpy,
+ const __GLcontextModes *modes,
+ __DRIid draw,
+ __DRIdrawable *pdraw,
+ int renderType,
+ const int *attrs)
+{
+ __DRIscreen * const pDRIScreen = __glXFindDRIScreen(dpy, modes->screen);
+ __DRIscreenPrivate *psp;
+ __DRIdrawablePrivate *pdp;
+
+
+ pdraw->private = NULL;
+
+ /* Since pbuffers are not yet supported, no drawable attributes are
+ * supported either.
+ */
+ (void) attrs;
+
+ if ( (pDRIScreen == NULL) || (pDRIScreen->private == NULL) ) {
+ return NULL;
+ }
+
+ pdp = (__DRIdrawablePrivate *)Xmalloc(sizeof(__DRIdrawablePrivate));
+ if (!pdp) {
+ return NULL;
+ }
+
+ pdp->draw = draw;
+ pdp->refcount = 0;
+ pdp->surface_id = 0;
+ pdp->uid = 0;
+ pdp->destroyed = FALSE;
+
+ psp = (__DRIscreenPrivate *)pDRIScreen->private;
+ pdp->driScreenPriv = psp;
+ pdp->driContextPriv = NULL;
+
+ driMesaCreateSurface(dpy, modes->screen, pdp);
+ if (pdp->surface_id == 0) {
+ Xfree(pdp);
+ return NULL;
+ }
+
+ pdraw->private = pdp;
+ pdraw->destroyDrawable = driMesaDestroyDrawable;
+ pdraw->swapBuffers = driMesaSwapBuffers; /* called by glXSwapBuffers() */
+
+#if 0
+ /* We don't support these yet. */
+ if ( driCompareGLXAPIVersion( 20030317 ) >= 0 ) {
+ pdraw->getSBC = driGetSBC;
+ pdraw->waitForSBC = driWaitForSBC;
+ pdraw->waitForMSC = driWaitForMSC;
+ pdraw->swapBuffersMSC = driSwapBuffersMSC;
+ pdraw->frameTracking = NULL;
+ pdraw->queryFrameTracking = driQueryFrameTracking;
+
+ /* This special default value is replaced with the configured
+ * default value when the drawable is first bound to a direct
+ * rendering context. */
+ pdraw->swap_interval = (unsigned)-1;
+ }
+#endif
+
+ return (void *) pdp;
+}
+
+static __DRIdrawable *driMesaGetDrawable(__DRInativeDisplay *dpy,
+ GLXDrawable draw,
+ void *screenPrivate)
+{
+ __DRIscreenPrivate *psp = (__DRIscreenPrivate *) screenPrivate;
+ __DRIdrawable *dri_draw;
+
+ xmutex_lock(psp->mutex);
+
+ /*
+ ** Make sure this routine returns NULL if the drawable is not bound
+ ** to a direct rendering context!
+ */
+ dri_draw = __driMesaFindDrawable(psp->drawHash, draw);
+
+ xmutex_unlock(psp->mutex);
+ return dri_draw;
+}
+
+static void driMesaSwapBuffers(__DRInativeDisplay *dpy, void *drawPrivate)
+{
+ __DRIdrawablePrivate *pdp = (__DRIdrawablePrivate *) drawPrivate;
+ __DRIcontextPrivate *pcp;
+ xthread_t self = xthread_self();
+ static Bool warned;
+
+ xmutex_lock(pdp->driScreenPriv->mutex);
+
+ /* FIXME: this is sub-optimal, since we may not always find a context
+ bound to the given drawable on this thread. */
+
+ for (pcp = pdp->driContextPriv; pcp != NULL; pcp = pcp->next)
+ {
+ if (pcp->thread_id == self || pcp->thread_id == 0)
+ break;
+ }
+
+ if (pcp != NULL)
+ {
+ CGLFlushDrawable(pcp->ctx);
+ }
+ else
+ {
+ if (!warned) {
+ fprintf(stderr, "glXSwapBuffers: no context for this drawable\n");
+ warned = TRUE;
+ }
+ }
+
+ xmutex_unlock(pdp->driScreenPriv->mutex);
+}
+
+/* pdp->mutex is held. */
+static void driMesaDestroyDrawable(__DRInativeDisplay *dpy, void *drawPrivate)
+{
+ __DRIdrawablePrivate *pdp = (__DRIdrawablePrivate *)drawPrivate;
+
+ if (pdp) {
+ unbind_drawable(pdp);
+ if (pdp->surface_id != 0) {
+ xp_destroy_surface(pdp->surface_id);
+ pdp->surface_id = 0;
+ }
+ if (!pdp->destroyed) {
+ /* don't try to destroy an already destroyed surface. */
+ XAppleDRIDestroySurface(dpy, pdp->driScreenPriv->myNum, pdp->draw);
+ }
+ Xfree(pdp);
+ }
+}
+
+/*****************************************************************/
+
+static CGLPixelFormatObj
+driCreatePixelFormat(Display *dpy, __DRIscreenPrivate *psp,
+ XVisualInfo *visinfo, __GLXvisualConfig *config)
+{
+ int i;
+ CGLPixelFormatAttribute attr[64]; // currently uses max of 30
+ CGLPixelFormatObj result;
+ long n_formats;
+
+ i = 0;
+
+ if (!config->rgba)
+ return NULL;
+
+ if (config->stereo)
+ attr[i++] = kCGLPFAStereo;
+
+ if (config->doubleBuffer)
+ attr[i++] = kCGLPFADoubleBuffer;
+
+ attr[i++] = kCGLPFAColorSize;
+ attr[i++] = config->redSize + config->greenSize + config->blueSize;
+ attr[i++] = kCGLPFAAlphaSize;
+ attr[i++] = 1; /* FIXME: ignoring config->alphaSize which is always 0 */
+
+ if (config->accumRedSize + config->accumGreenSize
+ + config->accumBlueSize + config->accumAlphaSize > 0)
+ {
+ attr[i++] = kCGLPFAAccumSize;
+ attr[i++] = (config->accumRedSize + config->accumGreenSize
+ + config->accumBlueSize + config->accumAlphaSize);
+ }
+
+ if (config->depthSize > 0) {
+ attr[i++] = kCGLPFADepthSize;
+ attr[i++] = config->depthSize;
+ }
+
+ if (config->stencilSize > 0) {
+ attr[i++] = kCGLPFAStencilSize;
+ attr[i++] = config->stencilSize;
+ }
+
+ if (config->auxBuffers > 0) {
+ attr[i++] = kCGLPFAAuxBuffers;
+ attr[i++] = config->auxBuffers;
+ }
+
+ /* FIXME: things we don't handle: color/alpha masks, level,
+ visualrating, transparentFoo */
+
+ attr[i++] = 0;
+
+ result = NULL;
+ CGLChoosePixelFormat(attr, &result, &n_formats);
+
+ return result;
+}
+
+static void *driMesaCreateContext(Display *dpy, XVisualInfo *vis, void *shared,
+ __DRIcontext *pctx)
+{
+ __DRIscreen *pDRIScreen;
+ __DRIcontextPrivate *pcp;
+ __DRIcontextPrivate *pshare = (__DRIcontextPrivate *)shared;
+ __DRIscreenPrivate *psp;
+ int i;
+
+ if (!(pDRIScreen = __glXFindDRIScreen(dpy, vis->screen))) {
+ /* ERROR!!! */
+ return NULL;
+ } else if (!(psp = (__DRIscreenPrivate *)pDRIScreen->private)) {
+ /* ERROR!!! */
+ return NULL;
+ }
+
+ /* Create the hash table */
+ if (!psp->drawHash) {
+ xmutex_lock(psp->mutex);
+ if (!psp->drawHash)
+ psp->drawHash = x_hash_table_new(NULL, NULL, NULL, NULL);
+ xmutex_unlock(psp->mutex);
+ }
+
+ pcp = (__DRIcontextPrivate *)Xmalloc(sizeof(__DRIcontextPrivate));
+ if (!pcp) {
+ return NULL;
+ }
+
+ pcp->display = dpy;
+ pcp->driScreenPriv = psp;
+ pcp->driDrawablePriv = NULL;
+
+ pcp->ctx = NULL;
+ pcp->surface_id = 0;
+
+ pcp->pending_clear = FALSE;
+ pcp->pending_update = FALSE;
+
+ pcp->ctx = NULL;
+ for (i = 0; pcp->ctx == NULL && i < psp->numVisuals; i++) {
+ if (psp->visuals[i].vid == vis->visualid) {
+ CGLCreateContext(psp->visuals[i].pixel_format,
+ pshare ? pshare->ctx : NULL, &pcp->ctx);
+ }
+ }
+
+ if (!pcp->ctx) {
+ Xfree(pcp);
+ return NULL;
+ }
+
+ pctx->destroyContext = driMesaDestroyContext;
+ pctx->bindContext = driMesaBindContext;
+ pctx->unbindContext = driMesaUnbindContext;
+
+ wrap_context(pcp);
+
+ xmutex_lock(psp->mutex);
+ __driMesaGarbageCollectDrawables(pcp->driScreenPriv->drawHash);
+ xmutex_unlock(psp->mutex);
+
+ return pcp;
+}
+
+static void driMesaDestroyContext(__DRInativeDisplay *dpy, int scrn,
+ void *contextPrivate)
+{
+ __DRIcontextPrivate *pcp = (__DRIcontextPrivate *) contextPrivate;
+
+ if (pcp) {
+ xmutex_lock(pcp->driScreenPriv->mutex);
+ unbind_context(pcp);
+ __driMesaGarbageCollectDrawables(pcp->driScreenPriv->drawHash);
+ xmutex_unlock(pcp->driScreenPriv->mutex);
+ CGLDestroyContext(pcp->ctx);
+ Xfree(pcp);
+ }
+}
+
+/*****************************************************************/
+
+static void *driMesaCreateScreen(__DRInativeDisplay *dpy, int scrn,
+ __DRIscreen *psc, int numConfigs,
+ __GLXvisualConfig *config)
+{
+ int directCapable, i, n;
+ __DRIscreenPrivate *psp;
+ XVisualInfo visTmpl, *visinfo;
+
+ if (!XAppleDRIQueryDirectRenderingCapable(dpy, scrn, &directCapable)) {
+ return NULL;
+ }
+
+ if (!directCapable) {
+ return NULL;
+ }
+
+ psp = (__DRIscreenPrivate *)Xmalloc(sizeof(__DRIscreenPrivate));
+ if (!psp) {
+ return NULL;
+ }
+
+ psp->mutex = xmutex_malloc();
+ if (psp->mutex != NULL) {
+ xmutex_init (psp->mutex);
+ xmutex_set_name (psp->mutex, "AppleDRI");
+ }
+ psp->display = dpy;
+ psp->myNum = scrn;
+
+#if 0
+ if (!XAppleDRIAuthConnection(dpy, scrn, magic)) {
+ Xfree(psp);
+ (void)XAppleDRICloseConnection(dpy, scrn);
+ return NULL;
+ }
+#endif
+
+ /*
+ * Allocate space for an array of visual records and initialize them.
+ */
+ psp->visuals = (__DRIvisualPrivate *)Xmalloc(numConfigs *
+ sizeof(__DRIvisualPrivate));
+ if (!psp->visuals) {
+ Xfree(psp);
+ return NULL;
+ }
+
+ visTmpl.screen = scrn;
+ visinfo = XGetVisualInfo(dpy, VisualScreenMask, &visTmpl, &n);
+ if (n != numConfigs) {
+ Xfree(psp);
+ return NULL;
+ }
+
+ psp->numVisuals = 0;
+ for (i = 0; i < numConfigs; i++, config++) {
+ psp->visuals[psp->numVisuals].vid = visinfo[i].visualid;
+ psp->visuals[psp->numVisuals].pixel_format =
+ driCreatePixelFormat(dpy, psp, &visinfo[i], config);
+ if (psp->visuals[psp->numVisuals].pixel_format != NULL) {
+ psp->numVisuals++;
+ }
+ }
+
+ XFree(visinfo);
+
+ if (psp->numVisuals == 0) {
+ /* Couldn't create any pixel formats. */
+ Xfree(psp->visuals);
+ Xfree(psp);
+ return NULL;
+ }
+
+ /* Initialize the drawHash when the first context is created */
+ psp->drawHash = NULL;
+
+ psc->destroyScreen = driMesaDestroyScreen;
+ psc->createContext = driMesaCreateContext;
+ psc->createNewDrawable = driMesaCreateNewDrawable;
+ psc->getDrawable = driMesaGetDrawable;
+
+ return (void *)psp;
+}
+
+static void driMesaDestroyScreen(__DRInativeDisplay *dpy, int scrn,
+ void *screenPrivate)
+{
+ __DRIscreenPrivate *psp = (__DRIscreenPrivate *) screenPrivate;
+
+ if (psp) {
+ //FIXME resetDriver ?
+ Xfree(psp->visuals);
+ Xfree(psp);
+ }
+}
+
+/* Note: definitely can't make any X protocol requests here. */
+static void driAppleSurfaceNotify(Display *dpy, unsigned int uid, int kind)
+{
+ __DRIscreenPrivate *psp;
+ __DRIdrawablePrivate *pdp;
+ __DRIcontextPrivate *pcp;
+
+ /* locks psp->mutex if successful. */
+ if (driMesaFindDrawableByUID(dpy, uid, &psp, &pdp))
+ {
+ xthread_t self = xthread_self();
+
+ switch (kind)
+ {
+ Bool all_safe;
+
+ case AppleDRISurfaceNotifyDestroyed:
+ xp_destroy_surface(pdp->surface_id);
+ pdp->surface_id = 0;
+
+ for (pcp = pdp->driContextPriv; pcp != NULL; pcp = pcp->next)
+ {
+ pcp->surface_id = 0;
+
+ if (pcp->thread_id == self || pcp->thread_id == 0) {
+ CGLClearDrawable(pcp->ctx);
+ pcp->pending_clear = FALSE;
+ } else
+ pcp->pending_clear = TRUE;
+ }
+ break;
+
+ case AppleDRISurfaceNotifyChanged:
+ all_safe = TRUE;
+ for (pcp = pdp->driContextPriv; pcp != NULL; pcp = pcp->next)
+ {
+ if (pcp->thread_id != 0 && pcp->thread_id != self) {
+ all_safe = FALSE;
+ break;
+ }
+ }
+ for (pcp = pdp->driContextPriv; pcp != NULL; pcp = pcp->next)
+ {
+ if (all_safe) {
+ xp_update_gl_context(pcp->ctx);
+ pcp->pending_update = FALSE;
+ } else
+ pcp->pending_update = TRUE;
+ }
+ break;
+ }
+
+ xmutex_unlock(psp->mutex);
+ }
+}
+
+/**
+ * Entrypoint function used to create a new driver-private screen structure.
+ *
+ * \param dpy Display pointer.
+ * \param scrn Index of the screen.
+ * \param psc DRI screen data (not driver private)
+ * \param numConfigs Number of visual configs pointed to by \c configs.
+ * \param config Array of GLXvisualConfigs exported by the 2D driver.
+ *
+ * \deprecated
+ * In dynamically linked drivers, this function has been replaced by
+ * \c __driCreateNewScreen.
+ */
+void *__driCreateScreen(Display *dpy, int scrn, __DRIscreen *psc,
+ int numConfigs, __GLXvisualConfig *config)
+{
+ static int here_before;
+
+ if (!here_before)
+ {
+ XAppleDRISetSurfaceNotifyHandler(driAppleSurfaceNotify);
+ here_before = True;
+ }
+
+ return driMesaCreateScreen(dpy, scrn, psc, numConfigs, config);
+}
+
+void __driRegisterExtensions(void)
+{
+}
+
+__private_extern__ void XAppleDRIUseIndirectDispatch(void)
+{
+ CGLSetCurrentContext(XAppleDRIGetIndirectContext());
+}
+
+/*****************************************************************/
+
+/*
+ * Currently (Mac OS X 10.3) the only way we have of regaining control
+ * from threads calling GL and nothing else is by patching the dispatch
+ * table of the CGLContext, so that glViewport, glFlush and glFinish
+ * call us back.
+ *
+ * Since glNewList and glEndList overwrite the entire dispatch table we
+ * also need to patch those so we can restore the others.
+ *
+ * WARNING: This is not expected to work on future OS releases.
+ */
+
+#define WRAP_CGL(context, vec, fun) \
+ do { \
+ (context)->disp.vec = (context)->ctx->disp.vec; \
+ (context)->ctx->disp.vec = (fun); \
+ } while (0)
+
+#define UNWRAP_CGL(context, vec) \
+ do { \
+ (context)->ctx->disp.vec = (context)->disp.vec; \
+ } while (0)
+
+#define WRAP_BOILERPLATE \
+ GLXContext gc; \
+ __DRIcontextPrivate *pcp; \
+ gc = __glXGetCurrentContext(); \
+ if (gc == NULL || !gc->isDirect) return; \
+ pcp = (__DRIcontextPrivate *) gc->driContext.private; \
+ if (pcp == NULL) return;
+
+static void viewport_callback(GLIContext ctx, GLint x, GLint y,
+ GLsizei width, GLsizei height)
+{
+ WRAP_BOILERPLATE
+
+ xmutex_lock(pcp->driScreenPriv->mutex);
+ update_context(pcp);
+ xmutex_unlock(pcp->driScreenPriv->mutex);
+
+ (*pcp->disp.viewport)(ctx, x, y, width, height);
+}
+
+static void new_list_callback(GLIContext ctx, GLuint list, GLenum mode)
+{
+ WRAP_BOILERPLATE
+
+ unwrap_context(pcp);
+ (*pcp->ctx->disp.new_list)(ctx, list, mode);
+ wrap_context(pcp);
+}
+
+static void end_list_callback(GLIContext ctx)
+{
+ WRAP_BOILERPLATE
+
+ unwrap_context(pcp);
+ (*pcp->ctx->disp.end_list)(ctx);
+ wrap_context(pcp);
+}
+
+static void unwrap_context(__DRIcontextPrivate *pcp)
+{
+ UNWRAP_CGL(pcp, viewport);
+ UNWRAP_CGL(pcp, new_list);
+ UNWRAP_CGL(pcp, end_list);
+}
+
+static void wrap_context(__DRIcontextPrivate *pcp)
+{
+ WRAP_CGL(pcp, new_list, new_list_callback);
+ WRAP_CGL(pcp, end_list, end_list_callback);
+ WRAP_CGL(pcp, viewport, viewport_callback);
+}
+
+#endif /* GLX_DIRECT_RENDERING */