aboutsummaryrefslogtreecommitdiff
path: root/nx-X11/programs/Xserver/GL/dri/dri.c
diff options
context:
space:
mode:
Diffstat (limited to 'nx-X11/programs/Xserver/GL/dri/dri.c')
-rw-r--r--nx-X11/programs/Xserver/GL/dri/dri.c2109
1 files changed, 2109 insertions, 0 deletions
diff --git a/nx-X11/programs/Xserver/GL/dri/dri.c b/nx-X11/programs/Xserver/GL/dri/dri.c
new file mode 100644
index 000000000..424a21c68
--- /dev/null
+++ b/nx-X11/programs/Xserver/GL/dri/dri.c
@@ -0,0 +1,2109 @@
+/* $XFree86: xc/programs/Xserver/GL/dri/dri.c,v 1.39 2003/11/10 18:21:41 tsi Exp $ */
+/**************************************************************************
+
+Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas.
+Copyright 2000 VA Linux Systems, 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, 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.
+
+**************************************************************************/
+
+/*
+ * Authors:
+ * Jens Owen <jens@tungstengraphics.com>
+ * Rickard E. (Rik) Faith <faith@valinux.com>
+ *
+ */
+
+#ifdef HAVE_XORG_CONFIG_H
+#include <xorg-config.h>
+#endif
+
+#include "xf86.h"
+#ifdef XFree86LOADER
+#include "xf86_ansic.h"
+#else
+#include <sys/time.h>
+#include <unistd.h>
+#endif
+
+#define NEED_REPLIES
+#define NEED_EVENTS
+#include <X11/X.h>
+#include <X11/Xproto.h>
+#include "misc.h"
+#include "dixstruct.h"
+#include "extnsionst.h"
+#include "colormapst.h"
+#include "cursorstr.h"
+#include "scrnintstr.h"
+#include "windowstr.h"
+#include "servermd.h"
+#define _XF86DRI_SERVER_
+#include "xf86dristr.h"
+#include "swaprep.h"
+#include "xf86str.h"
+#include "dri.h"
+#include "sarea.h"
+#include "dristruct.h"
+#include "xf86.h"
+#include "xf86drm.h"
+#include "glxserver.h"
+#include "mi.h"
+#include "mipointer.h"
+
+#if defined(XFree86LOADER) && !defined(PANORAMIX)
+extern Bool noPanoramiXExtension;
+#endif
+
+static int DRIScreenPrivIndex = -1;
+static int DRIWindowPrivIndex = -1;
+static unsigned long DRIGeneration = 0;
+static unsigned int DRIDrawableValidationStamp = 0;
+
+static RESTYPE DRIDrawablePrivResType;
+static RESTYPE DRIContextPrivResType;
+static void DRIDestroyDummyContext(ScreenPtr pScreen, Bool hasCtxPriv);
+
+ /* Wrapper just like xf86DrvMsg, but
+ without the verbosity level checking.
+ This will make it easy to turn off some
+ messages later, based on verbosity
+ level. */
+
+/*
+ * Since we're already referencing things from the XFree86 common layer in
+ * this file, we'd might as well just call xf86VDrvMsgVerb, and have
+ * consistent message formatting. The verbosity of these messages can be
+ * easily changed here.
+ */
+#define DRI_MSG_VERBOSITY 1
+static void
+DRIDrvMsg(int scrnIndex, MessageType type, const char *format, ...)
+{
+ va_list ap;
+
+ va_start(ap, format);
+ xf86VDrvMsgVerb(scrnIndex, type, DRI_MSG_VERBOSITY, format, ap);
+ va_end(ap);
+}
+
+Bool
+DRIScreenInit(ScreenPtr pScreen, DRIInfoPtr pDRIInfo, int *pDRMFD)
+{
+ DRIScreenPrivPtr pDRIPriv;
+ drm_context_t * reserved;
+ int reserved_count;
+ int i, fd, drmWasAvailable;
+ Bool xineramaInCore = FALSE;
+ int err = 0;
+ char *openbusid;
+ drmVersionPtr drmlibv;
+ int drmlibmajor, drmlibminor, drmdimajor, drmdiminor;
+
+ if (DRIGeneration != serverGeneration) {
+ if ((DRIScreenPrivIndex = AllocateScreenPrivateIndex()) < 0)
+ return FALSE;
+ DRIGeneration = serverGeneration;
+ }
+
+ /* If the DRI extension is disabled, do not initialize the DRI */
+ if (noXFree86DRIExtension) {
+ DRIDrvMsg(pScreen->myNum, X_WARNING,
+ "Direct rendering has been disabled.\n");
+ return FALSE;
+ }
+
+ /*
+ * If Xinerama is on, don't allow DRI to initialise. It won't be usable
+ * anyway.
+ */
+#if defined(PANORAMIX) && !defined(XFree86LOADER)
+ xineramaInCore = TRUE;
+#elif defined(XFree86LOADER)
+ if (xf86LoaderCheckSymbol("noPanoramiXExtension"))
+ xineramaInCore = TRUE;
+#endif
+
+#if defined(PANORAMIX) || defined(XFree86LOADER)
+ if (xineramaInCore) {
+ if (!noPanoramiXExtension) {
+ DRIDrvMsg(pScreen->myNum, X_WARNING,
+ "Direct rendering is not supported when Xinerama is enabled\n");
+ return FALSE;
+ }
+ }
+#endif
+
+ drmWasAvailable = drmAvailable();
+
+ /* Check the DRM lib version.
+ * drmGetLibVersion was not supported in version 1.0, so check for
+ * symbol first to avoid possible crash or hang.
+ */
+ drmlibmajor = 1;
+ drmlibminor = 0;
+ if (xf86LoaderCheckSymbol("drmGetLibVersion")) {
+ drmlibv = drmGetLibVersion(-1);
+ if (drmlibv != NULL) {
+ drmlibmajor = drmlibv->version_major;
+ drmlibminor = drmlibv->version_minor;
+ drmFreeVersion(drmlibv);
+ }
+ }
+
+ /* Check if the libdrm can handle falling back to loading based on name
+ * if a busid string is passed.
+ */
+ if (drmlibmajor == 1 && drmlibminor >= 2)
+ openbusid = pDRIInfo->busIdString;
+ else
+ openbusid = NULL;
+
+ /* Note that drmOpen will try to load the kernel module, if needed. */
+ fd = drmOpen(pDRIInfo->drmDriverName, openbusid);
+ if (fd < 0) {
+ /* failed to open DRM */
+ pScreen->devPrivates[DRIScreenPrivIndex].ptr = NULL;
+ DRIDrvMsg(pScreen->myNum, X_INFO,
+ "[drm] drmOpen failed\n");
+ return FALSE;
+ }
+
+ if (!drmWasAvailable) {
+ /* drmOpen loaded the kernel module, print a message to say so */
+ DRIDrvMsg(pScreen->myNum, X_INFO,
+ "[drm] loaded kernel module for \"%s\" driver\n",
+ pDRIInfo->drmDriverName);
+ }
+
+ pDRIPriv = (DRIScreenPrivPtr) xcalloc(1, sizeof(DRIScreenPrivRec));
+ if (!pDRIPriv) {
+ pScreen->devPrivates[DRIScreenPrivIndex].ptr = NULL;
+ return FALSE;
+ }
+
+ pScreen->devPrivates[DRIScreenPrivIndex].ptr = (pointer) pDRIPriv;
+ pDRIPriv->drmFD = fd;
+ pDRIPriv->directRenderingSupport = TRUE;
+ pDRIPriv->pDriverInfo = pDRIInfo;
+ pDRIPriv->nrWindows = 0;
+ pDRIPriv->fullscreen = NULL;
+
+ pDRIPriv->createDummyCtx = pDRIInfo->createDummyCtx;
+ pDRIPriv->createDummyCtxPriv = pDRIInfo->createDummyCtxPriv;
+
+ pDRIPriv->grabbedDRILock = FALSE;
+ pDRIPriv->drmSIGIOHandlerInstalled = FALSE;
+
+ if (drmlibmajor == 1 && drmlibminor >= 2) {
+ drmSetVersion sv;
+
+ /* Get the interface version, asking for 1.1. */
+ sv.drm_di_major = 1;
+ sv.drm_di_minor = 1;
+ sv.drm_dd_major = -1;
+ err = drmSetInterfaceVersion(pDRIPriv->drmFD, &sv);
+ if (err == 0) {
+ drmdimajor = sv.drm_di_major;
+ drmdiminor = sv.drm_di_minor;
+ } else {
+ /* failure, so set it to 1.0.0. */
+ drmdimajor = 1;
+ drmdiminor = 0;
+ }
+ }
+ else {
+ /* We can't check the DI DRM interface version, so set it to 1.0.0. */
+ drmdimajor = 1;
+ drmdiminor = 0;
+ }
+ DRIDrvMsg(pScreen->myNum, X_INFO,
+ "[drm] DRM interface version %d.%d\n", drmdimajor, drmdiminor);
+
+ /* If the interface minor number is 1.1, then we've opened a DRM device
+ * that already had the busid set through drmOpen.
+ */
+ if (drmdimajor == 1 && drmdiminor >= 1)
+ err = 0;
+ else
+ err = drmSetBusid(pDRIPriv->drmFD, pDRIPriv->pDriverInfo->busIdString);
+
+ if (err < 0) {
+ pDRIPriv->directRenderingSupport = FALSE;
+ pScreen->devPrivates[DRIScreenPrivIndex].ptr = NULL;
+ drmClose(pDRIPriv->drmFD);
+ DRIDrvMsg(pScreen->myNum, X_INFO,
+ "[drm] drmSetBusid failed (%d, %s), %s\n",
+ pDRIPriv->drmFD, pDRIPriv->pDriverInfo->busIdString, strerror(-err));
+ return FALSE;
+ }
+
+ *pDRMFD = pDRIPriv->drmFD;
+ DRIDrvMsg(pScreen->myNum, X_INFO,
+ "[drm] created \"%s\" driver at busid \"%s\"\n",
+ pDRIPriv->pDriverInfo->drmDriverName,
+ pDRIPriv->pDriverInfo->busIdString);
+
+ if (drmAddMap( pDRIPriv->drmFD,
+ 0,
+ pDRIPriv->pDriverInfo->SAREASize,
+ DRM_SHM,
+ DRM_CONTAINS_LOCK,
+ &pDRIPriv->hSAREA) < 0)
+ {
+ pDRIPriv->directRenderingSupport = FALSE;
+ pScreen->devPrivates[DRIScreenPrivIndex].ptr = NULL;
+ drmClose(pDRIPriv->drmFD);
+ DRIDrvMsg(pScreen->myNum, X_INFO,
+ "[drm] drmAddMap failed\n");
+ return FALSE;
+ }
+ DRIDrvMsg(pScreen->myNum, X_INFO,
+ "[drm] added %d byte SAREA at %p\n",
+ pDRIPriv->pDriverInfo->SAREASize, pDRIPriv->hSAREA);
+
+ if (drmMap( pDRIPriv->drmFD,
+ pDRIPriv->hSAREA,
+ pDRIPriv->pDriverInfo->SAREASize,
+ (drmAddressPtr)(&pDRIPriv->pSAREA)) < 0)
+ {
+ pDRIPriv->directRenderingSupport = FALSE;
+ pScreen->devPrivates[DRIScreenPrivIndex].ptr = NULL;
+ drmClose(pDRIPriv->drmFD);
+ DRIDrvMsg(pScreen->myNum, X_INFO,
+ "[drm] drmMap failed\n");
+ return FALSE;
+ }
+ memset(pDRIPriv->pSAREA, 0, pDRIPriv->pDriverInfo->SAREASize);
+ DRIDrvMsg(pScreen->myNum, X_INFO, "[drm] mapped SAREA %p to %p\n",
+ pDRIPriv->hSAREA, pDRIPriv->pSAREA);
+
+ if (drmAddMap( pDRIPriv->drmFD,
+ (drm_handle_t)pDRIPriv->pDriverInfo->frameBufferPhysicalAddress,
+ pDRIPriv->pDriverInfo->frameBufferSize,
+ DRM_FRAME_BUFFER,
+ 0,
+ &pDRIPriv->hFrameBuffer) < 0)
+ {
+ pDRIPriv->directRenderingSupport = FALSE;
+ pScreen->devPrivates[DRIScreenPrivIndex].ptr = NULL;
+ drmUnmap(pDRIPriv->pSAREA, pDRIPriv->pDriverInfo->SAREASize);
+ drmClose(pDRIPriv->drmFD);
+ DRIDrvMsg(pScreen->myNum, X_INFO,
+ "[drm] drmAddMap failed\n");
+ return FALSE;
+ }
+ DRIDrvMsg(pScreen->myNum, X_INFO, "[drm] framebuffer handle = %p\n",
+ pDRIPriv->hFrameBuffer);
+
+ /* Add tags for reserved contexts */
+ if ((reserved = drmGetReservedContextList(pDRIPriv->drmFD,
+ &reserved_count))) {
+ int i;
+ void *tag;
+
+ for (i = 0; i < reserved_count; i++) {
+ tag = DRICreateContextPrivFromHandle(pScreen,
+ reserved[i],
+ DRI_CONTEXT_RESERVED);
+ drmAddContextTag(pDRIPriv->drmFD, reserved[i], tag);
+ }
+ drmFreeReservedContextList(reserved);
+ DRIDrvMsg(pScreen->myNum, X_INFO,
+ "[drm] added %d reserved context%s for kernel\n",
+ reserved_count, reserved_count > 1 ? "s" : "");
+ }
+
+ /* validate max drawable table entry set by driver */
+ if ((pDRIPriv->pDriverInfo->maxDrawableTableEntry <= 0) ||
+ (pDRIPriv->pDriverInfo->maxDrawableTableEntry > SAREA_MAX_DRAWABLES)) {
+ DRIDrvMsg(pScreen->myNum, X_ERROR,
+ "Invalid max drawable table size set by driver: %d\n",
+ pDRIPriv->pDriverInfo->maxDrawableTableEntry);
+ }
+
+ /* Initialize drawable tables (screen private and SAREA) */
+ for( i=0; i < pDRIPriv->pDriverInfo->maxDrawableTableEntry; i++) {
+ pDRIPriv->DRIDrawables[i] = NULL;
+ pDRIPriv->pSAREA->drawableTable[i].stamp = 0;
+ pDRIPriv->pSAREA->drawableTable[i].flags = 0;
+ }
+
+ return TRUE;
+}
+
+Bool
+DRIFinishScreenInit(ScreenPtr pScreen)
+{
+ DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
+ DRIInfoPtr pDRIInfo = pDRIPriv->pDriverInfo;
+ DRIContextFlags flags = 0;
+ DRIContextPrivPtr pDRIContextPriv;
+
+ /* Set up flags for DRICreateContextPriv */
+ switch (pDRIInfo->driverSwapMethod) {
+ case DRI_KERNEL_SWAP: flags = DRI_CONTEXT_2DONLY; break;
+ case DRI_HIDE_X_CONTEXT: flags = DRI_CONTEXT_PRESERVED; break;
+ }
+
+ if (!(pDRIContextPriv = DRICreateContextPriv(pScreen,
+ &pDRIPriv->myContext,
+ flags))) {
+ DRIDrvMsg(pScreen->myNum, X_ERROR,
+ "failed to create server context\n");
+ return FALSE;
+ }
+ pDRIPriv->myContextPriv = pDRIContextPriv;
+
+ DRIDrvMsg(pScreen->myNum, X_INFO,
+ "X context handle = %p\n", pDRIPriv->myContext);
+
+ /* Now that we have created the X server's context, we can grab the
+ * hardware lock for the X server.
+ */
+ DRILock(pScreen, 0);
+ pDRIPriv->grabbedDRILock = TRUE;
+
+ /* pointers so that we can prevent memory leaks later */
+ pDRIPriv->hiddenContextStore = NULL;
+ pDRIPriv->partial3DContextStore = NULL;
+
+ switch(pDRIInfo->driverSwapMethod) {
+ case DRI_HIDE_X_CONTEXT:
+ /* Server will handle 3D swaps, and hide 2D swaps from kernel.
+ * Register server context as a preserved context.
+ */
+
+ /* allocate memory for hidden context store */
+ pDRIPriv->hiddenContextStore
+ = (void *)xcalloc(1, pDRIInfo->contextSize);
+ if (!pDRIPriv->hiddenContextStore) {
+ DRIDrvMsg(pScreen->myNum, X_ERROR,
+ "failed to allocate hidden context\n");
+ DRIDestroyContextPriv(pDRIContextPriv);
+ return FALSE;
+ }
+
+ /* allocate memory for partial 3D context store */
+ pDRIPriv->partial3DContextStore
+ = (void *)xcalloc(1, pDRIInfo->contextSize);
+ if (!pDRIPriv->partial3DContextStore) {
+ DRIDrvMsg(pScreen->myNum, X_ERROR,
+ "[DRI] failed to allocate partial 3D context\n");
+ xfree(pDRIPriv->hiddenContextStore);
+ DRIDestroyContextPriv(pDRIContextPriv);
+ return FALSE;
+ }
+
+ /* save initial context store */
+ if (pDRIInfo->SwapContext) {
+ (*pDRIInfo->SwapContext)(
+ pScreen,
+ DRI_NO_SYNC,
+ DRI_2D_CONTEXT,
+ pDRIPriv->hiddenContextStore,
+ DRI_NO_CONTEXT,
+ NULL);
+ }
+ /* fall through */
+
+ case DRI_SERVER_SWAP:
+ /* For swap methods of DRI_SERVER_SWAP and DRI_HIDE_X_CONTEXT
+ * setup signal handler for receiving swap requests from kernel
+ */
+ if (!(pDRIPriv->drmSIGIOHandlerInstalled =
+ drmInstallSIGIOHandler(pDRIPriv->drmFD, DRISwapContext))) {
+ DRIDrvMsg(pScreen->myNum, X_ERROR,
+ "[drm] failed to setup DRM signal handler\n");
+ if (pDRIPriv->hiddenContextStore)
+ xfree(pDRIPriv->hiddenContextStore);
+ if (pDRIPriv->partial3DContextStore)
+ xfree(pDRIPriv->partial3DContextStore);
+ DRIDestroyContextPriv(pDRIContextPriv);
+ return FALSE;
+ } else {
+ DRIDrvMsg(pScreen->myNum, X_INFO,
+ "[drm] installed DRM signal handler\n");
+ }
+
+ default:
+ break;
+ }
+
+ /* Wrap DRI support */
+ if (pDRIInfo->wrap.ValidateTree) {
+ pDRIPriv->wrap.ValidateTree = pScreen->ValidateTree;
+ pScreen->ValidateTree = pDRIInfo->wrap.ValidateTree;
+ }
+ if (pDRIInfo->wrap.PostValidateTree) {
+ pDRIPriv->wrap.PostValidateTree = pScreen->PostValidateTree;
+ pScreen->PostValidateTree = pDRIInfo->wrap.PostValidateTree;
+ }
+ if (pDRIInfo->wrap.WindowExposures) {
+ pDRIPriv->wrap.WindowExposures = pScreen->WindowExposures;
+ pScreen->WindowExposures = pDRIInfo->wrap.WindowExposures;
+ }
+ if (pDRIInfo->wrap.CopyWindow) {
+ pDRIPriv->wrap.CopyWindow = pScreen->CopyWindow;
+ pScreen->CopyWindow = pDRIInfo->wrap.CopyWindow;
+ }
+ if (pDRIInfo->wrap.ClipNotify) {
+ pDRIPriv->wrap.ClipNotify = pScreen->ClipNotify;
+ pScreen->ClipNotify = pDRIInfo->wrap.ClipNotify;
+ }
+ if (pDRIInfo->wrap.AdjustFrame) {
+ ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+ pDRIPriv->wrap.AdjustFrame = pScrn->AdjustFrame;
+ pScrn->AdjustFrame = pDRIInfo->wrap.AdjustFrame;
+ }
+ pDRIPriv->wrapped = TRUE;
+
+ DRIDrvMsg(pScreen->myNum, X_INFO, "[DRI] installation complete\n");
+
+ return TRUE;
+}
+
+void
+DRICloseScreen(ScreenPtr pScreen)
+{
+ DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
+ DRIInfoPtr pDRIInfo;
+ drm_context_t * reserved;
+ int reserved_count;
+
+ if (pDRIPriv && pDRIPriv->directRenderingSupport) {
+
+ pDRIInfo = pDRIPriv->pDriverInfo;
+
+ if (pDRIPriv->wrapped) {
+ /* Unwrap DRI Functions */
+ if (pDRIInfo->wrap.ValidateTree) {
+ pScreen->ValidateTree = pDRIPriv->wrap.ValidateTree;
+ pDRIPriv->wrap.ValidateTree = NULL;
+ }
+ if (pDRIInfo->wrap.PostValidateTree) {
+ pScreen->PostValidateTree = pDRIPriv->wrap.PostValidateTree;
+ pDRIPriv->wrap.PostValidateTree = NULL;
+ }
+ if (pDRIInfo->wrap.WindowExposures) {
+ pScreen->WindowExposures = pDRIPriv->wrap.WindowExposures;
+ pDRIPriv->wrap.WindowExposures = NULL;
+ }
+ if (pDRIInfo->wrap.CopyWindow) {
+ pScreen->CopyWindow = pDRIPriv->wrap.CopyWindow;
+ pDRIPriv->wrap.CopyWindow = NULL;
+ }
+ if (pDRIInfo->wrap.ClipNotify) {
+ pScreen->ClipNotify = pDRIPriv->wrap.ClipNotify;
+ pDRIPriv->wrap.ClipNotify = NULL;
+ }
+ if (pDRIInfo->wrap.AdjustFrame) {
+ ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+ pScrn->AdjustFrame = pDRIPriv->wrap.AdjustFrame;
+ pDRIPriv->wrap.AdjustFrame = NULL;
+ }
+ pDRIPriv->wrapped = FALSE;
+ }
+
+ if (pDRIPriv->drmSIGIOHandlerInstalled) {
+ if (!drmRemoveSIGIOHandler(pDRIPriv->drmFD)) {
+ DRIDrvMsg(pScreen->myNum, X_ERROR,
+ "[drm] failed to remove DRM signal handler\n");
+ }
+ }
+
+ if (pDRIPriv->dummyCtxPriv && pDRIPriv->createDummyCtx) {
+ DRIDestroyDummyContext(pScreen, pDRIPriv->createDummyCtxPriv);
+ }
+
+ if (!DRIDestroyContextPriv(pDRIPriv->myContextPriv)) {
+ DRIDrvMsg(pScreen->myNum, X_ERROR,
+ "failed to destroy server context\n");
+ }
+
+ /* Remove tags for reserved contexts */
+ if ((reserved = drmGetReservedContextList(pDRIPriv->drmFD,
+ &reserved_count))) {
+ int i;
+
+ for (i = 0; i < reserved_count; i++) {
+ DRIDestroyContextPriv(drmGetContextTag(pDRIPriv->drmFD,
+ reserved[i]));
+ }
+ drmFreeReservedContextList(reserved);
+ DRIDrvMsg(pScreen->myNum, X_INFO,
+ "[drm] removed %d reserved context%s for kernel\n",
+ reserved_count, reserved_count > 1 ? "s" : "");
+ }
+
+ /* Make sure signals get unblocked etc. */
+ drmUnlock(pDRIPriv->drmFD, pDRIPriv->myContext);
+ pDRIPriv->lockRefCount = 0;
+ DRIDrvMsg(pScreen->myNum, X_INFO,
+ "[drm] unmapping %d bytes of SAREA %p at %p\n",
+ pDRIInfo->SAREASize,
+ pDRIPriv->hSAREA,
+ pDRIPriv->pSAREA);
+ if (drmUnmap(pDRIPriv->pSAREA, pDRIInfo->SAREASize)) {
+ DRIDrvMsg(pScreen->myNum, X_ERROR,
+ "[drm] unable to unmap %d bytes"
+ " of SAREA %p at %p\n",
+ pDRIInfo->SAREASize,
+ pDRIPriv->hSAREA,
+ pDRIPriv->pSAREA);
+ }
+
+ drmClose(pDRIPriv->drmFD);
+
+ xfree(pDRIPriv);
+ pScreen->devPrivates[DRIScreenPrivIndex].ptr = NULL;
+ }
+}
+
+Bool
+DRIExtensionInit(void)
+{
+ int i;
+ ScreenPtr pScreen;
+
+ if (DRIScreenPrivIndex < 0) {
+ return FALSE;
+ }
+
+ /* Allocate a window private index with a zero sized private area for
+ * each window, then should a window become a DRI window, we'll hang
+ * a DRIWindowPrivateRec off of this private index.
+ */
+ if ((DRIWindowPrivIndex = AllocateWindowPrivateIndex()) < 0)
+ return FALSE;
+
+ DRIDrawablePrivResType = CreateNewResourceType(DRIDrawablePrivDelete);
+ DRIContextPrivResType = CreateNewResourceType(DRIContextPrivDelete);
+
+ for (i = 0; i < screenInfo.numScreens; i++)
+ {
+ pScreen = screenInfo.screens[i];
+ if (!AllocateWindowPrivate(pScreen, DRIWindowPrivIndex, 0))
+ return FALSE;
+ }
+
+ RegisterBlockAndWakeupHandlers(DRIBlockHandler, DRIWakeupHandler, NULL);
+
+ return TRUE;
+}
+
+void
+DRIReset(void)
+{
+ /*
+ * This stub routine is called when the X Server recycles, resources
+ * allocated by DRIExtensionInit need to be managed here.
+ *
+ * Currently this routine is a stub because all the interesting resources
+ * are managed via the screen init process.
+ */
+}
+
+Bool
+DRIQueryDirectRenderingCapable(ScreenPtr pScreen, Bool* isCapable)
+{
+ DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
+
+ if (pDRIPriv)
+ *isCapable = pDRIPriv->directRenderingSupport;
+ else
+ *isCapable = FALSE;
+
+ return TRUE;
+}
+
+Bool
+DRIOpenConnection(ScreenPtr pScreen, drm_handle_t * hSAREA, char **busIdString)
+{
+ DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
+
+ *hSAREA = pDRIPriv->hSAREA;
+ *busIdString = pDRIPriv->pDriverInfo->busIdString;
+
+ return TRUE;
+}
+
+Bool
+DRIAuthConnection(ScreenPtr pScreen, drm_magic_t magic)
+{
+ DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
+
+ if (drmAuthMagic(pDRIPriv->drmFD, magic)) return FALSE;
+ return TRUE;
+}
+
+Bool
+DRICloseConnection(ScreenPtr pScreen)
+{
+ return TRUE;
+}
+
+Bool
+DRIGetClientDriverName(ScreenPtr pScreen,
+ int *ddxDriverMajorVersion,
+ int *ddxDriverMinorVersion,
+ int *ddxDriverPatchVersion,
+ char **clientDriverName)
+{
+ DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
+
+ *ddxDriverMajorVersion = pDRIPriv->pDriverInfo->ddxDriverMajorVersion;
+ *ddxDriverMinorVersion = pDRIPriv->pDriverInfo->ddxDriverMinorVersion;
+ *ddxDriverPatchVersion = pDRIPriv->pDriverInfo->ddxDriverPatchVersion;
+ *clientDriverName = pDRIPriv->pDriverInfo->clientDriverName;
+
+ return TRUE;
+}
+
+/* DRICreateContextPriv and DRICreateContextPrivFromHandle are helper
+ functions that layer on drmCreateContext and drmAddContextTag.
+
+ DRICreateContextPriv always creates a kernel drm_context_t and then calls
+ DRICreateContextPrivFromHandle to create a DRIContextPriv structure for
+ DRI tracking. For the SIGIO handler, the drm_context_t is associated with
+ DRIContextPrivPtr. Any special flags are stored in the DRIContextPriv
+ area and are passed to the kernel (if necessary).
+
+ DRICreateContextPriv returns a pointer to newly allocated
+ DRIContextPriv, and returns the kernel drm_context_t in pHWContext. */
+
+DRIContextPrivPtr
+DRICreateContextPriv(ScreenPtr pScreen,
+ drm_context_t * pHWContext,
+ DRIContextFlags flags)
+{
+ DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
+
+ if (drmCreateContext(pDRIPriv->drmFD, pHWContext)) {
+ return NULL;
+ }
+
+ return DRICreateContextPrivFromHandle(pScreen, *pHWContext, flags);
+}
+
+DRIContextPrivPtr
+DRICreateContextPrivFromHandle(ScreenPtr pScreen,
+ drm_context_t hHWContext,
+ DRIContextFlags flags)
+{
+ DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
+ DRIContextPrivPtr pDRIContextPriv;
+ int contextPrivSize;
+
+ contextPrivSize = sizeof(DRIContextPrivRec) +
+ pDRIPriv->pDriverInfo->contextSize;
+ if (!(pDRIContextPriv = xcalloc(1, contextPrivSize))) {
+ return NULL;
+ }
+ pDRIContextPriv->pContextStore = (void *)(pDRIContextPriv + 1);
+
+ drmAddContextTag(pDRIPriv->drmFD, hHWContext, pDRIContextPriv);
+
+ pDRIContextPriv->hwContext = hHWContext;
+ pDRIContextPriv->pScreen = pScreen;
+ pDRIContextPriv->flags = flags;
+ pDRIContextPriv->valid3D = FALSE;
+
+ if (flags & DRI_CONTEXT_2DONLY) {
+ if (drmSetContextFlags(pDRIPriv->drmFD,
+ hHWContext,
+ DRM_CONTEXT_2DONLY)) {
+ DRIDrvMsg(pScreen->myNum, X_ERROR,
+ "[drm] failed to set 2D context flag\n");
+ DRIDestroyContextPriv(pDRIContextPriv);
+ return NULL;
+ }
+ }
+ if (flags & DRI_CONTEXT_PRESERVED) {
+ if (drmSetContextFlags(pDRIPriv->drmFD,
+ hHWContext,
+ DRM_CONTEXT_PRESERVED)) {
+ DRIDrvMsg(pScreen->myNum, X_ERROR,
+ "[drm] failed to set preserved flag\n");
+ DRIDestroyContextPriv(pDRIContextPriv);
+ return NULL;
+ }
+ }
+ return pDRIContextPriv;
+}
+
+Bool
+DRIDestroyContextPriv(DRIContextPrivPtr pDRIContextPriv)
+{
+ DRIScreenPrivPtr pDRIPriv;
+
+ if (!pDRIContextPriv) return TRUE;
+
+ pDRIPriv = DRI_SCREEN_PRIV(pDRIContextPriv->pScreen);
+
+ if (!(pDRIContextPriv->flags & DRI_CONTEXT_RESERVED)) {
+ /* Don't delete reserved contexts from
+ kernel area -- the kernel manages its
+ reserved contexts itself. */
+ if (drmDestroyContext(pDRIPriv->drmFD, pDRIContextPriv->hwContext))
+ return FALSE;
+ }
+
+ /* Remove the tag last to prevent a race
+ condition where the context has pending
+ buffers. The context can't be re-used
+ while in this thread, but buffers can be
+ dispatched asynchronously. */
+ drmDelContextTag(pDRIPriv->drmFD, pDRIContextPriv->hwContext);
+ xfree(pDRIContextPriv);
+ return TRUE;
+}
+
+static Bool
+DRICreateDummyContext(ScreenPtr pScreen, Bool needCtxPriv)
+{
+ DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
+ __GLXscreenInfo *pGLXScreen = __glXgetActiveScreen(pScreen->myNum);
+ __GLcontextModes *modes = pGLXScreen->modes;
+ void **pVisualConfigPriv = pGLXScreen->pVisualPriv;
+ DRIContextPrivPtr pDRIContextPriv;
+ void *contextStore;
+ VisualPtr visual;
+ int visNum;
+
+ visual = pScreen->visuals;
+
+ /* Find the X visual that corresponds the the first GLX visual */
+ for (visNum = 0;
+ visNum < pScreen->numVisuals;
+ visNum++, visual++) {
+ if (modes->visualID == visual->vid)
+ break;
+ }
+ if (visNum == pScreen->numVisuals) return FALSE;
+
+ if (!(pDRIContextPriv =
+ DRICreateContextPriv(pScreen,
+ &pDRIPriv->pSAREA->dummy_context, 0))) {
+ return FALSE;
+ }
+
+ contextStore = DRIGetContextStore(pDRIContextPriv);
+ if (pDRIPriv->pDriverInfo->CreateContext && needCtxPriv) {
+ if (!pDRIPriv->pDriverInfo->CreateContext(pScreen, visual,
+ pDRIPriv->pSAREA->dummy_context,
+ *pVisualConfigPriv,
+ (DRIContextType)(long)contextStore)) {
+ DRIDestroyContextPriv(pDRIContextPriv);
+ return FALSE;
+ }
+ }
+
+ pDRIPriv->dummyCtxPriv = pDRIContextPriv;
+ return TRUE;
+}
+
+static void
+DRIDestroyDummyContext(ScreenPtr pScreen, Bool hasCtxPriv)
+{
+ DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
+ DRIContextPrivPtr pDRIContextPriv = pDRIPriv->dummyCtxPriv;
+ void *contextStore;
+
+ if (!pDRIContextPriv) return;
+ if (pDRIPriv->pDriverInfo->DestroyContext && hasCtxPriv) {
+ contextStore = DRIGetContextStore(pDRIContextPriv);
+ pDRIPriv->pDriverInfo->DestroyContext(pDRIContextPriv->pScreen,
+ pDRIContextPriv->hwContext,
+ (DRIContextType)(long)contextStore);
+ }
+
+ DRIDestroyContextPriv(pDRIPriv->dummyCtxPriv);
+ pDRIPriv->dummyCtxPriv = NULL;
+}
+
+Bool
+DRICreateContext(ScreenPtr pScreen, VisualPtr visual,
+ XID context, drm_context_t * pHWContext)
+{
+ DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
+ __GLXscreenInfo *pGLXScreen = __glXgetActiveScreen(pScreen->myNum);
+ __GLcontextModes *modes = pGLXScreen->modes;
+ void **pVisualConfigPriv = pGLXScreen->pVisualPriv;
+ DRIContextPrivPtr pDRIContextPriv;
+ void *contextStore;
+
+ if (pDRIPriv->createDummyCtx && !pDRIPriv->dummyCtxPriv) {
+ if (!DRICreateDummyContext(pScreen, pDRIPriv->createDummyCtxPriv)) {
+ DRIDrvMsg(pScreen->myNum, X_INFO,
+ "[drm] Could not create dummy context\n");
+ return FALSE;
+ }
+ }
+
+ /* Find the GLX visual associated with the one requested */
+ for (modes = pGLXScreen->modes; modes != NULL; modes = modes->next) {
+ if (modes->visualID == visual->vid)
+ break;
+ pVisualConfigPriv++;
+ }
+
+ if (modes == NULL) {
+ /* No matching GLX visual found */
+ return FALSE;
+ }
+
+ if (!(pDRIContextPriv = DRICreateContextPriv(pScreen, pHWContext, 0))) {
+ return FALSE;
+ }
+
+ contextStore = DRIGetContextStore(pDRIContextPriv);
+ if (pDRIPriv->pDriverInfo->CreateContext) {
+ if (!((*pDRIPriv->pDriverInfo->CreateContext)(pScreen, visual,
+ *pHWContext, *pVisualConfigPriv,
+ (DRIContextType)(long)contextStore))) {
+ DRIDestroyContextPriv(pDRIContextPriv);
+ return FALSE;
+ }
+ }
+
+ /* track this in case the client dies before cleanup */
+ AddResource(context, DRIContextPrivResType, (pointer)pDRIContextPriv);
+
+ return TRUE;
+}
+
+Bool
+DRIDestroyContext(ScreenPtr pScreen, XID context)
+{
+ FreeResourceByType(context, DRIContextPrivResType, FALSE);
+
+ return TRUE;
+}
+
+/* DRIContextPrivDelete is called by the resource manager. */
+Bool
+DRIContextPrivDelete(pointer pResource, XID id)
+{
+ DRIContextPrivPtr pDRIContextPriv = (DRIContextPrivPtr)pResource;
+ DRIScreenPrivPtr pDRIPriv;
+ void *contextStore;
+
+ pDRIPriv = DRI_SCREEN_PRIV(pDRIContextPriv->pScreen);
+ if (pDRIPriv->pDriverInfo->DestroyContext) {
+ contextStore = DRIGetContextStore(pDRIContextPriv);
+ pDRIPriv->pDriverInfo->DestroyContext(pDRIContextPriv->pScreen,
+ pDRIContextPriv->hwContext,
+ (DRIContextType)(long)contextStore);
+ }
+ return DRIDestroyContextPriv(pDRIContextPriv);
+}
+
+
+/* This walks the drawable timestamp array and invalidates all of them
+ * in the case of transition from private to shared backbuffers. It's
+ * not necessary for correctness, because DRIClipNotify gets called in
+ * time to prevent any conflict, but the transition from
+ * shared->private is sometimes missed if we don't do this.
+ */
+static void
+DRIClipNotifyAllDrawables(ScreenPtr pScreen)
+{
+ int i;
+ DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
+
+ for( i=0; i < pDRIPriv->pDriverInfo->maxDrawableTableEntry; i++) {
+ pDRIPriv->pSAREA->drawableTable[i].stamp = DRIDrawableValidationStamp++;
+ }
+}
+
+
+static void
+DRITransitionToSharedBuffers(ScreenPtr pScreen)
+{
+ DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
+ DRIInfoPtr pDRIInfo = pDRIPriv->pDriverInfo;
+
+ DRIClipNotifyAllDrawables( pScreen );
+
+ if (pDRIInfo->TransitionSingleToMulti3D)
+ pDRIInfo->TransitionSingleToMulti3D( pScreen );
+}
+
+
+static void
+DRITransitionToPrivateBuffers(ScreenPtr pScreen)
+{
+ DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
+ DRIInfoPtr pDRIInfo = pDRIPriv->pDriverInfo;
+
+ DRIClipNotifyAllDrawables( pScreen );
+
+ if (pDRIInfo->TransitionMultiToSingle3D)
+ pDRIInfo->TransitionMultiToSingle3D( pScreen );
+}
+
+
+static void
+DRITransitionTo3d(ScreenPtr pScreen)
+{
+ DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
+ DRIInfoPtr pDRIInfo = pDRIPriv->pDriverInfo;
+
+ DRIClipNotifyAllDrawables( pScreen );
+
+ if (pDRIInfo->TransitionTo3d)
+ pDRIInfo->TransitionTo3d( pScreen );
+}
+
+static void
+DRITransitionTo2d(ScreenPtr pScreen)
+{
+ DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
+ DRIInfoPtr pDRIInfo = pDRIPriv->pDriverInfo;
+
+ DRIClipNotifyAllDrawables( pScreen );
+
+ if (pDRIInfo->TransitionTo2d)
+ pDRIInfo->TransitionTo2d( pScreen );
+}
+
+
+Bool
+DRICreateDrawable(ScreenPtr pScreen, Drawable id,
+ DrawablePtr pDrawable, drm_drawable_t * hHWDrawable)
+{
+ DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
+ DRIDrawablePrivPtr pDRIDrawablePriv;
+ WindowPtr pWin;
+
+ if (pDrawable->type == DRAWABLE_WINDOW) {
+ pWin = (WindowPtr)pDrawable;
+ if ((pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pWin))) {
+ pDRIDrawablePriv->refCount++;
+ }
+ else {
+ /* allocate a DRI Window Private record */
+ if (!(pDRIDrawablePriv = xalloc(sizeof(DRIDrawablePrivRec)))) {
+ return FALSE;
+ }
+
+ /* Only create a drm_drawable_t once */
+ if (drmCreateDrawable(pDRIPriv->drmFD, hHWDrawable)) {
+ xfree(pDRIDrawablePriv);
+ return FALSE;
+ }
+
+ /* add it to the list of DRI drawables for this screen */
+ pDRIDrawablePriv->hwDrawable = *hHWDrawable;
+ pDRIDrawablePriv->pScreen = pScreen;
+ pDRIDrawablePriv->refCount = 1;
+ pDRIDrawablePriv->drawableIndex = -1;
+
+ /* save private off of preallocated index */
+ pWin->devPrivates[DRIWindowPrivIndex].ptr =
+ (pointer)pDRIDrawablePriv;
+
+ switch (++pDRIPriv->nrWindows) {
+ case 1:
+ DRITransitionTo3d( pScreen );
+ break;
+ case 2:
+ DRITransitionToSharedBuffers( pScreen );
+ break;
+ default:
+ break;
+ }
+
+ /* track this in case this window is destroyed */
+ AddResource(id, DRIDrawablePrivResType, (pointer)pWin);
+ }
+ }
+ else { /* pixmap (or for GLX 1.3, a PBuffer) */
+ /* NOT_DONE */
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+Bool
+DRIDestroyDrawable(ScreenPtr pScreen, Drawable id, DrawablePtr pDrawable)
+{
+ DRIDrawablePrivPtr pDRIDrawablePriv;
+ WindowPtr pWin;
+
+
+ if (pDrawable->type == DRAWABLE_WINDOW) {
+ pWin = (WindowPtr)pDrawable;
+ pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pWin);
+ pDRIDrawablePriv->refCount--;
+ if (pDRIDrawablePriv->refCount <= 0) {
+ /* This calls back DRIDrawablePrivDelete which frees private area */
+ FreeResourceByType(id, DRIDrawablePrivResType, FALSE);
+ }
+ }
+ else { /* pixmap (or for GLX 1.3, a PBuffer) */
+ /* NOT_DONE */
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+Bool
+DRIDrawablePrivDelete(pointer pResource, XID id)
+{
+ DrawablePtr pDrawable = (DrawablePtr)pResource;
+ DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pDrawable->pScreen);
+ DRIDrawablePrivPtr pDRIDrawablePriv;
+ WindowPtr pWin;
+
+ if (pDrawable->type == DRAWABLE_WINDOW) {
+ pWin = (WindowPtr)pDrawable;
+ pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pWin);
+
+ if (pDRIDrawablePriv->drawableIndex != -1) {
+ /* bump stamp to force outstanding 3D requests to resync */
+ pDRIPriv->pSAREA->drawableTable[pDRIDrawablePriv->drawableIndex].stamp
+ = DRIDrawableValidationStamp++;
+
+ /* release drawable table entry */
+ pDRIPriv->DRIDrawables[pDRIDrawablePriv->drawableIndex] = NULL;
+ }
+
+ if (drmDestroyDrawable(pDRIPriv->drmFD,
+ pDRIDrawablePriv->hwDrawable)) {
+ return FALSE;
+ }
+ xfree(pDRIDrawablePriv);
+ pWin->devPrivates[DRIWindowPrivIndex].ptr = NULL;
+
+ switch (--pDRIPriv->nrWindows) {
+ case 0:
+ DRITransitionTo2d( pDrawable->pScreen );
+ break;
+ case 1:
+ DRITransitionToPrivateBuffers( pDrawable->pScreen );
+ break;
+ default:
+ break;
+ }
+ }
+ else { /* pixmap (or for GLX 1.3, a PBuffer) */
+ /* NOT_DONE */
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+Bool
+DRIGetDrawableInfo(ScreenPtr pScreen,
+ DrawablePtr pDrawable,
+ unsigned int* index,
+ unsigned int* stamp,
+ int* X,
+ int* Y,
+ int* W,
+ int* H,
+ int* numClipRects,
+ drm_clip_rect_t ** pClipRects,
+ int* backX,
+ int* backY,
+ int* numBackClipRects,
+ drm_clip_rect_t ** pBackClipRects)
+{
+ DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
+ DRIDrawablePrivPtr pDRIDrawablePriv, pOldDrawPriv;
+ WindowPtr pWin, pOldWin;
+ int i;
+
+ printf("maxDrawableTableEntry = %d\n", pDRIPriv->pDriverInfo->maxDrawableTableEntry);
+
+ if (pDrawable->type == DRAWABLE_WINDOW) {
+ pWin = (WindowPtr)pDrawable;
+ if ((pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pWin))) {
+
+ /* Manage drawable table */
+ if (pDRIDrawablePriv->drawableIndex == -1) { /* load SAREA table */
+
+ /* Search table for empty entry */
+ i = 0;
+ while (i < pDRIPriv->pDriverInfo->maxDrawableTableEntry) {
+ if (!(pDRIPriv->DRIDrawables[i])) {
+ pDRIPriv->DRIDrawables[i] = pDrawable;
+ pDRIDrawablePriv->drawableIndex = i;
+ pDRIPriv->pSAREA->drawableTable[i].stamp =
+ DRIDrawableValidationStamp++;
+ break;
+ }
+ i++;
+ }
+
+ /* Search table for oldest entry */
+ if (i == pDRIPriv->pDriverInfo->maxDrawableTableEntry) {
+ unsigned int oldestStamp = ~0;
+ int oldestIndex = 0;
+ i = pDRIPriv->pDriverInfo->maxDrawableTableEntry;
+ while (i--) {
+ if (pDRIPriv->pSAREA->drawableTable[i].stamp <
+ oldestStamp) {
+ oldestIndex = i;
+ oldestStamp =
+ pDRIPriv->pSAREA->drawableTable[i].stamp;
+ }
+ }
+ pDRIDrawablePriv->drawableIndex = oldestIndex;
+
+ /* release oldest drawable table entry */
+ pOldWin = (WindowPtr)pDRIPriv->DRIDrawables[oldestIndex];
+ pOldDrawPriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pOldWin);
+ pOldDrawPriv->drawableIndex = -1;
+
+ /* claim drawable table entry */
+ pDRIPriv->DRIDrawables[oldestIndex] = pDrawable;
+
+ /* validate SAREA entry */
+ pDRIPriv->pSAREA->drawableTable[oldestIndex].stamp =
+ DRIDrawableValidationStamp++;
+
+ /* check for stamp wrap around */
+ if (oldestStamp > DRIDrawableValidationStamp) {
+
+ /* walk SAREA table and invalidate all drawables */
+ for( i=0;
+ i < pDRIPriv->pDriverInfo->maxDrawableTableEntry;
+ i++) {
+ pDRIPriv->pSAREA->drawableTable[i].stamp =
+ DRIDrawableValidationStamp++;
+ }
+ }
+ }
+
+ /* If the driver wants to be notified when the index is
+ * set for a drawable, let it know now.
+ */
+ if (pDRIPriv->pDriverInfo->SetDrawableIndex)
+ pDRIPriv->pDriverInfo->SetDrawableIndex(pWin,
+ pDRIDrawablePriv->drawableIndex);
+
+ /* reinit drawable ID if window is visible */
+ if ((pWin->viewable) &&
+ (pDRIPriv->pDriverInfo->bufferRequests != DRI_NO_WINDOWS))
+ {
+ (*pDRIPriv->pDriverInfo->InitBuffers)(pWin,
+ &pWin->clipList, pDRIDrawablePriv->drawableIndex);
+ }
+ }
+
+ *index = pDRIDrawablePriv->drawableIndex;
+ *stamp = pDRIPriv->pSAREA->drawableTable[*index].stamp;
+ *X = (int)(pWin->drawable.x);
+ *Y = (int)(pWin->drawable.y);
+#if 0
+ *W = (int)(pWin->winSize.extents.x2 - pWin->winSize.extents.x1);
+ *H = (int)(pWin->winSize.extents.y2 - pWin->winSize.extents.y1);
+#endif
+ *W = (int)(pWin->drawable.width);
+ *H = (int)(pWin->drawable.height);
+ *numClipRects = REGION_NUM_RECTS(&pWin->clipList);
+ *pClipRects = (drm_clip_rect_t *)REGION_RECTS(&pWin->clipList);
+
+ if (!*numClipRects && pDRIPriv->fullscreen) {
+ /* use fake full-screen clip rect */
+ pDRIPriv->fullscreen_rect.x1 = *X;
+ pDRIPriv->fullscreen_rect.y1 = *Y;
+ pDRIPriv->fullscreen_rect.x2 = *X + *W;
+ pDRIPriv->fullscreen_rect.y2 = *Y + *H;
+
+ *numClipRects = 1;
+ *pClipRects = &pDRIPriv->fullscreen_rect;
+ }
+
+ *backX = *X;
+ *backY = *Y;
+
+ if (pDRIPriv->nrWindows == 1 && *numClipRects) {
+ /* Use a single cliprect. */
+
+ int x0 = *X;
+ int y0 = *Y;
+ int x1 = x0 + *W;
+ int y1 = y0 + *H;
+
+ if (x0 < 0) x0 = 0;
+ if (y0 < 0) y0 = 0;
+ if (x1 > pScreen->width) x1 = pScreen->width;
+ if (y1 > pScreen->height) y1 = pScreen->height;
+
+ pDRIPriv->private_buffer_rect.x1 = x0;
+ pDRIPriv->private_buffer_rect.y1 = y0;
+ pDRIPriv->private_buffer_rect.x2 = x1;
+ pDRIPriv->private_buffer_rect.y2 = y1;
+
+ *numBackClipRects = 1;
+ *pBackClipRects = &(pDRIPriv->private_buffer_rect);
+ } else {
+ /* Use the frontbuffer cliprects for back buffers. */
+ *numBackClipRects = 0;
+ *pBackClipRects = 0;
+ }
+ }
+ else {
+ /* Not a DRIDrawable */
+ return FALSE;
+ }
+ }
+ else { /* pixmap (or for GLX 1.3, a PBuffer) */
+ /* NOT_DONE */
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+Bool
+DRIGetDeviceInfo(ScreenPtr pScreen,
+ drm_handle_t * hFrameBuffer,
+ int* fbOrigin,
+ int* fbSize,
+ int* fbStride,
+ int* devPrivateSize,
+ void** pDevPrivate)
+{
+ DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
+
+ *hFrameBuffer = pDRIPriv->hFrameBuffer;
+ *fbOrigin = 0;
+ *fbSize = pDRIPriv->pDriverInfo->frameBufferSize;
+ *fbStride = pDRIPriv->pDriverInfo->frameBufferStride;
+ *devPrivateSize = pDRIPriv->pDriverInfo->devPrivateSize;
+ *pDevPrivate = pDRIPriv->pDriverInfo->devPrivate;
+
+ return TRUE;
+}
+
+DRIInfoPtr
+DRICreateInfoRec(void)
+{
+ DRIInfoPtr inforec = (DRIInfoPtr)xcalloc(1, sizeof(DRIInfoRec));
+ if (!inforec) return NULL;
+
+ /* Initialize defaults */
+ inforec->busIdString = NULL;
+
+ /* Wrapped function defaults */
+ inforec->wrap.WakeupHandler = DRIDoWakeupHandler;
+ inforec->wrap.BlockHandler = DRIDoBlockHandler;
+ inforec->wrap.WindowExposures = DRIWindowExposures;
+ inforec->wrap.CopyWindow = DRICopyWindow;
+ inforec->wrap.ValidateTree = DRIValidateTree;
+ inforec->wrap.PostValidateTree = DRIPostValidateTree;
+ inforec->wrap.ClipNotify = DRIClipNotify;
+ inforec->wrap.AdjustFrame = DRIAdjustFrame;
+
+ inforec->TransitionTo2d = 0;
+ inforec->TransitionTo3d = 0;
+ inforec->SetDrawableIndex = 0;
+
+ return inforec;
+}
+
+void
+DRIDestroyInfoRec(DRIInfoPtr DRIInfo)
+{
+ if (DRIInfo->busIdString) xfree(DRIInfo->busIdString);
+ xfree((char*)DRIInfo);
+}
+
+
+void
+DRIWakeupHandler(pointer wakeupData, int result, pointer pReadmask)
+{
+ int i;
+
+ for (i = 0; i < screenInfo.numScreens; i++) {
+ ScreenPtr pScreen = screenInfo.screens[i];
+ DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
+
+ if (pDRIPriv &&
+ pDRIPriv->pDriverInfo->wrap.WakeupHandler)
+ (*pDRIPriv->pDriverInfo->wrap.WakeupHandler)(i, wakeupData,
+ result, pReadmask);
+ }
+}
+
+void
+DRIBlockHandler(pointer blockData, OSTimePtr pTimeout, pointer pReadmask)
+{
+ int i;
+
+ for (i = 0; i < screenInfo.numScreens; i++) {
+ ScreenPtr pScreen = screenInfo.screens[i];
+ DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
+
+ if (pDRIPriv &&
+ pDRIPriv->pDriverInfo->wrap.BlockHandler)
+ (*pDRIPriv->pDriverInfo->wrap.BlockHandler)(i, blockData,
+ pTimeout, pReadmask);
+ }
+}
+
+void
+DRIDoWakeupHandler(int screenNum, pointer wakeupData,
+ unsigned long result, pointer pReadmask)
+{
+ ScreenPtr pScreen = screenInfo.screens[screenNum];
+ DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
+
+ DRILock(pScreen, 0);
+ if (pDRIPriv->pDriverInfo->driverSwapMethod == DRI_HIDE_X_CONTEXT) {
+ /* hide X context by swapping 2D component here */
+ (*pDRIPriv->pDriverInfo->SwapContext)(pScreen,
+ DRI_3D_SYNC,
+ DRI_2D_CONTEXT,
+ pDRIPriv->partial3DContextStore,
+ DRI_2D_CONTEXT,
+ pDRIPriv->hiddenContextStore);
+ }
+}
+
+void
+DRIDoBlockHandler(int screenNum, pointer blockData,
+ pointer pTimeout, pointer pReadmask)
+{
+ ScreenPtr pScreen = screenInfo.screens[screenNum];
+ DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
+
+ if (pDRIPriv->pDriverInfo->driverSwapMethod == DRI_HIDE_X_CONTEXT) {
+ /* hide X context by swapping 2D component here */
+ (*pDRIPriv->pDriverInfo->SwapContext)(pScreen,
+ DRI_2D_SYNC,
+ DRI_NO_CONTEXT,
+ NULL,
+ DRI_2D_CONTEXT,
+ pDRIPriv->partial3DContextStore);
+ }
+ DRIUnlock(pScreen);
+}
+
+void
+DRISwapContext(int drmFD, void *oldctx, void *newctx)
+{
+ DRIContextPrivPtr oldContext = (DRIContextPrivPtr)oldctx;
+ DRIContextPrivPtr newContext = (DRIContextPrivPtr)newctx;
+ ScreenPtr pScreen = newContext->pScreen;
+ DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
+ void* oldContextStore = NULL;
+ DRIContextType oldContextType;
+ void* newContextStore = NULL;
+ DRIContextType newContextType;
+ DRISyncType syncType;
+#ifdef DEBUG
+ static int count = 0;
+#endif
+
+ if (!newContext) {
+ DRIDrvMsg(pScreen->myNum, X_ERROR,
+ "[DRI] Context Switch Error: oldContext=%x, newContext=%x\n",
+ oldContext, newContext);
+ return;
+ }
+
+#ifdef DEBUG
+ /* usefull for debugging, just print out after n context switches */
+ if (!count || !(count % 1)) {
+ DRIDrvMsg(pScreen->myNum, X_INFO,
+ "[DRI] Context switch %5d from %p/0x%08x (%d)\n",
+ count,
+ oldContext,
+ oldContext ? oldContext->flags : 0,
+ oldContext ? oldContext->hwContext : -1);
+ DRIDrvMsg(pScreen->myNum, X_INFO,
+ "[DRI] Context switch %5d to %p/0x%08x (%d)\n",
+ count,
+ newContext,
+ newContext ? newContext->flags : 0,
+ newContext ? newContext->hwContext : -1);
+ }
+ ++count;
+#endif
+
+ if (!pDRIPriv->pDriverInfo->SwapContext) {
+ DRIDrvMsg(pScreen->myNum, X_ERROR,
+ "[DRI] DDX driver missing context swap call back\n");
+ return;
+ }
+
+ if (pDRIPriv->pDriverInfo->driverSwapMethod == DRI_HIDE_X_CONTEXT) {
+
+ /* only 3D contexts are swapped in this case */
+ if (oldContext) {
+ oldContextStore = DRIGetContextStore(oldContext);
+ oldContext->valid3D = TRUE;
+ oldContextType = DRI_3D_CONTEXT;
+ } else {
+ oldContextType = DRI_NO_CONTEXT;
+ }
+ newContextStore = DRIGetContextStore(newContext);
+ if ((newContext->valid3D) &&
+ (newContext->hwContext != pDRIPriv->myContext)) {
+ newContextType = DRI_3D_CONTEXT;
+ }
+ else {
+ newContextType = DRI_2D_CONTEXT;
+ }
+ syncType = DRI_3D_SYNC;
+ }
+ else /* default: driverSwapMethod == DRI_SERVER_SWAP */ {
+
+ /* optimize 2D context swaps */
+
+ if (newContext->flags & DRI_CONTEXT_2DONLY) {
+ /* go from 3D context to 2D context and only save 2D
+ * subset of 3D state
+ */
+ oldContextStore = DRIGetContextStore(oldContext);
+ oldContextType = DRI_2D_CONTEXT;
+ newContextStore = DRIGetContextStore(newContext);
+ newContextType = DRI_2D_CONTEXT;
+ syncType = DRI_3D_SYNC;
+ pDRIPriv->lastPartial3DContext = oldContext;
+ }
+ else if (oldContext->flags & DRI_CONTEXT_2DONLY) {
+ if (pDRIPriv->lastPartial3DContext == newContext) {
+ /* go from 2D context back to previous 3D context and
+ * only restore 2D subset of previous 3D state
+ */
+ oldContextStore = DRIGetContextStore(oldContext);
+ oldContextType = DRI_2D_CONTEXT;
+ newContextStore = DRIGetContextStore(newContext);
+ newContextType = DRI_2D_CONTEXT;
+ syncType = DRI_2D_SYNC;
+ }
+ else {
+ /* go from 2D context to a different 3D context */
+
+ /* call DDX driver to do partial restore */
+ oldContextStore = DRIGetContextStore(oldContext);
+ newContextStore =
+ DRIGetContextStore(pDRIPriv->lastPartial3DContext);
+ (*pDRIPriv->pDriverInfo->SwapContext)(pScreen,
+ DRI_2D_SYNC,
+ DRI_2D_CONTEXT,
+ oldContextStore,
+ DRI_2D_CONTEXT,
+ newContextStore);
+
+ /* now setup for a complete 3D swap */
+ oldContextStore = newContextStore;
+ oldContext->valid3D = TRUE;
+ oldContextType = DRI_3D_CONTEXT;
+ newContextStore = DRIGetContextStore(newContext);
+ if ((newContext->valid3D) &&
+ (newContext->hwContext != pDRIPriv->myContext)) {
+ newContextType = DRI_3D_CONTEXT;
+ }
+ else {
+ newContextType = DRI_2D_CONTEXT;
+ }
+ syncType = DRI_NO_SYNC;
+ }
+ }
+ else {
+ /* now setup for a complete 3D swap */
+ oldContextStore = newContextStore;
+ oldContext->valid3D = TRUE;
+ oldContextType = DRI_3D_CONTEXT;
+ newContextStore = DRIGetContextStore(newContext);
+ if ((newContext->valid3D) &&
+ (newContext->hwContext != pDRIPriv->myContext)) {
+ newContextType = DRI_3D_CONTEXT;
+ }
+ else {
+ newContextType = DRI_2D_CONTEXT;
+ }
+ syncType = DRI_3D_SYNC;
+ }
+ }
+
+ /* call DDX driver to perform the swap */
+ (*pDRIPriv->pDriverInfo->SwapContext)(pScreen,
+ syncType,
+ oldContextType,
+ oldContextStore,
+ newContextType,
+ newContextStore);
+}
+
+void*
+DRIGetContextStore(DRIContextPrivPtr context)
+{
+ return((void *)context->pContextStore);
+}
+
+void
+DRIWindowExposures(WindowPtr pWin, RegionPtr prgn, RegionPtr bsreg)
+{
+ ScreenPtr pScreen = pWin->drawable.pScreen;
+ DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
+ DRIDrawablePrivPtr pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pWin);
+
+ if(pDRIDrawablePriv) {
+ (*pDRIPriv->pDriverInfo->InitBuffers)(pWin, prgn,
+ pDRIDrawablePriv->drawableIndex);
+ }
+
+ /* call lower wrapped functions */
+ if (pDRIPriv && pDRIPriv->wrap.WindowExposures) {
+
+ /* unwrap */
+ pScreen->WindowExposures = pDRIPriv->wrap.WindowExposures;
+
+ /* call lower layers */
+ (*pScreen->WindowExposures)(pWin, prgn, bsreg);
+
+ /* rewrap */
+ pDRIPriv->wrap.WindowExposures = pScreen->WindowExposures;
+ pScreen->WindowExposures = DRIWindowExposures;
+ }
+}
+
+
+static int
+DRITreeTraversal(WindowPtr pWin, pointer data)
+{
+ DRIDrawablePrivPtr pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pWin);
+
+ if(pDRIDrawablePriv) {
+ ScreenPtr pScreen = pWin->drawable.pScreen;
+ DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
+ RegionPtr reg = (RegionPtr)data;
+
+ REGION_UNION(pScreen, reg, reg, &(pWin->clipList));
+
+ if(pDRIPriv->nrWindows == 1)
+ return WT_STOPWALKING;
+ }
+ return WT_WALKCHILDREN;
+}
+
+void
+DRICopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc)
+{
+ ScreenPtr pScreen = pWin->drawable.pScreen;
+ DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
+
+ if(!pDRIPriv) return;
+
+ if(pDRIPriv->nrWindows > 0) {
+ RegionRec reg;
+
+ REGION_NULL(pScreen, &reg);
+ TraverseTree(pWin, DRITreeTraversal, (pointer)(&reg));
+
+ if(REGION_NOTEMPTY(pScreen, &reg)) {
+ REGION_TRANSLATE(pScreen, &reg, ptOldOrg.x - pWin->drawable.x,
+ ptOldOrg.y - pWin->drawable.y);
+ REGION_INTERSECT(pScreen, &reg, &reg, prgnSrc);
+
+ /* The MoveBuffers interface is not ideal */
+ (*pDRIPriv->pDriverInfo->MoveBuffers)(pWin, ptOldOrg, &reg,
+ pDRIPriv->pDriverInfo->ddxDrawableTableEntry);
+ }
+
+ REGION_UNINIT(pScreen, &reg);
+ }
+
+ /* call lower wrapped functions */
+ if(pDRIPriv->wrap.CopyWindow) {
+ /* unwrap */
+ pScreen->CopyWindow = pDRIPriv->wrap.CopyWindow;
+
+ /* call lower layers */
+ (*pScreen->CopyWindow)(pWin, ptOldOrg, prgnSrc);
+
+ /* rewrap */
+ pDRIPriv->wrap.CopyWindow = pScreen->CopyWindow;
+ pScreen->CopyWindow = DRICopyWindow;
+ }
+}
+
+static void
+DRIGetSecs(long *secs, long *usecs)
+{
+#ifdef XFree86LOADER
+ getsecs(secs,usecs);
+#else
+ struct timeval tv;
+
+ gettimeofday(&tv, NULL);
+
+ *secs = tv.tv_sec;
+ *usecs = tv.tv_usec;
+#endif
+}
+
+static unsigned long
+DRIComputeMilliSeconds(unsigned long s_secs, unsigned long s_usecs,
+ unsigned long f_secs, unsigned long f_usecs)
+{
+ if (f_usecs < s_usecs) {
+ --f_secs;
+ f_usecs += 1000000;
+ }
+ return (f_secs - s_secs) * 1000 + (f_usecs - s_usecs) / 1000;
+}
+
+static void
+DRISpinLockTimeout(drmLock *lock, int val, unsigned long timeout /* in mS */)
+{
+ int count = 10000;
+#if !defined(__alpha__) && !defined(__powerpc__)
+ char ret;
+#else
+ int ret;
+#endif
+ long s_secs, s_usecs;
+ long f_secs, f_usecs;
+ long msecs;
+ long prev = 0;
+
+ DRIGetSecs(&s_secs, &s_usecs);
+
+ do {
+ DRM_SPINLOCK_COUNT(lock, val, count, ret);
+ if (!ret) return; /* Got lock */
+ DRIGetSecs(&f_secs, &f_usecs);
+ msecs = DRIComputeMilliSeconds(s_secs, s_usecs, f_secs, f_usecs);
+ if (msecs - prev < 250) count *= 2; /* Not more than 0.5S */
+ } while (msecs < timeout);
+
+ /* Didn't get lock, so take it. The worst
+ that can happen is that there is some
+ garbage written to the wrong part of the
+ framebuffer that a refresh will repair.
+ That's undesirable, but better than
+ locking the server. This should be a
+ very rare event. */
+ DRM_SPINLOCK_TAKE(lock, val);
+}
+
+static void
+DRILockTree(ScreenPtr pScreen)
+{
+ DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
+
+ if(!pDRIPriv) return;
+
+ /* Restore the last known 3D context if the X context is hidden */
+ if (pDRIPriv->pDriverInfo->driverSwapMethod == DRI_HIDE_X_CONTEXT) {
+ (*pDRIPriv->pDriverInfo->SwapContext)(pScreen,
+ DRI_2D_SYNC,
+ DRI_NO_CONTEXT,
+ NULL,
+ DRI_2D_CONTEXT,
+ pDRIPriv->partial3DContextStore);
+ }
+
+ /* Call kernel to release lock */
+ DRIUnlock(pScreen);
+
+ /* Grab drawable spin lock: a time out between 10 and 30 seconds is
+ appropriate, since this should never time out except in the case of
+ client death while the lock is being held. The timeout must be
+ greater than any reasonable rendering time. */
+ DRISpinLockTimeout(&pDRIPriv->pSAREA->drawable_lock, 1, 10000); /*10 secs*/
+
+ /* Call kernel flush outstanding buffers and relock */
+ DRILock(pScreen, DRM_LOCK_QUIESCENT|DRM_LOCK_FLUSH_ALL);
+
+ /* Switch back to our 2D context if the X context is hidden */
+ if (pDRIPriv->pDriverInfo->driverSwapMethod == DRI_HIDE_X_CONTEXT) {
+ /* hide X context by swapping 2D component here */
+ (*pDRIPriv->pDriverInfo->SwapContext)(pScreen,
+ DRI_3D_SYNC,
+ DRI_2D_CONTEXT,
+ pDRIPriv->partial3DContextStore,
+ DRI_2D_CONTEXT,
+ pDRIPriv->hiddenContextStore);
+ }
+}
+
+/* It appears that somebody is relying on the lock being set even
+ if we aren't touching 3D windows */
+
+#define DRI_BROKEN
+
+static Bool DRIWindowsTouched = FALSE;
+
+int
+DRIValidateTree(WindowPtr pParent, WindowPtr pChild, VTKind kind)
+{
+ ScreenPtr pScreen = pParent->drawable.pScreen;
+ DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
+
+ int returnValue = 1; /* always return 1, not checked by dix/window.c */
+
+ if(!pDRIPriv) return returnValue;
+
+ DRIWindowsTouched = FALSE;
+
+#ifdef DRI_BROKEN
+ if(!DRIWindowsTouched) {
+ DRILockTree(pScreen);
+ DRIWindowsTouched = TRUE;
+ }
+#endif
+
+ /* call lower wrapped functions */
+ if(pDRIPriv->wrap.ValidateTree) {
+ /* unwrap */
+ pScreen->ValidateTree = pDRIPriv->wrap.ValidateTree;
+
+ /* call lower layers */
+ returnValue = (*pScreen->ValidateTree)(pParent, pChild, kind);
+
+ /* rewrap */
+ pDRIPriv->wrap.ValidateTree = pScreen->ValidateTree;
+ pScreen->ValidateTree = DRIValidateTree;
+ }
+
+ return returnValue;
+}
+
+void
+DRIPostValidateTree(WindowPtr pParent, WindowPtr pChild, VTKind kind)
+{
+ ScreenPtr pScreen;
+ DRIScreenPrivPtr pDRIPriv;
+
+ if (pParent) {
+ pScreen = pParent->drawable.pScreen;
+ } else {
+ pScreen = pChild->drawable.pScreen;
+ }
+ if(!(pDRIPriv = DRI_SCREEN_PRIV(pScreen))) return;
+
+ if (pDRIPriv->wrap.PostValidateTree) {
+ /* unwrap */
+ pScreen->PostValidateTree = pDRIPriv->wrap.PostValidateTree;
+
+ /* call lower layers */
+ (*pScreen->PostValidateTree)(pParent, pChild, kind);
+
+ /* rewrap */
+ pDRIPriv->wrap.PostValidateTree = pScreen->PostValidateTree;
+ pScreen->PostValidateTree = DRIPostValidateTree;
+ }
+
+ if (DRIWindowsTouched) {
+ /* Release spin lock */
+ DRM_SPINUNLOCK(&pDRIPriv->pSAREA->drawable_lock, 1);
+ DRIWindowsTouched = FALSE;
+ }
+}
+
+void
+DRIClipNotify(WindowPtr pWin, int dx, int dy)
+{
+ ScreenPtr pScreen = pWin->drawable.pScreen;
+ DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
+ DRIDrawablePrivPtr pDRIDrawablePriv;
+
+ if(!pDRIPriv) return;
+
+ if ((pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pWin))) {
+
+#ifndef DRI_BROKEN
+ if(!DRIWindowsTouched) {
+ DRILockTree(pScreen);
+ DRIWindowsTouched = TRUE;
+ }
+#endif
+
+ pDRIPriv->pSAREA->drawableTable[pDRIDrawablePriv->drawableIndex].stamp
+ = DRIDrawableValidationStamp++;
+ }
+
+ /* call lower wrapped functions */
+ if(pDRIPriv->wrap.ClipNotify) {
+
+ /* unwrap */
+ pScreen->ClipNotify = pDRIPriv->wrap.ClipNotify;
+
+ /* call lower layers */
+ (*pScreen->ClipNotify)(pWin, dx, dy);
+
+ /* rewrap */
+ pDRIPriv->wrap.ClipNotify = pScreen->ClipNotify;
+ pScreen->ClipNotify = DRIClipNotify;
+ }
+}
+
+CARD32
+DRIGetDrawableIndex(WindowPtr pWin)
+{
+ ScreenPtr pScreen = pWin->drawable.pScreen;
+ DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
+ DRIDrawablePrivPtr pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pWin);
+ CARD32 index;
+
+ if (pDRIDrawablePriv) {
+ index = pDRIDrawablePriv->drawableIndex;
+ }
+ else {
+ index = pDRIPriv->pDriverInfo->ddxDrawableTableEntry;
+ }
+
+ return index;
+}
+
+unsigned int
+DRIGetDrawableStamp(ScreenPtr pScreen, CARD32 drawable_index)
+{
+ DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
+ return pDRIPriv->pSAREA->drawableTable[drawable_index].stamp;
+}
+
+
+void
+DRIPrintDrawableLock(ScreenPtr pScreen, char *msg)
+{
+ DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
+
+ ErrorF("%s: %d\n", msg, pDRIPriv->pSAREA->drawable_lock.lock);
+}
+
+void
+DRILock(ScreenPtr pScreen, int flags)
+{
+ DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
+ if(!pDRIPriv) return;
+
+ if (!pDRIPriv->lockRefCount)
+ DRM_LOCK(pDRIPriv->drmFD, pDRIPriv->pSAREA, pDRIPriv->myContext, flags);
+ pDRIPriv->lockRefCount++;
+}
+
+void
+DRIUnlock(ScreenPtr pScreen)
+{
+ DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
+ if(!pDRIPriv) return;
+
+ if (pDRIPriv->lockRefCount > 0) {
+ pDRIPriv->lockRefCount--;
+ }
+ else {
+ ErrorF("DRIUnlock called when not locked\n");
+ return;
+ }
+ if (!pDRIPriv->lockRefCount)
+ DRM_UNLOCK(pDRIPriv->drmFD, pDRIPriv->pSAREA, pDRIPriv->myContext);
+}
+
+void *
+DRIGetSAREAPrivate(ScreenPtr pScreen)
+{
+ DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
+ if (!pDRIPriv) return 0;
+
+ return (void *)(((char*)pDRIPriv->pSAREA)+sizeof(XF86DRISAREARec));
+}
+
+drm_context_t
+DRIGetContext(ScreenPtr pScreen)
+{
+ DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
+ if (!pDRIPriv) return 0;
+
+ return pDRIPriv->myContext;
+}
+
+/* This lets get at the unwrapped functions so that they can correctly
+ * call the lowerlevel functions, and choose whether they will be
+ * called at every level of recursion (eg in validatetree).
+ */
+DRIWrappedFuncsRec *
+DRIGetWrappedFuncs(ScreenPtr pScreen)
+{
+ return &(DRI_SCREEN_PRIV(pScreen)->wrap);
+}
+
+/* note that this returns the library version, not the protocol version */
+void
+DRIQueryVersion(int *majorVersion,
+ int *minorVersion,
+ int *patchVersion)
+{
+ *majorVersion = DRIINFO_MAJOR_VERSION;
+ *minorVersion = DRIINFO_MINOR_VERSION;
+ *patchVersion = DRIINFO_PATCH_VERSION;
+}
+
+static void
+_DRIAdjustFrame(ScrnInfoPtr pScrn, DRIScreenPrivPtr pDRIPriv, int x, int y)
+{
+ pDRIPriv->pSAREA->frame.x = x;
+ pDRIPriv->pSAREA->frame.y = y;
+ pDRIPriv->pSAREA->frame.width = pScrn->frameX1 - x + 1;
+ pDRIPriv->pSAREA->frame.height = pScrn->frameY1 - y + 1;
+}
+
+void
+DRIAdjustFrame(int scrnIndex, int x, int y, int flags)
+{
+ ScreenPtr pScreen = screenInfo.screens[scrnIndex];
+ DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
+ ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+ int px, py;
+
+ if (!pDRIPriv || !pDRIPriv->pSAREA) {
+ DRIDrvMsg(scrnIndex, X_ERROR, "[DRI] No SAREA (%p %p)\n",
+ pDRIPriv, pDRIPriv ? pDRIPriv->pSAREA : NULL);
+ return;
+ }
+
+ if (pDRIPriv->fullscreen) {
+ /* Fix up frame */
+ pScrn->frameX0 = pDRIPriv->pSAREA->frame.x;
+ pScrn->frameY0 = pDRIPriv->pSAREA->frame.y;
+ pScrn->frameX1 = pScrn->frameX0 + pDRIPriv->pSAREA->frame.width - 1;
+ pScrn->frameY1 = pScrn->frameY0 + pDRIPriv->pSAREA->frame.height - 1;
+
+ /* Fix up cursor */
+ miPointerPosition(&px, &py);
+ if (px < pScrn->frameX0) px = pScrn->frameX0;
+ if (px > pScrn->frameX1) px = pScrn->frameX1;
+ if (py < pScrn->frameY0) py = pScrn->frameY0;
+ if (py > pScrn->frameY1) py = pScrn->frameY1;
+ pScreen->SetCursorPosition(pScreen, px, py, TRUE);
+ return;
+ }
+
+ if (pDRIPriv->wrap.AdjustFrame) {
+ /* unwrap */
+ pScrn->AdjustFrame = pDRIPriv->wrap.AdjustFrame;
+ /* call lower layers */
+ (*pScrn->AdjustFrame)(scrnIndex, x, y, flags);
+ /* rewrap */
+ pDRIPriv->wrap.AdjustFrame = pScrn->AdjustFrame;
+ pScrn->AdjustFrame = DRIAdjustFrame;
+ }
+
+ _DRIAdjustFrame(pScrn, pDRIPriv, x, y);
+}
+
+/*
+ * DRIMoveBuffersHelper swaps the regions rects in place leaving you
+ * a region with the rects in the order that you need to blit them,
+ * but it is possibly (likely) an invalid region afterwards. If you
+ * need to use the region again for anything you have to call
+ * REGION_VALIDATE on it, or better yet, save a copy first.
+ */
+
+void
+DRIMoveBuffersHelper(
+ ScreenPtr pScreen,
+ int dx,
+ int dy,
+ int *xdir,
+ int *ydir,
+ RegionPtr reg
+)
+{
+ BoxPtr extents, pbox, firstBox, lastBox;
+ BoxRec tmpBox;
+ int y, nbox;
+
+ extents = REGION_EXTENTS(pScreen, reg);
+ nbox = REGION_NUM_RECTS(reg);
+ pbox = REGION_RECTS(reg);
+
+ if((dy > 0) && (dy < (extents->y2 - extents->y1))) {
+ *ydir = -1;
+ if(nbox > 1) {
+ firstBox = pbox;
+ lastBox = pbox + nbox - 1;
+ while((unsigned long)firstBox < (unsigned long)lastBox) {
+ tmpBox = *firstBox;
+ *firstBox = *lastBox;
+ *lastBox = tmpBox;
+ firstBox++;
+ lastBox--;
+ }
+ }
+ } else *ydir = 1;
+
+ if((dx > 0) && (dx < (extents->x2 - extents->x1))) {
+ *xdir = -1;
+ if(nbox > 1) {
+ firstBox = lastBox = pbox;
+ y = pbox->y1;
+ while(--nbox) {
+ pbox++;
+ if(pbox->y1 == y) lastBox++;
+ else {
+ while((unsigned long)firstBox < (unsigned long)lastBox) {
+ tmpBox = *firstBox;
+ *firstBox = *lastBox;
+ *lastBox = tmpBox;
+ firstBox++;
+ lastBox--;
+ }
+
+ firstBox = lastBox = pbox;
+ y = pbox->y1;
+ }
+ }
+ while((unsigned long)firstBox < (unsigned long)lastBox) {
+ tmpBox = *firstBox;
+ *firstBox = *lastBox;
+ *lastBox = tmpBox;
+ firstBox++;
+ lastBox--;
+ }
+ }
+ } else *xdir = 1;
+
+}
+
+char *
+DRICreatePCIBusID(pciVideoPtr PciInfo)
+{
+ char *busID;
+ int domain;
+ PCITAG tag;
+
+ busID = xalloc(20);
+ if (busID == NULL)
+ return NULL;
+
+ tag = pciTag(PciInfo->bus, PciInfo->device, PciInfo->func);
+ domain = xf86GetPciDomain(tag);
+ snprintf(busID, 20, "pci:%04x:%02x:%02x.%d", domain, PciInfo->bus,
+ PciInfo->device, PciInfo->func);
+ return busID;
+}