diff options
Diffstat (limited to 'nx-X11/lib/GL/apple/dri_driver.c')
-rw-r--r-- | nx-X11/lib/GL/apple/dri_driver.c | 1141 |
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 */ |