From 1c94119ae26b94a60bb2c2b33494ed43c3b8a52f Mon Sep 17 00:00:00 2001 From: marha Date: Sun, 16 May 2010 20:50:58 +0000 Subject: svn merge -r588:HEAD ^/branches/released . --- xorg-server/hw/xfree86/dri/dri.c | 5008 +++++++++++++++++++------------------- 1 file changed, 2504 insertions(+), 2504 deletions(-) (limited to 'xorg-server/hw/xfree86/dri/dri.c') diff --git a/xorg-server/hw/xfree86/dri/dri.c b/xorg-server/hw/xfree86/dri/dri.c index 836967c73..a8b050a94 100644 --- a/xorg-server/hw/xfree86/dri/dri.c +++ b/xorg-server/hw/xfree86/dri/dri.c @@ -1,2504 +1,2504 @@ -/************************************************************************** - -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 - * Rickard E. (Rik) Faith - * - */ - -#ifdef HAVE_XORG_CONFIG_H -#include -#endif - -#include "xf86.h" -#include -#include -#include -#include -#include -#include - -#include -#include -#include "xf86drm.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 -#include "swaprep.h" -#include "xf86str.h" -#include "dri.h" -#include "sarea.h" -#include "dristruct.h" -#include "xf86.h" -#include "xf86drm.h" -#include "mi.h" -#include "mipointer.h" -#include "xf86_OSproc.h" -#include "inputstr.h" -#include "xf86VGAarbiter.h" - -#define PCI_BUS_NO_DOMAIN(bus) ((bus) & 0xffu) - -static int DRIEntPrivIndex = -1; -static int DRIScreenPrivKeyIndex; -static DevPrivateKey DRIScreenPrivKey = &DRIScreenPrivKeyIndex; -static int DRIWindowPrivKeyIndex; -static DevPrivateKey DRIWindowPrivKey = &DRIWindowPrivKeyIndex; -static unsigned long DRIGeneration = 0; -static unsigned int DRIDrawableValidationStamp = 0; - -static RESTYPE DRIDrawablePrivResType; -static RESTYPE DRIContextPrivResType; -static void DRIDestroyDummyContext(ScreenPtr pScreen, Bool hasCtxPriv); - -drmServerInfo DRIDRMServerInfo; - - /* 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); -} - - -static void -DRIOpenDRMCleanup(DRIEntPrivPtr pDRIEntPriv) -{ - if (pDRIEntPriv->pLSAREA != NULL) { - drmUnmap(pDRIEntPriv->pLSAREA, pDRIEntPriv->sAreaSize); - pDRIEntPriv->pLSAREA = NULL; - } - if (pDRIEntPriv->hLSAREA != 0) { - drmRmMap(pDRIEntPriv->drmFD, pDRIEntPriv->hLSAREA); - } - if (pDRIEntPriv->drmFD >= 0) { - drmClose(pDRIEntPriv->drmFD); - pDRIEntPriv->drmFD = 0; - } -} - -int -DRIMasterFD(ScrnInfoPtr pScrn) -{ - return DRI_ENT_PRIV(pScrn)->drmFD; -} - -void * -DRIMasterSareaPointer(ScrnInfoPtr pScrn) -{ - return DRI_ENT_PRIV(pScrn)->pLSAREA; -} - -drm_handle_t -DRIMasterSareaHandle(ScrnInfoPtr pScrn) -{ - return DRI_ENT_PRIV(pScrn)->hLSAREA; -} - - -Bool -DRIOpenDRMMaster(ScrnInfoPtr pScrn, - unsigned long sAreaSize, - const char *busID, - const char *drmDriverName) -{ - drmSetVersion saveSv, sv; - Bool drmWasAvailable; - DRIEntPrivPtr pDRIEntPriv; - DRIEntPrivRec tmp; - drmVersionPtr drmlibv; - int drmlibmajor, drmlibminor; - const char *openBusID; - int count; - int err; - - if (DRIEntPrivIndex == -1) - DRIEntPrivIndex = xf86AllocateEntityPrivateIndex(); - - pDRIEntPriv = DRI_ENT_PRIV(pScrn); - - if (pDRIEntPriv && pDRIEntPriv->drmFD != -1) - return TRUE; - - drmWasAvailable = drmAvailable(); - - memset(&tmp, 0, sizeof(tmp)); - - /* 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. - */ - openBusID = (drmlibmajor == 1 && drmlibminor >= 2) ? busID : NULL; - - tmp.drmFD = -1; - sv.drm_di_major = 1; - sv.drm_di_minor = 1; - sv.drm_dd_major = -1; - - saveSv = sv; - count = 10; - while (count--) { - tmp.drmFD = drmOpen(drmDriverName, openBusID); - - if (tmp.drmFD < 0) { - DRIDrvMsg(-1, X_ERROR, "[drm] drmOpen failed.\n"); - goto out_err; - } - - err = drmSetInterfaceVersion(tmp.drmFD, &sv); - - if (err != -EPERM) - break; - - sv = saveSv; - drmClose(tmp.drmFD); - tmp.drmFD = -1; - usleep(100000); - } - - if (tmp.drmFD <= 0) { - DRIDrvMsg(-1, X_ERROR, "[drm] DRM was busy with another master.\n"); - goto out_err; - } - - if (!drmWasAvailable) { - DRIDrvMsg(-1, X_INFO, - "[drm] loaded kernel module for \"%s\" driver.\n", - drmDriverName); - } - - if (err != 0) { - sv.drm_di_major = 1; - sv.drm_di_minor = 0; - } - - DRIDrvMsg(-1, X_INFO, "[drm] DRM interface version %d.%d\n", - sv.drm_di_major, sv.drm_di_minor); - - if (sv.drm_di_major == 1 && sv.drm_di_minor >= 1) - err = 0; - else - err = drmSetBusid(tmp.drmFD, busID); - - if (err) { - DRIDrvMsg(-1, X_ERROR, "[drm] Could not set DRM device bus ID.\n"); - goto out_err; - } - - /* - * Create a lock-containing sarea. - */ - - if (drmAddMap( tmp.drmFD, 0, sAreaSize, DRM_SHM, - DRM_CONTAINS_LOCK, &tmp.hLSAREA) < 0) { - DRIDrvMsg(-1, X_INFO, "[drm] Could not create SAREA for DRM lock.\n"); - tmp.hLSAREA = 0; - goto out_err; - } - - if (drmMap( tmp.drmFD, tmp.hLSAREA, sAreaSize, - (drmAddressPtr)(&tmp.pLSAREA)) < 0) { - DRIDrvMsg(-1, X_INFO, "[drm] Mapping SAREA for DRM lock failed.\n"); - tmp.pLSAREA = NULL; - goto out_err; - } - - memset(tmp.pLSAREA, 0, sAreaSize); - - /* - * Reserved contexts are handled by the first opened screen. - */ - - tmp.resOwner = NULL; - - if (!pDRIEntPriv) - pDRIEntPriv = xnfcalloc(sizeof(*pDRIEntPriv), 1); - - if (!pDRIEntPriv) { - DRIDrvMsg(-1, X_INFO, "[drm] Failed to allocate memory for " - "DRM device.\n"); - goto out_err; - } - *pDRIEntPriv = tmp; - xf86GetEntityPrivate((pScrn)->entityList[0],DRIEntPrivIndex)->ptr = - pDRIEntPriv; - - DRIDrvMsg(-1, X_INFO, "[drm] DRM open master succeeded.\n"); - return TRUE; - - out_err: - - DRIOpenDRMCleanup(&tmp); - return FALSE; -} - -static void -DRIClipNotifyAllDrawables(ScreenPtr pScreen); - -static void -dri_crtc_notify(ScreenPtr pScreen) -{ - DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); - DRIClipNotifyAllDrawables(pScreen); - xf86_unwrap_crtc_notify(pScreen, pDRIPriv->xf86_crtc_notify); - xf86_crtc_notify(pScreen); - pDRIPriv->xf86_crtc_notify = xf86_wrap_crtc_notify(pScreen, dri_crtc_notify); -} - -Bool -DRIScreenInit(ScreenPtr pScreen, DRIInfoPtr pDRIInfo, int *pDRMFD) -{ - DRIScreenPrivPtr pDRIPriv; - drm_context_t * reserved; - int reserved_count; - int i; - DRIEntPrivPtr pDRIEntPriv; - ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; - DRIContextFlags flags = 0; - DRIContextPrivPtr pDRIContextPriv; - - /* 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 (!xf86VGAarbiterAllowDRI(pScreen)) { - DRIDrvMsg(pScreen->myNum, X_WARNING, - "Direct rendering is not supported when VGA arb is necessary for the device\n"); - return FALSE; - } - -#ifdef PANORAMIX - /* - * If Xinerama is on, don't allow DRI to initialise. It won't be usable - * anyway. - */ - if (!noPanoramiXExtension) { - DRIDrvMsg(pScreen->myNum, X_WARNING, - "Direct rendering is not supported when Xinerama is enabled\n"); - return FALSE; - } -#endif - - if (!DRIOpenDRMMaster(pScrn, pDRIInfo->SAREASize, - pDRIInfo->busIdString, - pDRIInfo->drmDriverName)) - return FALSE; - - pDRIEntPriv = DRI_ENT_PRIV(pScrn); - - if (DRIGeneration != serverGeneration) - DRIGeneration = serverGeneration; - - pDRIPriv = (DRIScreenPrivPtr) xcalloc(1, sizeof(DRIScreenPrivRec)); - if (!pDRIPriv) { - dixSetPrivate(&pScreen->devPrivates, DRIScreenPrivKey, NULL); - return FALSE; - } - - dixSetPrivate(&pScreen->devPrivates, DRIScreenPrivKey, pDRIPriv); - pDRIPriv->drmFD = pDRIEntPriv->drmFD; - pDRIPriv->directRenderingSupport = TRUE; - pDRIPriv->pDriverInfo = pDRIInfo; - pDRIPriv->nrWindows = 0; - pDRIPriv->nrWindowsVisible = 0; - pDRIPriv->fullscreen = NULL; - - pDRIPriv->createDummyCtx = pDRIInfo->createDummyCtx; - pDRIPriv->createDummyCtxPriv = pDRIInfo->createDummyCtxPriv; - - pDRIPriv->grabbedDRILock = FALSE; - pDRIPriv->drmSIGIOHandlerInstalled = FALSE; - *pDRMFD = pDRIPriv->drmFD; - - if (pDRIEntPriv->sAreaGrabbed || pDRIInfo->allocSarea) { - - if (drmAddMap( pDRIPriv->drmFD, - 0, - pDRIPriv->pDriverInfo->SAREASize, - DRM_SHM, - 0, - &pDRIPriv->hSAREA) < 0) - { - pDRIPriv->directRenderingSupport = FALSE; - dixSetPrivate(&pScreen->devPrivates, DRIScreenPrivKey, 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); - - /* Backwards compat. */ - if (drmMap( pDRIPriv->drmFD, - pDRIPriv->hSAREA, - pDRIPriv->pDriverInfo->SAREASize, - (drmAddressPtr)(&pDRIPriv->pSAREA)) < 0) - { - pDRIPriv->directRenderingSupport = FALSE; - dixSetPrivate(&pScreen->devPrivates, DRIScreenPrivKey, NULL); - drmClose(pDRIPriv->drmFD); - DRIDrvMsg(pScreen->myNum, X_INFO, - "[drm] drmMap failed\n"); - return FALSE; - } - DRIDrvMsg(pScreen->myNum, X_INFO, "[drm] mapped SAREA %p to %p\n", - pDRIPriv->hSAREA, pDRIPriv->pSAREA); - memset(pDRIPriv->pSAREA, 0, pDRIPriv->pDriverInfo->SAREASize); - } else { - DRIDrvMsg(pScreen->myNum, X_INFO, "[drm] Using the DRM lock " - "SAREA also for drawables.\n"); - pDRIPriv->hSAREA = pDRIEntPriv->hLSAREA; - pDRIPriv->pSAREA = (XF86DRISAREAPtr) pDRIEntPriv->pLSAREA; - pDRIEntPriv->sAreaGrabbed = TRUE; - } - - pDRIPriv->hLSAREA = pDRIEntPriv->hLSAREA; - pDRIPriv->pLSAREA = pDRIEntPriv->pLSAREA; - - if (!pDRIPriv->pDriverInfo->dontMapFrameBuffer) - { - if (drmAddMap( pDRIPriv->drmFD, - (drm_handle_t)pDRIPriv->pDriverInfo->frameBufferPhysicalAddress, - pDRIPriv->pDriverInfo->frameBufferSize, - DRM_FRAME_BUFFER, - 0, - &pDRIPriv->pDriverInfo->hFrameBuffer) < 0) - { - pDRIPriv->directRenderingSupport = FALSE; - dixSetPrivate(&pScreen->devPrivates, DRIScreenPrivKey, 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->pDriverInfo->hFrameBuffer); - } else { - DRIDrvMsg(pScreen->myNum, X_INFO, - "[drm] framebuffer mapped by ddx driver\n"); - } - - if (pDRIEntPriv->resOwner == NULL) { - pDRIEntPriv->resOwner = pScreen; - - /* 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; - } - - pDRIPriv->pLockRefCount = &pDRIEntPriv->lockRefCount; - pDRIPriv->pLockingContext = &pDRIEntPriv->lockingContext; - - if (!pDRIEntPriv->keepFDOpen) - pDRIEntPriv->keepFDOpen = pDRIInfo->keepFDOpen; - - pDRIEntPriv->refCount++; - - /* 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; - } - - return TRUE; -} - -Bool -DRIFinishScreenInit(ScreenPtr pScreen) -{ - DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); - DRIInfoPtr pDRIInfo = pDRIPriv->pDriverInfo; - - /* 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; - } - - pDRIPriv->DestroyWindow = pScreen->DestroyWindow; - pScreen->DestroyWindow = DRIDestroyWindow; - - pDRIPriv->xf86_crtc_notify = xf86_wrap_crtc_notify(pScreen, - dri_crtc_notify); - - 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; - ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; - DRIEntPrivPtr pDRIEntPriv = DRI_ENT_PRIV(pScrn); - Bool closeMaster; - - if (pDRIPriv) { - - 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 (pDRIPriv->DestroyWindow) { - pScreen->DestroyWindow = pDRIPriv->DestroyWindow; - pDRIPriv->DestroyWindow = NULL; - } - - xf86_unwrap_crtc_notify(pScreen, pDRIPriv->xf86_crtc_notify); - - 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 (pDRIEntPriv->resOwner == pScreen) { - pDRIEntPriv->resOwner = NULL; - - 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->pLockRefCount = NULL; - closeMaster = (--pDRIEntPriv->refCount == 0) && - !pDRIEntPriv->keepFDOpen; - if (closeMaster || pDRIPriv->hSAREA != pDRIEntPriv->hLSAREA) { - 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); - } - } else { - pDRIEntPriv->sAreaGrabbed = FALSE; - } - - if (closeMaster || (pDRIEntPriv->drmFD != pDRIPriv->drmFD)) { - drmClose(pDRIPriv->drmFD); - if (pDRIEntPriv->drmFD == pDRIPriv->drmFD) { - DRIDrvMsg(pScreen->myNum, X_INFO, - "[drm] Closed DRM master.\n"); - pDRIEntPriv->drmFD = -1; - } - } - - xfree(pDRIPriv); - dixSetPrivate(&pScreen->devPrivates, DRIScreenPrivKey, NULL); - } -} - -#define DRM_MSG_VERBOSITY 3 - -static int dri_drm_debug_print(const char *format, va_list ap) -{ - xf86VDrvMsgVerb(-1, X_NONE, DRM_MSG_VERBOSITY, format, ap); - return 0; -} - -static void dri_drm_get_perms(gid_t *group, mode_t *mode) -{ - *group = xf86ConfigDRI.group; - *mode = xf86ConfigDRI.mode; -} - -drmServerInfo DRIDRMServerInfo = { - dri_drm_debug_print, - xf86LoadKernelModule, - dri_drm_get_perms, -}; - -Bool -DRIExtensionInit(void) -{ - if (!DRIScreenPrivKey || DRIGeneration != serverGeneration) { - return FALSE; - } - - DRIDrawablePrivResType = CreateNewResourceType(DRIDrawablePrivDelete, - "DRIDrawable"); - DRIContextPrivResType = CreateNewResourceType(DRIContextPrivDelete, - "DRIContext"); - - if (!DRIDrawablePrivResType || !DRIContextPrivResType) - 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); - DRIContextPrivPtr pDRIContextPriv; - void *contextStore; - - if (!(pDRIContextPriv = - DRICreateContextPriv(pScreen, - &pDRIPriv->pSAREA->dummy_context, 0))) { - return FALSE; - } - - contextStore = DRIGetContextStore(pDRIContextPriv); - if (pDRIPriv->pDriverInfo->CreateContext && needCtxPriv) { - if (!pDRIPriv->pDriverInfo->CreateContext(pScreen, NULL, - pDRIPriv->pSAREA->dummy_context, - NULL, - (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); - 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; - } - } - - if (!(pDRIContextPriv = DRICreateContextPriv(pScreen, pHWContext, 0))) { - return FALSE; - } - - contextStore = DRIGetContextStore(pDRIContextPriv); - if (pDRIPriv->pDriverInfo->CreateContext) { - if (!((*pDRIPriv->pDriverInfo->CreateContext)(pScreen, NULL, - *pHWContext, NULL, - (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 ); -} - - -static int -DRIDCNTreeTraversal(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); - - if (REGION_NUM_RECTS(&pWin->clipList) > 0) { - WindowPtr *pDRIWindows = (WindowPtr*)data; - int i = 0; - - while (pDRIWindows[i]) - i++; - - pDRIWindows[i] = pWin; - - pDRIPriv->nrWalked++; - } - - if (pDRIPriv->nrWindows == pDRIPriv->nrWalked) - return WT_STOPWALKING; - } - - return WT_WALKCHILDREN; -} - -static void -DRIDriverClipNotify(ScreenPtr pScreen) -{ - DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); - - if (pDRIPriv->pDriverInfo->ClipNotify) { - WindowPtr *pDRIWindows = xcalloc(sizeof(WindowPtr), pDRIPriv->nrWindows); - DRIInfoPtr pDRIInfo = pDRIPriv->pDriverInfo; - - if (pDRIPriv->nrWindows > 0) { - pDRIPriv->nrWalked = 0; - TraverseTree(WindowTable[pScreen->myNum], DRIDCNTreeTraversal, - (pointer)pDRIWindows); - } - - pDRIInfo->ClipNotify(pScreen, pDRIWindows, pDRIPriv->nrWindows); - - xfree(pDRIWindows); - } -} - -static void -DRIIncreaseNumberVisible(ScreenPtr pScreen) -{ - DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); - - switch (++pDRIPriv->nrWindowsVisible) { - case 1: - DRITransitionTo3d( pScreen ); - break; - case 2: - DRITransitionToSharedBuffers( pScreen ); - break; - default: - break; - } - - DRIDriverClipNotify(pScreen); -} - -static void -DRIDecreaseNumberVisible(ScreenPtr pScreen) -{ - DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); - - switch (--pDRIPriv->nrWindowsVisible) { - case 0: - DRITransitionTo2d( pScreen ); - break; - case 1: - DRITransitionToPrivateBuffers( pScreen ); - break; - default: - break; - } - - DRIDriverClipNotify(pScreen); -} - -Bool -DRICreateDrawable(ScreenPtr pScreen, ClientPtr client, 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++; - - if (!pDRIDrawablePriv->hwDrawable) { - drmCreateDrawable(pDRIPriv->drmFD, &pDRIDrawablePriv->hwDrawable); - } - } - 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, - &pDRIDrawablePriv->hwDrawable)) { - xfree(pDRIDrawablePriv); - return FALSE; - } - - /* add it to the list of DRI drawables for this screen */ - pDRIDrawablePriv->pScreen = pScreen; - pDRIDrawablePriv->refCount = 1; - pDRIDrawablePriv->drawableIndex = -1; - pDRIDrawablePriv->nrects = REGION_NUM_RECTS(&pWin->clipList); - - /* save private off of preallocated index */ - dixSetPrivate(&pWin->devPrivates, DRIWindowPrivKey, - pDRIDrawablePriv); - pDRIPriv->nrWindows++; - - if (pDRIDrawablePriv->nrects) - DRIIncreaseNumberVisible(pScreen); - } - - /* track this in case the client dies */ - AddResource(FakeClientID(client->index), DRIDrawablePrivResType, - (pointer)(intptr_t)pDrawable->id); - - if (pDRIDrawablePriv->hwDrawable) { - drmUpdateDrawableInfo(pDRIPriv->drmFD, - pDRIDrawablePriv->hwDrawable, - DRM_DRAWABLE_CLIPRECTS, - REGION_NUM_RECTS(&pWin->clipList), - REGION_RECTS(&pWin->clipList)); - *hHWDrawable = pDRIDrawablePriv->hwDrawable; - } - } - else if (pDrawable->type != DRAWABLE_PIXMAP) { /* PBuffer */ - /* NOT_DONE */ - return FALSE; - } - - return TRUE; -} - -static void -DRIDrawablePrivDestroy(WindowPtr pWin) -{ - DRIDrawablePrivPtr pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pWin); - ScreenPtr pScreen; - DRIScreenPrivPtr pDRIPriv; - - if (!pDRIDrawablePriv) - return; - - pScreen = pWin->drawable.pScreen; - pDRIPriv = DRI_SCREEN_PRIV(pScreen); - - 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; - } - - pDRIPriv->nrWindows--; - - if (pDRIDrawablePriv->nrects) - DRIDecreaseNumberVisible(pScreen); - - drmDestroyDrawable(pDRIPriv->drmFD, pDRIDrawablePriv->hwDrawable); - - xfree(pDRIDrawablePriv); - dixSetPrivate(&pWin->devPrivates, DRIWindowPrivKey, NULL); -} - -static Bool -DRIDestroyDrawableCB(pointer value, XID id, pointer data) -{ - if (value == data) { - /* This calls back DRIDrawablePrivDelete which frees private area */ - FreeResourceByType(id, DRIDrawablePrivResType, FALSE); - - return TRUE; - } - - return FALSE; -} - -Bool -DRIDestroyDrawable(ScreenPtr pScreen, ClientPtr client, DrawablePtr pDrawable) -{ - if (pDrawable->type == DRAWABLE_WINDOW) { - LookupClientResourceComplex(client, DRIDrawablePrivResType, - DRIDestroyDrawableCB, - (pointer)(intptr_t)pDrawable->id); - } - else { /* pixmap (or for GLX 1.3, a PBuffer) */ - /* NOT_DONE */ - return FALSE; - } - - return TRUE; -} - -Bool -DRIDrawablePrivDelete(pointer pResource, XID id) -{ - WindowPtr pWin; - int rc; - - /* For DRIDrawablePrivResType, the XID is the client's fake ID. The - * important XID is the value in pResource. */ - id = (XID)(intptr_t)pResource; - rc = dixLookupWindow(&pWin, id, serverClient, DixGetAttrAccess); - - if (rc == Success) { - DRIDrawablePrivPtr pDRIDrwPriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pWin); - - if (!pDRIDrwPriv) - return FALSE; - - if (--pDRIDrwPriv->refCount == 0) - DRIDrawablePrivDestroy(pWin); - - return TRUE; - } - else { /* pixmap (or for GLX 1.3, a PBuffer) */ - /* NOT_DONE */ - return FALSE; - } -} - -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; - -#if 0 - printf("maxDrawableTableEntry = %d\n", pDRIPriv->pDriverInfo->maxDrawableTableEntry); -#endif - - 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->nrWindowsVisible == 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; - - if (y0 >= y1 || x0 >= x1) { - *numBackClipRects = 0; - *pBackClipRects = NULL; - } else { - 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->pDriverInfo->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); - } - - if (pDRIPriv->windowsTouched) - DRM_SPINUNLOCK(&pDRIPriv->pSAREA->drawable_lock, 1); - pDRIPriv->windowsTouched = FALSE; - - 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; - - if (!newContext) { - DRIDrvMsg(pScreen->myNum, X_ERROR, - "[DRI] Context Switch Error: oldContext=%x, newContext=%x\n", - oldContext, newContext); - return; - } - - /* 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); - - if(REGION_NUM_RECTS(&(pWin->clipList)) > 0) { - RegionPtr reg = (RegionPtr)data; - - REGION_UNION(pScreen, reg, reg, &(pWin->clipList)); - pDRIPriv->nrWalked++; - } - - if(pDRIPriv->nrWindows == pDRIPriv->nrWalked) - return WT_STOPWALKING; - } - return WT_WALKCHILDREN; -} - -Bool -DRIDestroyWindow(WindowPtr pWin) -{ - ScreenPtr pScreen = pWin->drawable.pScreen; - DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); - Bool retval = TRUE; - - DRIDrawablePrivDestroy(pWin); - - /* call lower wrapped functions */ - if(pDRIPriv->DestroyWindow) { - /* unwrap */ - pScreen->DestroyWindow = pDRIPriv->DestroyWindow; - - /* call lower layers */ - retval = (*pScreen->DestroyWindow)(pWin); - - /* rewrap */ - pDRIPriv->DestroyWindow = pScreen->DestroyWindow; - pScreen->DestroyWindow = DRIDestroyWindow; - } - - return retval; -} - -void -DRICopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc) -{ - ScreenPtr pScreen = pWin->drawable.pScreen; - DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); - - if(!pDRIPriv) return; - - if(pDRIPriv->nrWindowsVisible > 0) { - RegionRec reg; - - REGION_NULL(pScreen, ®); - pDRIPriv->nrWalked = 0; - TraverseTree(pWin, DRITreeTraversal, (pointer)(®)); - - if(REGION_NOTEMPTY(pScreen, ®)) { - REGION_TRANSLATE(pScreen, ®, ptOldOrg.x - pWin->drawable.x, - ptOldOrg.y - pWin->drawable.y); - REGION_INTERSECT(pScreen, ®, ®, prgnSrc); - - /* The MoveBuffers interface is not ideal */ - (*pDRIPriv->pDriverInfo->MoveBuffers)(pWin, ptOldOrg, ®, - pDRIPriv->pDriverInfo->ddxDrawableTableEntry); - } - - REGION_UNINIT(pScreen, ®); - } - - /* 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) -{ - struct timeval tv; - - gettimeofday(&tv, NULL); - - *secs = tv.tv_sec; - *usecs = tv.tv_usec; -} - -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); - } -} - -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; - - /* 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; - } -} - -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))) { - int nrects = REGION_NUM_RECTS(&pWin->clipList); - - if(!pDRIPriv->windowsTouched) { - DRILockTree(pScreen); - pDRIPriv->windowsTouched = TRUE; - } - - if (nrects && !pDRIDrawablePriv->nrects) - DRIIncreaseNumberVisible(pScreen); - else if (!nrects && pDRIDrawablePriv->nrects) - DRIDecreaseNumberVisible(pScreen); - else - DRIDriverClipNotify(pScreen); - - pDRIDrawablePriv->nrects = nrects; - - pDRIPriv->pSAREA->drawableTable[pDRIDrawablePriv->drawableIndex].stamp - = DRIDrawableValidationStamp++; - - drmUpdateDrawableInfo(pDRIPriv->drmFD, pDRIDrawablePriv->hwDrawable, - DRM_DRAWABLE_CLIPRECTS, - nrects, REGION_RECTS(&pWin->clipList)); - } - - /* 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 || !pDRIPriv->pLockRefCount) return; - - if (!*pDRIPriv->pLockRefCount) { - DRM_LOCK(pDRIPriv->drmFD, pDRIPriv->pLSAREA, pDRIPriv->myContext, flags); - *pDRIPriv->pLockingContext = pDRIPriv->myContext; - } else if (*pDRIPriv->pLockingContext != pDRIPriv->myContext) { - DRIDrvMsg(pScreen->myNum, X_ERROR, - "[DRI] Locking deadlock.\n" - "\tAlready locked with context %d,\n" - "\ttrying to lock with context %d.\n", - pDRIPriv->pLockingContext, - pDRIPriv->myContext); - } - (*pDRIPriv->pLockRefCount)++; -} - -void -DRIUnlock(ScreenPtr pScreen) -{ - DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); - - if(!pDRIPriv || !pDRIPriv->pLockRefCount) return; - - if (*pDRIPriv->pLockRefCount > 0) { - if (pDRIPriv->myContext != *pDRIPriv->pLockingContext) { - DRIDrvMsg(pScreen->myNum, X_ERROR, - "[DRI] Unlocking inconsistency:\n" - "\tContext %d trying to unlock lock held by context %d\n", - pDRIPriv->pLockingContext, - pDRIPriv->myContext); - } - (*pDRIPriv->pLockRefCount)--; - } else { - DRIDrvMsg(pScreen->myNum, X_ERROR, - "DRIUnlock called when not locked.\n"); - return; - } - if (! *pDRIPriv->pLockRefCount) - DRM_UNLOCK(pDRIPriv->drmFD, pDRIPriv->pLSAREA, 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; -} - -void -DRIGetTexOffsetFuncs(ScreenPtr pScreen, - DRITexOffsetStartProcPtr *texOffsetStartFunc, - DRITexOffsetFinishProcPtr *texOffsetFinishFunc) -{ - DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); - - if (!pDRIPriv) return; - - *texOffsetStartFunc = pDRIPriv->pDriverInfo->texOffsetStart; - *texOffsetFinishFunc = pDRIPriv->pDriverInfo->texOffsetFinish; -} - -/* 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 */ - miPointerGetPosition(inputInfo.pointer, &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(inputInfo.pointer, 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(const struct pci_device * dev) -{ - char *busID; - - busID = xalloc(20); - if (busID == NULL) - return NULL; - - snprintf(busID, 20, "pci:%04x:%02x:%02x.%d", dev->domain, dev->bus, - dev->dev, dev->func); - - return busID; -} - -static void drmSIGIOHandler(int interrupt, void *closure) -{ - unsigned long key; - void *value; - ssize_t count; - drm_ctx_t ctx; - typedef void (*_drmCallback)(int, void *, void *); - char buf[256]; - drm_context_t old; - drm_context_t new; - void *oldctx; - void *newctx; - char *pt; - drmHashEntry *entry; - void *hash_table; - - hash_table = drmGetHashTable(); - - if (!hash_table) return; - if (drmHashFirst(hash_table, &key, &value)) { - entry = value; - do { -#if 0 - fprintf(stderr, "Trying %d\n", entry->fd); -#endif - if ((count = read(entry->fd, buf, sizeof(buf) - 1)) > 0) { - buf[count] = '\0'; -#if 0 - fprintf(stderr, "Got %s\n", buf); -#endif - - for (pt = buf; *pt != ' '; ++pt); /* Find first space */ - ++pt; - old = strtol(pt, &pt, 0); - new = strtol(pt, NULL, 0); - oldctx = drmGetContextTag(entry->fd, old); - newctx = drmGetContextTag(entry->fd, new); -#if 0 - fprintf(stderr, "%d %d %p %p\n", old, new, oldctx, newctx); -#endif - ((_drmCallback)entry->f)(entry->fd, oldctx, newctx); - ctx.handle = new; - ioctl(entry->fd, DRM_IOCTL_NEW_CTX, &ctx); - } - } while (drmHashNext(hash_table, &key, &value)); - } -} - - -int drmInstallSIGIOHandler(int fd, void (*f)(int, void *, void *)) -{ - drmHashEntry *entry; - - entry = drmGetEntry(fd); - entry->f = f; - - return xf86InstallSIGIOHandler(fd, drmSIGIOHandler, 0); -} - -int drmRemoveSIGIOHandler(int fd) -{ - drmHashEntry *entry = drmGetEntry(fd); - - entry->f = NULL; - - return xf86RemoveSIGIOHandler(fd); -} +/************************************************************************** + +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 + * Rickard E. (Rik) Faith + * + */ + +#ifdef HAVE_XORG_CONFIG_H +#include +#endif + +#include "xf86.h" +#include +#include +#include +#include +#include +#include + +#include +#include +#include "xf86drm.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 +#include "swaprep.h" +#include "xf86str.h" +#include "dri.h" +#include "sarea.h" +#include "dristruct.h" +#include "xf86.h" +#include "xf86drm.h" +#include "mi.h" +#include "mipointer.h" +#include "xf86_OSproc.h" +#include "inputstr.h" +#include "xf86VGAarbiter.h" + +#define PCI_BUS_NO_DOMAIN(bus) ((bus) & 0xffu) + +static int DRIEntPrivIndex = -1; +static int DRIScreenPrivKeyIndex; +static DevPrivateKey DRIScreenPrivKey = &DRIScreenPrivKeyIndex; +static int DRIWindowPrivKeyIndex; +static DevPrivateKey DRIWindowPrivKey = &DRIWindowPrivKeyIndex; +static unsigned long DRIGeneration = 0; +static unsigned int DRIDrawableValidationStamp = 0; + +static RESTYPE DRIDrawablePrivResType; +static RESTYPE DRIContextPrivResType; +static void DRIDestroyDummyContext(ScreenPtr pScreen, Bool hasCtxPriv); + +drmServerInfo DRIDRMServerInfo; + + /* 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); +} + + +static void +DRIOpenDRMCleanup(DRIEntPrivPtr pDRIEntPriv) +{ + if (pDRIEntPriv->pLSAREA != NULL) { + drmUnmap(pDRIEntPriv->pLSAREA, pDRIEntPriv->sAreaSize); + pDRIEntPriv->pLSAREA = NULL; + } + if (pDRIEntPriv->hLSAREA != 0) { + drmRmMap(pDRIEntPriv->drmFD, pDRIEntPriv->hLSAREA); + } + if (pDRIEntPriv->drmFD >= 0) { + drmClose(pDRIEntPriv->drmFD); + pDRIEntPriv->drmFD = 0; + } +} + +int +DRIMasterFD(ScrnInfoPtr pScrn) +{ + return DRI_ENT_PRIV(pScrn)->drmFD; +} + +void * +DRIMasterSareaPointer(ScrnInfoPtr pScrn) +{ + return DRI_ENT_PRIV(pScrn)->pLSAREA; +} + +drm_handle_t +DRIMasterSareaHandle(ScrnInfoPtr pScrn) +{ + return DRI_ENT_PRIV(pScrn)->hLSAREA; +} + + +Bool +DRIOpenDRMMaster(ScrnInfoPtr pScrn, + unsigned long sAreaSize, + const char *busID, + const char *drmDriverName) +{ + drmSetVersion saveSv, sv; + Bool drmWasAvailable; + DRIEntPrivPtr pDRIEntPriv; + DRIEntPrivRec tmp; + drmVersionPtr drmlibv; + int drmlibmajor, drmlibminor; + const char *openBusID; + int count; + int err; + + if (DRIEntPrivIndex == -1) + DRIEntPrivIndex = xf86AllocateEntityPrivateIndex(); + + pDRIEntPriv = DRI_ENT_PRIV(pScrn); + + if (pDRIEntPriv && pDRIEntPriv->drmFD != -1) + return TRUE; + + drmWasAvailable = drmAvailable(); + + memset(&tmp, 0, sizeof(tmp)); + + /* 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. + */ + openBusID = (drmlibmajor == 1 && drmlibminor >= 2) ? busID : NULL; + + tmp.drmFD = -1; + sv.drm_di_major = 1; + sv.drm_di_minor = 1; + sv.drm_dd_major = -1; + + saveSv = sv; + count = 10; + while (count--) { + tmp.drmFD = drmOpen(drmDriverName, openBusID); + + if (tmp.drmFD < 0) { + DRIDrvMsg(-1, X_ERROR, "[drm] drmOpen failed.\n"); + goto out_err; + } + + err = drmSetInterfaceVersion(tmp.drmFD, &sv); + + if (err != -EPERM) + break; + + sv = saveSv; + drmClose(tmp.drmFD); + tmp.drmFD = -1; + usleep(100000); + } + + if (tmp.drmFD <= 0) { + DRIDrvMsg(-1, X_ERROR, "[drm] DRM was busy with another master.\n"); + goto out_err; + } + + if (!drmWasAvailable) { + DRIDrvMsg(-1, X_INFO, + "[drm] loaded kernel module for \"%s\" driver.\n", + drmDriverName); + } + + if (err != 0) { + sv.drm_di_major = 1; + sv.drm_di_minor = 0; + } + + DRIDrvMsg(-1, X_INFO, "[drm] DRM interface version %d.%d\n", + sv.drm_di_major, sv.drm_di_minor); + + if (sv.drm_di_major == 1 && sv.drm_di_minor >= 1) + err = 0; + else + err = drmSetBusid(tmp.drmFD, busID); + + if (err) { + DRIDrvMsg(-1, X_ERROR, "[drm] Could not set DRM device bus ID.\n"); + goto out_err; + } + + /* + * Create a lock-containing sarea. + */ + + if (drmAddMap( tmp.drmFD, 0, sAreaSize, DRM_SHM, + DRM_CONTAINS_LOCK, &tmp.hLSAREA) < 0) { + DRIDrvMsg(-1, X_INFO, "[drm] Could not create SAREA for DRM lock.\n"); + tmp.hLSAREA = 0; + goto out_err; + } + + if (drmMap( tmp.drmFD, tmp.hLSAREA, sAreaSize, + (drmAddressPtr)(&tmp.pLSAREA)) < 0) { + DRIDrvMsg(-1, X_INFO, "[drm] Mapping SAREA for DRM lock failed.\n"); + tmp.pLSAREA = NULL; + goto out_err; + } + + memset(tmp.pLSAREA, 0, sAreaSize); + + /* + * Reserved contexts are handled by the first opened screen. + */ + + tmp.resOwner = NULL; + + if (!pDRIEntPriv) + pDRIEntPriv = xnfcalloc(sizeof(*pDRIEntPriv), 1); + + if (!pDRIEntPriv) { + DRIDrvMsg(-1, X_INFO, "[drm] Failed to allocate memory for " + "DRM device.\n"); + goto out_err; + } + *pDRIEntPriv = tmp; + xf86GetEntityPrivate((pScrn)->entityList[0],DRIEntPrivIndex)->ptr = + pDRIEntPriv; + + DRIDrvMsg(-1, X_INFO, "[drm] DRM open master succeeded.\n"); + return TRUE; + + out_err: + + DRIOpenDRMCleanup(&tmp); + return FALSE; +} + +static void +DRIClipNotifyAllDrawables(ScreenPtr pScreen); + +static void +dri_crtc_notify(ScreenPtr pScreen) +{ + DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); + DRIClipNotifyAllDrawables(pScreen); + xf86_unwrap_crtc_notify(pScreen, pDRIPriv->xf86_crtc_notify); + xf86_crtc_notify(pScreen); + pDRIPriv->xf86_crtc_notify = xf86_wrap_crtc_notify(pScreen, dri_crtc_notify); +} + +Bool +DRIScreenInit(ScreenPtr pScreen, DRIInfoPtr pDRIInfo, int *pDRMFD) +{ + DRIScreenPrivPtr pDRIPriv; + drm_context_t * reserved; + int reserved_count; + int i; + DRIEntPrivPtr pDRIEntPriv; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + DRIContextFlags flags = 0; + DRIContextPrivPtr pDRIContextPriv; + + /* 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 (!xf86VGAarbiterAllowDRI(pScreen)) { + DRIDrvMsg(pScreen->myNum, X_WARNING, + "Direct rendering is not supported when VGA arb is necessary for the device\n"); + return FALSE; + } + +#ifdef PANORAMIX + /* + * If Xinerama is on, don't allow DRI to initialise. It won't be usable + * anyway. + */ + if (!noPanoramiXExtension) { + DRIDrvMsg(pScreen->myNum, X_WARNING, + "Direct rendering is not supported when Xinerama is enabled\n"); + return FALSE; + } +#endif + + if (!DRIOpenDRMMaster(pScrn, pDRIInfo->SAREASize, + pDRIInfo->busIdString, + pDRIInfo->drmDriverName)) + return FALSE; + + pDRIEntPriv = DRI_ENT_PRIV(pScrn); + + if (DRIGeneration != serverGeneration) + DRIGeneration = serverGeneration; + + pDRIPriv = (DRIScreenPrivPtr) calloc(1, sizeof(DRIScreenPrivRec)); + if (!pDRIPriv) { + dixSetPrivate(&pScreen->devPrivates, DRIScreenPrivKey, NULL); + return FALSE; + } + + dixSetPrivate(&pScreen->devPrivates, DRIScreenPrivKey, pDRIPriv); + pDRIPriv->drmFD = pDRIEntPriv->drmFD; + pDRIPriv->directRenderingSupport = TRUE; + pDRIPriv->pDriverInfo = pDRIInfo; + pDRIPriv->nrWindows = 0; + pDRIPriv->nrWindowsVisible = 0; + pDRIPriv->fullscreen = NULL; + + pDRIPriv->createDummyCtx = pDRIInfo->createDummyCtx; + pDRIPriv->createDummyCtxPriv = pDRIInfo->createDummyCtxPriv; + + pDRIPriv->grabbedDRILock = FALSE; + pDRIPriv->drmSIGIOHandlerInstalled = FALSE; + *pDRMFD = pDRIPriv->drmFD; + + if (pDRIEntPriv->sAreaGrabbed || pDRIInfo->allocSarea) { + + if (drmAddMap( pDRIPriv->drmFD, + 0, + pDRIPriv->pDriverInfo->SAREASize, + DRM_SHM, + 0, + &pDRIPriv->hSAREA) < 0) + { + pDRIPriv->directRenderingSupport = FALSE; + dixSetPrivate(&pScreen->devPrivates, DRIScreenPrivKey, 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); + + /* Backwards compat. */ + if (drmMap( pDRIPriv->drmFD, + pDRIPriv->hSAREA, + pDRIPriv->pDriverInfo->SAREASize, + (drmAddressPtr)(&pDRIPriv->pSAREA)) < 0) + { + pDRIPriv->directRenderingSupport = FALSE; + dixSetPrivate(&pScreen->devPrivates, DRIScreenPrivKey, NULL); + drmClose(pDRIPriv->drmFD); + DRIDrvMsg(pScreen->myNum, X_INFO, + "[drm] drmMap failed\n"); + return FALSE; + } + DRIDrvMsg(pScreen->myNum, X_INFO, "[drm] mapped SAREA %p to %p\n", + pDRIPriv->hSAREA, pDRIPriv->pSAREA); + memset(pDRIPriv->pSAREA, 0, pDRIPriv->pDriverInfo->SAREASize); + } else { + DRIDrvMsg(pScreen->myNum, X_INFO, "[drm] Using the DRM lock " + "SAREA also for drawables.\n"); + pDRIPriv->hSAREA = pDRIEntPriv->hLSAREA; + pDRIPriv->pSAREA = (XF86DRISAREAPtr) pDRIEntPriv->pLSAREA; + pDRIEntPriv->sAreaGrabbed = TRUE; + } + + pDRIPriv->hLSAREA = pDRIEntPriv->hLSAREA; + pDRIPriv->pLSAREA = pDRIEntPriv->pLSAREA; + + if (!pDRIPriv->pDriverInfo->dontMapFrameBuffer) + { + if (drmAddMap( pDRIPriv->drmFD, + (drm_handle_t)pDRIPriv->pDriverInfo->frameBufferPhysicalAddress, + pDRIPriv->pDriverInfo->frameBufferSize, + DRM_FRAME_BUFFER, + 0, + &pDRIPriv->pDriverInfo->hFrameBuffer) < 0) + { + pDRIPriv->directRenderingSupport = FALSE; + dixSetPrivate(&pScreen->devPrivates, DRIScreenPrivKey, 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->pDriverInfo->hFrameBuffer); + } else { + DRIDrvMsg(pScreen->myNum, X_INFO, + "[drm] framebuffer mapped by ddx driver\n"); + } + + if (pDRIEntPriv->resOwner == NULL) { + pDRIEntPriv->resOwner = pScreen; + + /* 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; + } + + pDRIPriv->pLockRefCount = &pDRIEntPriv->lockRefCount; + pDRIPriv->pLockingContext = &pDRIEntPriv->lockingContext; + + if (!pDRIEntPriv->keepFDOpen) + pDRIEntPriv->keepFDOpen = pDRIInfo->keepFDOpen; + + pDRIEntPriv->refCount++; + + /* 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 *)calloc(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 *)calloc(1, pDRIInfo->contextSize); + if (!pDRIPriv->partial3DContextStore) { + DRIDrvMsg(pScreen->myNum, X_ERROR, + "[DRI] failed to allocate partial 3D context\n"); + free(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) + free(pDRIPriv->hiddenContextStore); + if (pDRIPriv->partial3DContextStore) + free(pDRIPriv->partial3DContextStore); + DRIDestroyContextPriv(pDRIContextPriv); + return FALSE; + } else { + DRIDrvMsg(pScreen->myNum, X_INFO, + "[drm] installed DRM signal handler\n"); + } + + default: + break; + } + + return TRUE; +} + +Bool +DRIFinishScreenInit(ScreenPtr pScreen) +{ + DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); + DRIInfoPtr pDRIInfo = pDRIPriv->pDriverInfo; + + /* 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; + } + + pDRIPriv->DestroyWindow = pScreen->DestroyWindow; + pScreen->DestroyWindow = DRIDestroyWindow; + + pDRIPriv->xf86_crtc_notify = xf86_wrap_crtc_notify(pScreen, + dri_crtc_notify); + + 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; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + DRIEntPrivPtr pDRIEntPriv = DRI_ENT_PRIV(pScrn); + Bool closeMaster; + + if (pDRIPriv) { + + 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 (pDRIPriv->DestroyWindow) { + pScreen->DestroyWindow = pDRIPriv->DestroyWindow; + pDRIPriv->DestroyWindow = NULL; + } + + xf86_unwrap_crtc_notify(pScreen, pDRIPriv->xf86_crtc_notify); + + 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 (pDRIEntPriv->resOwner == pScreen) { + pDRIEntPriv->resOwner = NULL; + + 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->pLockRefCount = NULL; + closeMaster = (--pDRIEntPriv->refCount == 0) && + !pDRIEntPriv->keepFDOpen; + if (closeMaster || pDRIPriv->hSAREA != pDRIEntPriv->hLSAREA) { + 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); + } + } else { + pDRIEntPriv->sAreaGrabbed = FALSE; + } + + if (closeMaster || (pDRIEntPriv->drmFD != pDRIPriv->drmFD)) { + drmClose(pDRIPriv->drmFD); + if (pDRIEntPriv->drmFD == pDRIPriv->drmFD) { + DRIDrvMsg(pScreen->myNum, X_INFO, + "[drm] Closed DRM master.\n"); + pDRIEntPriv->drmFD = -1; + } + } + + free(pDRIPriv); + dixSetPrivate(&pScreen->devPrivates, DRIScreenPrivKey, NULL); + } +} + +#define DRM_MSG_VERBOSITY 3 + +static int dri_drm_debug_print(const char *format, va_list ap) +{ + xf86VDrvMsgVerb(-1, X_NONE, DRM_MSG_VERBOSITY, format, ap); + return 0; +} + +static void dri_drm_get_perms(gid_t *group, mode_t *mode) +{ + *group = xf86ConfigDRI.group; + *mode = xf86ConfigDRI.mode; +} + +drmServerInfo DRIDRMServerInfo = { + dri_drm_debug_print, + xf86LoadKernelModule, + dri_drm_get_perms, +}; + +Bool +DRIExtensionInit(void) +{ + if (!DRIScreenPrivKey || DRIGeneration != serverGeneration) { + return FALSE; + } + + DRIDrawablePrivResType = CreateNewResourceType(DRIDrawablePrivDelete, + "DRIDrawable"); + DRIContextPrivResType = CreateNewResourceType(DRIContextPrivDelete, + "DRIContext"); + + if (!DRIDrawablePrivResType || !DRIContextPrivResType) + 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 = calloc(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); + free(pDRIContextPriv); + return TRUE; +} + +static Bool +DRICreateDummyContext(ScreenPtr pScreen, Bool needCtxPriv) +{ + DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); + DRIContextPrivPtr pDRIContextPriv; + void *contextStore; + + if (!(pDRIContextPriv = + DRICreateContextPriv(pScreen, + &pDRIPriv->pSAREA->dummy_context, 0))) { + return FALSE; + } + + contextStore = DRIGetContextStore(pDRIContextPriv); + if (pDRIPriv->pDriverInfo->CreateContext && needCtxPriv) { + if (!pDRIPriv->pDriverInfo->CreateContext(pScreen, NULL, + pDRIPriv->pSAREA->dummy_context, + NULL, + (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); + 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; + } + } + + if (!(pDRIContextPriv = DRICreateContextPriv(pScreen, pHWContext, 0))) { + return FALSE; + } + + contextStore = DRIGetContextStore(pDRIContextPriv); + if (pDRIPriv->pDriverInfo->CreateContext) { + if (!((*pDRIPriv->pDriverInfo->CreateContext)(pScreen, NULL, + *pHWContext, NULL, + (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 ); +} + + +static int +DRIDCNTreeTraversal(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); + + if (REGION_NUM_RECTS(&pWin->clipList) > 0) { + WindowPtr *pDRIWindows = (WindowPtr*)data; + int i = 0; + + while (pDRIWindows[i]) + i++; + + pDRIWindows[i] = pWin; + + pDRIPriv->nrWalked++; + } + + if (pDRIPriv->nrWindows == pDRIPriv->nrWalked) + return WT_STOPWALKING; + } + + return WT_WALKCHILDREN; +} + +static void +DRIDriverClipNotify(ScreenPtr pScreen) +{ + DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); + + if (pDRIPriv->pDriverInfo->ClipNotify) { + WindowPtr *pDRIWindows = calloc(sizeof(WindowPtr), pDRIPriv->nrWindows); + DRIInfoPtr pDRIInfo = pDRIPriv->pDriverInfo; + + if (pDRIPriv->nrWindows > 0) { + pDRIPriv->nrWalked = 0; + TraverseTree(WindowTable[pScreen->myNum], DRIDCNTreeTraversal, + (pointer)pDRIWindows); + } + + pDRIInfo->ClipNotify(pScreen, pDRIWindows, pDRIPriv->nrWindows); + + free(pDRIWindows); + } +} + +static void +DRIIncreaseNumberVisible(ScreenPtr pScreen) +{ + DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); + + switch (++pDRIPriv->nrWindowsVisible) { + case 1: + DRITransitionTo3d( pScreen ); + break; + case 2: + DRITransitionToSharedBuffers( pScreen ); + break; + default: + break; + } + + DRIDriverClipNotify(pScreen); +} + +static void +DRIDecreaseNumberVisible(ScreenPtr pScreen) +{ + DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); + + switch (--pDRIPriv->nrWindowsVisible) { + case 0: + DRITransitionTo2d( pScreen ); + break; + case 1: + DRITransitionToPrivateBuffers( pScreen ); + break; + default: + break; + } + + DRIDriverClipNotify(pScreen); +} + +Bool +DRICreateDrawable(ScreenPtr pScreen, ClientPtr client, 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++; + + if (!pDRIDrawablePriv->hwDrawable) { + drmCreateDrawable(pDRIPriv->drmFD, &pDRIDrawablePriv->hwDrawable); + } + } + else { + /* allocate a DRI Window Private record */ + if (!(pDRIDrawablePriv = malloc(sizeof(DRIDrawablePrivRec)))) { + return FALSE; + } + + /* Only create a drm_drawable_t once */ + if (drmCreateDrawable(pDRIPriv->drmFD, + &pDRIDrawablePriv->hwDrawable)) { + free(pDRIDrawablePriv); + return FALSE; + } + + /* add it to the list of DRI drawables for this screen */ + pDRIDrawablePriv->pScreen = pScreen; + pDRIDrawablePriv->refCount = 1; + pDRIDrawablePriv->drawableIndex = -1; + pDRIDrawablePriv->nrects = REGION_NUM_RECTS(&pWin->clipList); + + /* save private off of preallocated index */ + dixSetPrivate(&pWin->devPrivates, DRIWindowPrivKey, + pDRIDrawablePriv); + pDRIPriv->nrWindows++; + + if (pDRIDrawablePriv->nrects) + DRIIncreaseNumberVisible(pScreen); + } + + /* track this in case the client dies */ + AddResource(FakeClientID(client->index), DRIDrawablePrivResType, + (pointer)(intptr_t)pDrawable->id); + + if (pDRIDrawablePriv->hwDrawable) { + drmUpdateDrawableInfo(pDRIPriv->drmFD, + pDRIDrawablePriv->hwDrawable, + DRM_DRAWABLE_CLIPRECTS, + REGION_NUM_RECTS(&pWin->clipList), + REGION_RECTS(&pWin->clipList)); + *hHWDrawable = pDRIDrawablePriv->hwDrawable; + } + } + else if (pDrawable->type != DRAWABLE_PIXMAP) { /* PBuffer */ + /* NOT_DONE */ + return FALSE; + } + + return TRUE; +} + +static void +DRIDrawablePrivDestroy(WindowPtr pWin) +{ + DRIDrawablePrivPtr pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pWin); + ScreenPtr pScreen; + DRIScreenPrivPtr pDRIPriv; + + if (!pDRIDrawablePriv) + return; + + pScreen = pWin->drawable.pScreen; + pDRIPriv = DRI_SCREEN_PRIV(pScreen); + + 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; + } + + pDRIPriv->nrWindows--; + + if (pDRIDrawablePriv->nrects) + DRIDecreaseNumberVisible(pScreen); + + drmDestroyDrawable(pDRIPriv->drmFD, pDRIDrawablePriv->hwDrawable); + + free(pDRIDrawablePriv); + dixSetPrivate(&pWin->devPrivates, DRIWindowPrivKey, NULL); +} + +static Bool +DRIDestroyDrawableCB(pointer value, XID id, pointer data) +{ + if (value == data) { + /* This calls back DRIDrawablePrivDelete which frees private area */ + FreeResourceByType(id, DRIDrawablePrivResType, FALSE); + + return TRUE; + } + + return FALSE; +} + +Bool +DRIDestroyDrawable(ScreenPtr pScreen, ClientPtr client, DrawablePtr pDrawable) +{ + if (pDrawable->type == DRAWABLE_WINDOW) { + LookupClientResourceComplex(client, DRIDrawablePrivResType, + DRIDestroyDrawableCB, + (pointer)(intptr_t)pDrawable->id); + } + else { /* pixmap (or for GLX 1.3, a PBuffer) */ + /* NOT_DONE */ + return FALSE; + } + + return TRUE; +} + +Bool +DRIDrawablePrivDelete(pointer pResource, XID id) +{ + WindowPtr pWin; + int rc; + + /* For DRIDrawablePrivResType, the XID is the client's fake ID. The + * important XID is the value in pResource. */ + id = (XID)(intptr_t)pResource; + rc = dixLookupWindow(&pWin, id, serverClient, DixGetAttrAccess); + + if (rc == Success) { + DRIDrawablePrivPtr pDRIDrwPriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pWin); + + if (!pDRIDrwPriv) + return FALSE; + + if (--pDRIDrwPriv->refCount == 0) + DRIDrawablePrivDestroy(pWin); + + return TRUE; + } + else { /* pixmap (or for GLX 1.3, a PBuffer) */ + /* NOT_DONE */ + return FALSE; + } +} + +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; + +#if 0 + printf("maxDrawableTableEntry = %d\n", pDRIPriv->pDriverInfo->maxDrawableTableEntry); +#endif + + 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->nrWindowsVisible == 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; + + if (y0 >= y1 || x0 >= x1) { + *numBackClipRects = 0; + *pBackClipRects = NULL; + } else { + 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->pDriverInfo->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)calloc(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) free(DRIInfo->busIdString); + free((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); + } + + if (pDRIPriv->windowsTouched) + DRM_SPINUNLOCK(&pDRIPriv->pSAREA->drawable_lock, 1); + pDRIPriv->windowsTouched = FALSE; + + 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; + + if (!newContext) { + DRIDrvMsg(pScreen->myNum, X_ERROR, + "[DRI] Context Switch Error: oldContext=%x, newContext=%x\n", + oldContext, newContext); + return; + } + + /* 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); + + if(REGION_NUM_RECTS(&(pWin->clipList)) > 0) { + RegionPtr reg = (RegionPtr)data; + + REGION_UNION(pScreen, reg, reg, &(pWin->clipList)); + pDRIPriv->nrWalked++; + } + + if(pDRIPriv->nrWindows == pDRIPriv->nrWalked) + return WT_STOPWALKING; + } + return WT_WALKCHILDREN; +} + +Bool +DRIDestroyWindow(WindowPtr pWin) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); + Bool retval = TRUE; + + DRIDrawablePrivDestroy(pWin); + + /* call lower wrapped functions */ + if(pDRIPriv->DestroyWindow) { + /* unwrap */ + pScreen->DestroyWindow = pDRIPriv->DestroyWindow; + + /* call lower layers */ + retval = (*pScreen->DestroyWindow)(pWin); + + /* rewrap */ + pDRIPriv->DestroyWindow = pScreen->DestroyWindow; + pScreen->DestroyWindow = DRIDestroyWindow; + } + + return retval; +} + +void +DRICopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); + + if(!pDRIPriv) return; + + if(pDRIPriv->nrWindowsVisible > 0) { + RegionRec reg; + + REGION_NULL(pScreen, ®); + pDRIPriv->nrWalked = 0; + TraverseTree(pWin, DRITreeTraversal, (pointer)(®)); + + if(REGION_NOTEMPTY(pScreen, ®)) { + REGION_TRANSLATE(pScreen, ®, ptOldOrg.x - pWin->drawable.x, + ptOldOrg.y - pWin->drawable.y); + REGION_INTERSECT(pScreen, ®, ®, prgnSrc); + + /* The MoveBuffers interface is not ideal */ + (*pDRIPriv->pDriverInfo->MoveBuffers)(pWin, ptOldOrg, ®, + pDRIPriv->pDriverInfo->ddxDrawableTableEntry); + } + + REGION_UNINIT(pScreen, ®); + } + + /* 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) +{ + struct timeval tv; + + gettimeofday(&tv, NULL); + + *secs = tv.tv_sec; + *usecs = tv.tv_usec; +} + +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); + } +} + +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; + + /* 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; + } +} + +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))) { + int nrects = REGION_NUM_RECTS(&pWin->clipList); + + if(!pDRIPriv->windowsTouched) { + DRILockTree(pScreen); + pDRIPriv->windowsTouched = TRUE; + } + + if (nrects && !pDRIDrawablePriv->nrects) + DRIIncreaseNumberVisible(pScreen); + else if (!nrects && pDRIDrawablePriv->nrects) + DRIDecreaseNumberVisible(pScreen); + else + DRIDriverClipNotify(pScreen); + + pDRIDrawablePriv->nrects = nrects; + + pDRIPriv->pSAREA->drawableTable[pDRIDrawablePriv->drawableIndex].stamp + = DRIDrawableValidationStamp++; + + drmUpdateDrawableInfo(pDRIPriv->drmFD, pDRIDrawablePriv->hwDrawable, + DRM_DRAWABLE_CLIPRECTS, + nrects, REGION_RECTS(&pWin->clipList)); + } + + /* 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 || !pDRIPriv->pLockRefCount) return; + + if (!*pDRIPriv->pLockRefCount) { + DRM_LOCK(pDRIPriv->drmFD, pDRIPriv->pLSAREA, pDRIPriv->myContext, flags); + *pDRIPriv->pLockingContext = pDRIPriv->myContext; + } else if (*pDRIPriv->pLockingContext != pDRIPriv->myContext) { + DRIDrvMsg(pScreen->myNum, X_ERROR, + "[DRI] Locking deadlock.\n" + "\tAlready locked with context %d,\n" + "\ttrying to lock with context %d.\n", + pDRIPriv->pLockingContext, + pDRIPriv->myContext); + } + (*pDRIPriv->pLockRefCount)++; +} + +void +DRIUnlock(ScreenPtr pScreen) +{ + DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); + + if(!pDRIPriv || !pDRIPriv->pLockRefCount) return; + + if (*pDRIPriv->pLockRefCount > 0) { + if (pDRIPriv->myContext != *pDRIPriv->pLockingContext) { + DRIDrvMsg(pScreen->myNum, X_ERROR, + "[DRI] Unlocking inconsistency:\n" + "\tContext %d trying to unlock lock held by context %d\n", + pDRIPriv->pLockingContext, + pDRIPriv->myContext); + } + (*pDRIPriv->pLockRefCount)--; + } else { + DRIDrvMsg(pScreen->myNum, X_ERROR, + "DRIUnlock called when not locked.\n"); + return; + } + if (! *pDRIPriv->pLockRefCount) + DRM_UNLOCK(pDRIPriv->drmFD, pDRIPriv->pLSAREA, 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; +} + +void +DRIGetTexOffsetFuncs(ScreenPtr pScreen, + DRITexOffsetStartProcPtr *texOffsetStartFunc, + DRITexOffsetFinishProcPtr *texOffsetFinishFunc) +{ + DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); + + if (!pDRIPriv) return; + + *texOffsetStartFunc = pDRIPriv->pDriverInfo->texOffsetStart; + *texOffsetFinishFunc = pDRIPriv->pDriverInfo->texOffsetFinish; +} + +/* 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 */ + miPointerGetPosition(inputInfo.pointer, &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(inputInfo.pointer, 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(const struct pci_device * dev) +{ + char *busID; + + busID = malloc(20); + if (busID == NULL) + return NULL; + + snprintf(busID, 20, "pci:%04x:%02x:%02x.%d", dev->domain, dev->bus, + dev->dev, dev->func); + + return busID; +} + +static void drmSIGIOHandler(int interrupt, void *closure) +{ + unsigned long key; + void *value; + ssize_t count; + drm_ctx_t ctx; + typedef void (*_drmCallback)(int, void *, void *); + char buf[256]; + drm_context_t old; + drm_context_t new; + void *oldctx; + void *newctx; + char *pt; + drmHashEntry *entry; + void *hash_table; + + hash_table = drmGetHashTable(); + + if (!hash_table) return; + if (drmHashFirst(hash_table, &key, &value)) { + entry = value; + do { +#if 0 + fprintf(stderr, "Trying %d\n", entry->fd); +#endif + if ((count = read(entry->fd, buf, sizeof(buf) - 1)) > 0) { + buf[count] = '\0'; +#if 0 + fprintf(stderr, "Got %s\n", buf); +#endif + + for (pt = buf; *pt != ' '; ++pt); /* Find first space */ + ++pt; + old = strtol(pt, &pt, 0); + new = strtol(pt, NULL, 0); + oldctx = drmGetContextTag(entry->fd, old); + newctx = drmGetContextTag(entry->fd, new); +#if 0 + fprintf(stderr, "%d %d %p %p\n", old, new, oldctx, newctx); +#endif + ((_drmCallback)entry->f)(entry->fd, oldctx, newctx); + ctx.handle = new; + ioctl(entry->fd, DRM_IOCTL_NEW_CTX, &ctx); + } + } while (drmHashNext(hash_table, &key, &value)); + } +} + + +int drmInstallSIGIOHandler(int fd, void (*f)(int, void *, void *)) +{ + drmHashEntry *entry; + + entry = drmGetEntry(fd); + entry->f = f; + + return xf86InstallSIGIOHandler(fd, drmSIGIOHandler, 0); +} + +int drmRemoveSIGIOHandler(int fd) +{ + drmHashEntry *entry = drmGetEntry(fd); + + entry->f = NULL; + + return xf86RemoveSIGIOHandler(fd); +} -- cgit v1.2.3