#ifdef XFree86LOADER
#include "xf86.h"
#include "xf86_ansic.h"
#else
#include <sys/time.h>
#include <unistd.h>
#endif
#define NEED_REPLIES
#define NEED_EVENTS
#include "X.h"
#include "Xproto.h"
#include "misc.h"
#include "dixstruct.h"
#include "extnsionst.h"
#include "colormapst.h"
#include "cursorstr.h"
#include "scrnintstr.h"
#include "windowstr.h"
#include "servermd.h"
#define _XF86DRI_SERVER_
#include "xf86dristr.h"
#include "swaprep.h"
#include "dri.h"
#include "sarea.h"
#include "dristruct.h"
#include "xf86.h"
#include "xf86drm.h"
#include "glxserver.h"
#include "mi.h"
#include "mipointer.h"
#if defined(XFree86LOADER) && !defined(PANORAMIX)
extern Bool noPanoramiXExtension;
#endif
static int DRIScreenPrivIndex = -1;
static int DRIWindowPrivIndex = -1;
static unsigned long DRIGeneration = 0;
static unsigned int DRIDrawableValidationStamp = 0;
static int lockRefCount=0;
static Bool _DRICloseFullScreen(pointer pResource, XID id);
static RESTYPE DRIFullScreenResType;
static RESTYPE DRIDrawablePrivResType;
static RESTYPE DRIContextPrivResType;
static void DRIDestroyDummyContext(ScreenPtr pScreen, Bool hasCtxPriv);
#define DRI_MSG_VERBOSITY 1
static void
DRIDrvMsg(int scrnIndex, MessageType type, const char *format, ...)
{
va_list ap;
va_start(ap, format);
xf86VDrvMsgVerb(scrnIndex, type, DRI_MSG_VERBOSITY, format, ap);
va_end(ap);
}
Bool
DRIScreenInit(ScreenPtr pScreen, DRIInfoPtr pDRIInfo, int *pDRMFD)
{
DRIScreenPrivPtr pDRIPriv;
drmContextPtr reserved;
int reserved_count;
int i, fd, drmWasAvailable;
Bool xineramaInCore = FALSE;
int err = 0;
if (DRIGeneration != serverGeneration) {
if ((DRIScreenPrivIndex = AllocateScreenPrivateIndex()) < 0)
return FALSE;
DRIGeneration = serverGeneration;
}
#if defined(PANORAMIX) && !defined(XFree86LOADER)
xineramaInCore = TRUE;
#elif defined(XFree86LOADER)
if (xf86LoaderCheckSymbol("noPanoramiXExtension"))
xineramaInCore = TRUE;
#endif
#if defined(PANORAMIX) || defined(XFree86LOADER)
if (xineramaInCore) {
if (!noPanoramiXExtension) {
DRIDrvMsg(pScreen->myNum, X_WARNING,
"Direct rendering is not supported when Xinerama is enabled\n");
return FALSE;
}
}
#endif
drmWasAvailable = drmAvailable();
fd = drmOpen(pDRIInfo->drmDriverName, NULL );
if (fd < 0) {
pScreen->devPrivates[DRIScreenPrivIndex].ptr = NULL;
DRIDrvMsg(pScreen->myNum, X_INFO,
"[drm] drmOpen failed\n");
return FALSE;
}
if (!drmWasAvailable) {
DRIDrvMsg(pScreen->myNum, X_INFO,
"[drm] loaded kernel module for \"%s\" driver\n",
pDRIInfo->drmDriverName);
}
pDRIPriv = (DRIScreenPrivPtr) xcalloc(1, sizeof(DRIScreenPrivRec));
if (!pDRIPriv) {
pScreen->devPrivates[DRIScreenPrivIndex].ptr = NULL;
return FALSE;
}
pScreen->devPrivates[DRIScreenPrivIndex].ptr = (pointer) pDRIPriv;
pDRIPriv->drmFD = fd;
pDRIPriv->directRenderingSupport = TRUE;
pDRIPriv->pDriverInfo = pDRIInfo;
pDRIPriv->nrWindows = 0;
pDRIPriv->fullscreen = NULL;
pDRIPriv->createDummyCtx = pDRIInfo->createDummyCtx;
pDRIPriv->createDummyCtxPriv = pDRIInfo->createDummyCtxPriv;
pDRIPriv->grabbedDRILock = FALSE;
pDRIPriv->drmSIGIOHandlerInstalled = FALSE;
if ((err = drmSetBusid(pDRIPriv->drmFD, pDRIPriv->pDriverInfo->busIdString)) < 0) {
pDRIPriv->directRenderingSupport = FALSE;
pScreen->devPrivates[DRIScreenPrivIndex].ptr = NULL;
drmClose(pDRIPriv->drmFD);
DRIDrvMsg(pScreen->myNum, X_INFO,
"[drm] drmSetBusid failed (%d, %s), %s\n",
pDRIPriv->drmFD, pDRIPriv->pDriverInfo->busIdString, strerror(-err));
return FALSE;
}
*pDRMFD = pDRIPriv->drmFD;
DRIDrvMsg(pScreen->myNum, X_INFO,
"[drm] created \"%s\" driver at busid \"%s\"\n",
pDRIPriv->pDriverInfo->drmDriverName,
pDRIPriv->pDriverInfo->busIdString);
if (drmAddMap( pDRIPriv->drmFD,
0,
pDRIPriv->pDriverInfo->SAREASize,
DRM_SHM,
DRM_CONTAINS_LOCK,
&pDRIPriv->hSAREA) < 0)
{
pDRIPriv->directRenderingSupport = FALSE;
pScreen->devPrivates[DRIScreenPrivIndex].ptr = NULL;
drmClose(pDRIPriv->drmFD);
DRIDrvMsg(pScreen->myNum, X_INFO,
"[drm] drmAddMap failed\n");
return FALSE;
}
DRIDrvMsg(pScreen->myNum, X_INFO,
"[drm] added %d byte SAREA at 0x%08lx\n",
pDRIPriv->pDriverInfo->SAREASize, pDRIPriv->hSAREA);
if (drmMap( pDRIPriv->drmFD,
pDRIPriv->hSAREA,
pDRIPriv->pDriverInfo->SAREASize,
(drmAddressPtr)(&pDRIPriv->pSAREA)) < 0)
{
pDRIPriv->directRenderingSupport = FALSE;
pScreen->devPrivates[DRIScreenPrivIndex].ptr = NULL;
drmClose(pDRIPriv->drmFD);
DRIDrvMsg(pScreen->myNum, X_INFO,
"[drm] drmMap failed\n");
return FALSE;
}
memset(pDRIPriv->pSAREA, 0, pDRIPriv->pDriverInfo->SAREASize);
DRIDrvMsg(pScreen->myNum, X_INFO, "[drm] mapped SAREA 0x%08lx to %p\n",
pDRIPriv->hSAREA, pDRIPriv->pSAREA);
if (drmAddMap( pDRIPriv->drmFD,
(drmHandle)pDRIPriv->pDriverInfo->frameBufferPhysicalAddress,
pDRIPriv->pDriverInfo->frameBufferSize,
DRM_FRAME_BUFFER,
0,
&pDRIPriv->hFrameBuffer) < 0)
{
pDRIPriv->directRenderingSupport = FALSE;
pScreen->devPrivates[DRIScreenPrivIndex].ptr = NULL;
drmUnmap(pDRIPriv->pSAREA, pDRIPriv->pDriverInfo->SAREASize);
drmClose(pDRIPriv->drmFD);
DRIDrvMsg(pScreen->myNum, X_INFO,
"[drm] drmAddMap failed\n");
return FALSE;
}
DRIDrvMsg(pScreen->myNum, X_INFO, "[drm] framebuffer handle = 0x%08lx\n",
pDRIPriv->hFrameBuffer);
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" : "");
}
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);
}
for( i=0; i < pDRIPriv->pDriverInfo->maxDrawableTableEntry; i++) {
pDRIPriv->DRIDrawables[i] = NULL;
pDRIPriv->pSAREA->drawableTable[i].stamp = 0;
pDRIPriv->pSAREA->drawableTable[i].flags = 0;
}
return TRUE;
}
Bool
DRIFinishScreenInit(ScreenPtr pScreen)
{
DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
DRIInfoPtr pDRIInfo = pDRIPriv->pDriverInfo;
DRIContextFlags flags = 0;
DRIContextPrivPtr pDRIContextPriv;
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 = 0x%08lx\n", pDRIPriv->myContext);
DRILock(pScreen, 0);
pDRIPriv->grabbedDRILock = TRUE;
pDRIPriv->hiddenContextStore = NULL;
pDRIPriv->partial3DContextStore = NULL;
switch(pDRIInfo->driverSwapMethod) {
case DRI_HIDE_X_CONTEXT:
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;
}
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;
}
if (pDRIInfo->SwapContext) {
(*pDRIInfo->SwapContext)(
pScreen,
DRI_NO_SYNC,
DRI_2D_CONTEXT,
pDRIPriv->hiddenContextStore,
DRI_NO_CONTEXT,
NULL);
}
case DRI_SERVER_SWAP:
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;
}
if (pDRIInfo->wrap.ValidateTree) {
pDRIPriv->wrap.ValidateTree = pScreen->ValidateTree;
pScreen->ValidateTree = pDRIInfo->wrap.ValidateTree;
}
if (pDRIInfo->wrap.PostValidateTree) {
pDRIPriv->wrap.PostValidateTree = pScreen->PostValidateTree;
pScreen->PostValidateTree = pDRIInfo->wrap.PostValidateTree;
}
if (pDRIInfo->wrap.WindowExposures) {
pDRIPriv->wrap.WindowExposures = pScreen->WindowExposures;
pScreen->WindowExposures = pDRIInfo->wrap.WindowExposures;
}
if (pDRIInfo->wrap.CopyWindow) {
pDRIPriv->wrap.CopyWindow = pScreen->CopyWindow;
pScreen->CopyWindow = pDRIInfo->wrap.CopyWindow;
}
if (pDRIInfo->wrap.ClipNotify) {
pDRIPriv->wrap.ClipNotify = pScreen->ClipNotify;
pScreen->ClipNotify = pDRIInfo->wrap.ClipNotify;
}
if (pDRIInfo->wrap.AdjustFrame) {
ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
pDRIPriv->wrap.AdjustFrame = pScrn->AdjustFrame;
pScrn->AdjustFrame = pDRIInfo->wrap.AdjustFrame;
}
pDRIPriv->wrapped = TRUE;
DRIDrvMsg(pScreen->myNum, X_INFO, "[DRI] installation complete\n");
return TRUE;
}
void
DRICloseScreen(ScreenPtr pScreen)
{
DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
DRIInfoPtr pDRIInfo;
drmContextPtr reserved;
int reserved_count;
if (pDRIPriv && pDRIPriv->directRenderingSupport) {
pDRIInfo = pDRIPriv->pDriverInfo;
if (pDRIPriv->wrapped) {
if (pDRIInfo->wrap.ValidateTree) {
pScreen->ValidateTree = pDRIPriv->wrap.ValidateTree;
pDRIPriv->wrap.ValidateTree = NULL;
}
if (pDRIInfo->wrap.PostValidateTree) {
pScreen->PostValidateTree = pDRIPriv->wrap.PostValidateTree;
pDRIPriv->wrap.PostValidateTree = NULL;
}
if (pDRIInfo->wrap.WindowExposures) {
pScreen->WindowExposures = pDRIPriv->wrap.WindowExposures;
pDRIPriv->wrap.WindowExposures = NULL;
}
if (pDRIInfo->wrap.CopyWindow) {
pScreen->CopyWindow = pDRIPriv->wrap.CopyWindow;
pDRIPriv->wrap.CopyWindow = NULL;
}
if (pDRIInfo->wrap.ClipNotify) {
pScreen->ClipNotify = pDRIPriv->wrap.ClipNotify;
pDRIPriv->wrap.ClipNotify = NULL;
}
if (pDRIInfo->wrap.AdjustFrame) {
ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
pScrn->AdjustFrame = pDRIPriv->wrap.AdjustFrame;
pDRIPriv->wrap.AdjustFrame = NULL;
}
pDRIPriv->wrapped = FALSE;
}
if (pDRIPriv->drmSIGIOHandlerInstalled) {
if (!drmRemoveSIGIOHandler(pDRIPriv->drmFD)) {
DRIDrvMsg(pScreen->myNum, X_ERROR,
"[drm] failed to remove DRM signal handler\n");
}
}
if (pDRIPriv->dummyCtxPriv && pDRIPriv->createDummyCtx) {
DRIDestroyDummyContext(pScreen, pDRIPriv->createDummyCtxPriv);
}
if (!DRIDestroyContextPriv(pDRIPriv->myContextPriv)) {
DRIDrvMsg(pScreen->myNum, X_ERROR,
"failed to destroy server context\n");
}
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" : "");
}
drmUnlock(pDRIPriv->drmFD, pDRIPriv->myContext);
lockRefCount=0;
DRIDrvMsg(pScreen->myNum, X_INFO,
"[drm] unmapping %d bytes of SAREA 0x%08lx 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 0x%08lx at %p\n",
pDRIInfo->SAREASize,
pDRIPriv->hSAREA,
pDRIPriv->pSAREA);
}
drmClose(pDRIPriv->drmFD);
xfree(pDRIPriv);
pScreen->devPrivates[DRIScreenPrivIndex].ptr = NULL;
}
}
Bool
DRIExtensionInit(void)
{
int i;
ScreenPtr pScreen;
if (DRIScreenPrivIndex < 0) {
return FALSE;
}
if ((DRIWindowPrivIndex = AllocateWindowPrivateIndex()) < 0)
return FALSE;
DRIDrawablePrivResType = CreateNewResourceType(DRIDrawablePrivDelete);
DRIContextPrivResType = CreateNewResourceType(DRIContextPrivDelete);
DRIFullScreenResType = CreateNewResourceType(_DRICloseFullScreen);
for (i = 0; i < screenInfo.numScreens; i++)
{
pScreen = screenInfo.screens[i];
if (!AllocateWindowPrivate(pScreen, DRIWindowPrivIndex, 0))
return FALSE;
}
RegisterBlockAndWakeupHandlers(DRIBlockHandler, DRIWakeupHandler, NULL);
return TRUE;
}
void
DRIReset(void)
{
}
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, drmHandlePtr hSAREA, char **busIdString)
{
DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
*hSAREA = pDRIPriv->hSAREA;
*busIdString = pDRIPriv->pDriverInfo->busIdString;
return TRUE;
}
Bool
DRIAuthConnection(ScreenPtr pScreen, drmMagic 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;
}
DRIContextPrivPtr
DRICreateContextPriv(ScreenPtr pScreen,
drmContextPtr 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,
drmContext 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)) {
if (drmDestroyContext(pDRIPriv->drmFD, pDRIContextPriv->hwContext))
return FALSE;
}
drmDelContextTag(pDRIPriv->drmFD, pDRIContextPriv->hwContext);
xfree(pDRIContextPriv);
return TRUE;
}
static Bool
DRICreateDummyContext(ScreenPtr pScreen, Bool needCtxPriv)
{
DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
__GLXscreenInfo *pGLXScreen = &__glXActiveScreens[pScreen->myNum];
__GLXvisualConfig *pGLXVis = pGLXScreen->pGlxVisual;
void **pVisualConfigPriv = pGLXScreen->pVisualPriv;
DRIContextPrivPtr pDRIContextPriv;
void *contextStore;
VisualPtr visual;
int visNum;
visual = pScreen->visuals;
for (visNum = 0;
visNum < pScreen->numVisuals;
visNum++, visual++) {
if (pGLXVis->vid == visual->vid)
break;
}
if (visNum == pScreen->numVisuals) return FALSE;
if (!(pDRIContextPriv =
DRICreateContextPriv(pScreen,
&pDRIPriv->pSAREA->dummy_context, 0))) {
return FALSE;
}
contextStore = DRIGetContextStore(pDRIContextPriv);
if (pDRIPriv->pDriverInfo->CreateContext && needCtxPriv) {
if (!pDRIPriv->pDriverInfo->CreateContext(pScreen, visual,
pDRIPriv->pSAREA->dummy_context,
*pVisualConfigPriv,
(DRIContextType)(long)contextStore)) {
DRIDestroyContextPriv(pDRIContextPriv);
return FALSE;
}
}
pDRIPriv->dummyCtxPriv = pDRIContextPriv;
return TRUE;
}
static void
DRIDestroyDummyContext(ScreenPtr pScreen, Bool hasCtxPriv)
{
DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
DRIContextPrivPtr pDRIContextPriv = pDRIPriv->dummyCtxPriv;
void *contextStore;
if (!pDRIContextPriv) return;
if (pDRIPriv->pDriverInfo->DestroyContext && hasCtxPriv) {
contextStore = DRIGetContextStore(pDRIContextPriv);
pDRIPriv->pDriverInfo->DestroyContext(pDRIContextPriv->pScreen,
pDRIContextPriv->hwContext,
(DRIContextType)(long)contextStore);
}
DRIDestroyContextPriv(pDRIPriv->dummyCtxPriv);
pDRIPriv->dummyCtxPriv = NULL;
}
Bool
DRICreateContext(ScreenPtr pScreen, VisualPtr visual,
XID context, drmContextPtr pHWContext)
{
DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
__GLXscreenInfo *pGLXScreen = &__glXActiveScreens[pScreen->myNum];
__GLXvisualConfig *pGLXVis = pGLXScreen->pGlxVisual;
void **pVisualConfigPriv = pGLXScreen->pVisualPriv;
DRIContextPrivPtr pDRIContextPriv;
void *contextStore;
int visNum;
if (pDRIPriv->createDummyCtx && !pDRIPriv->dummyCtxPriv) {
if (!DRICreateDummyContext(pScreen, pDRIPriv->createDummyCtxPriv)) {
DRIDrvMsg(pScreen->myNum, X_INFO,
"[drm] Could not create dummy context\n");
return FALSE;
}
}
for (visNum = 0;
visNum < pGLXScreen->numVisuals;
visNum++, pGLXVis++, pVisualConfigPriv++)
if (pGLXVis->vid == visual->vid)
break;
if (visNum == pGLXScreen->numVisuals) {
return FALSE;
}
if (!(pDRIContextPriv = DRICreateContextPriv(pScreen, pHWContext, 0))) {
return FALSE;
}
contextStore = DRIGetContextStore(pDRIContextPriv);
if (pDRIPriv->pDriverInfo->CreateContext) {
if (!((*pDRIPriv->pDriverInfo->CreateContext)(pScreen, visual,
*pHWContext, *pVisualConfigPriv,
(DRIContextType)(long)contextStore))) {
DRIDestroyContextPriv(pDRIContextPriv);
return FALSE;
}
}
AddResource(context, DRIContextPrivResType, (pointer)pDRIContextPriv);
return TRUE;
}
Bool
DRIDestroyContext(ScreenPtr pScreen, XID context)
{
FreeResourceByType(context, DRIContextPrivResType, FALSE);
return TRUE;
}
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);
}
static void
DRIClipNotifyAllDrawables(ScreenPtr pScreen)
{
int i;
DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
for( i=0; i < pDRIPriv->pDriverInfo->maxDrawableTableEntry; i++) {
pDRIPriv->pSAREA->drawableTable[i].stamp = DRIDrawableValidationStamp++;
}
}
static void
DRITransitionToSharedBuffers(ScreenPtr pScreen)
{
DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
DRIInfoPtr pDRIInfo = pDRIPriv->pDriverInfo;
DRIClipNotifyAllDrawables( pScreen );
if (pDRIInfo->TransitionSingleToMulti3D)
pDRIInfo->TransitionSingleToMulti3D( pScreen );
}
static void
DRITransitionToPrivateBuffers(ScreenPtr pScreen)
{
DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
DRIInfoPtr pDRIInfo = pDRIPriv->pDriverInfo;
DRIClipNotifyAllDrawables( pScreen );
if (pDRIInfo->TransitionMultiToSingle3D)
pDRIInfo->TransitionMultiToSingle3D( pScreen );
}
static void
DRITransitionTo3d(ScreenPtr pScreen)
{
DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
DRIInfoPtr pDRIInfo = pDRIPriv->pDriverInfo;
DRIClipNotifyAllDrawables( pScreen );
if (pDRIInfo->TransitionTo3d)
pDRIInfo->TransitionTo3d( pScreen );
}
static void
DRITransitionTo2d(ScreenPtr pScreen)
{
DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
DRIInfoPtr pDRIInfo = pDRIPriv->pDriverInfo;
DRIClipNotifyAllDrawables( pScreen );
if (pDRIInfo->TransitionTo2d)
pDRIInfo->TransitionTo2d( pScreen );
}
Bool
DRICreateDrawable(ScreenPtr pScreen, Drawable id,
DrawablePtr pDrawable, drmDrawablePtr hHWDrawable)
{
DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
DRIDrawablePrivPtr pDRIDrawablePriv;
WindowPtr pWin;
if (pDrawable->type == DRAWABLE_WINDOW) {
pWin = (WindowPtr)pDrawable;
if ((pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pWin))) {
pDRIDrawablePriv->refCount++;
}
else {
if (!(pDRIDrawablePriv = xalloc(sizeof(DRIDrawablePrivRec)))) {
return FALSE;
}
if (drmCreateDrawable(pDRIPriv->drmFD, hHWDrawable)) {
xfree(pDRIDrawablePriv);
return FALSE;
}
pDRIDrawablePriv->hwDrawable = *hHWDrawable;
pDRIDrawablePriv->pScreen = pScreen;
pDRIDrawablePriv->refCount = 1;
pDRIDrawablePriv->drawableIndex = -1;
pWin->devPrivates[DRIWindowPrivIndex].ptr =
(pointer)pDRIDrawablePriv;
switch (++pDRIPriv->nrWindows) {
case 1:
DRITransitionTo3d( pScreen );
break;
case 2:
DRITransitionToSharedBuffers( pScreen );
break;
default:
break;
}
AddResource(id, DRIDrawablePrivResType, (pointer)pWin);
}
}
else {
return FALSE;
}
return TRUE;
}
Bool
DRIDestroyDrawable(ScreenPtr pScreen, Drawable id, DrawablePtr pDrawable)
{
DRIDrawablePrivPtr pDRIDrawablePriv;
WindowPtr pWin;
if (pDrawable->type == DRAWABLE_WINDOW) {
pWin = (WindowPtr)pDrawable;
pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pWin);
pDRIDrawablePriv->refCount--;
if (pDRIDrawablePriv->refCount <= 0) {
FreeResourceByType(id, DRIDrawablePrivResType, FALSE);
}
}
else {
return FALSE;
}
return TRUE;
}
Bool
DRIDrawablePrivDelete(pointer pResource, XID id)
{
DrawablePtr pDrawable = (DrawablePtr)pResource;
DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pDrawable->pScreen);
DRIDrawablePrivPtr pDRIDrawablePriv;
WindowPtr pWin;
if (pDrawable->type == DRAWABLE_WINDOW) {
pWin = (WindowPtr)pDrawable;
pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pWin);
if (pDRIDrawablePriv->drawableIndex != -1) {
pDRIPriv->pSAREA->drawableTable[pDRIDrawablePriv->drawableIndex].stamp
= DRIDrawableValidationStamp++;
pDRIPriv->DRIDrawables[pDRIDrawablePriv->drawableIndex] = NULL;
}
if (drmDestroyDrawable(pDRIPriv->drmFD,
pDRIDrawablePriv->hwDrawable)) {
return FALSE;
}
xfree(pDRIDrawablePriv);
pWin->devPrivates[DRIWindowPrivIndex].ptr = NULL;
switch (--pDRIPriv->nrWindows) {
case 0:
DRITransitionTo2d( pDrawable->pScreen );
break;
case 1:
DRITransitionToPrivateBuffers( pDrawable->pScreen );
break;
default:
break;
}
}
else {
return FALSE;
}
return TRUE;
}
Bool
DRIGetDrawableInfo(ScreenPtr pScreen,
DrawablePtr pDrawable,
unsigned int* index,
unsigned int* stamp,
int* X,
int* Y,
int* W,
int* H,
int* numClipRects,
XF86DRIClipRectPtr* pClipRects,
int* backX,
int* backY,
int* numBackClipRects,
XF86DRIClipRectPtr* pBackClipRects)
{
DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
DRIDrawablePrivPtr pDRIDrawablePriv, pOldDrawPriv;
WindowPtr pWin, pOldWin;
int i;
printf("maxDrawableTableEntry = %d\n", pDRIPriv->pDriverInfo->maxDrawableTableEntry);
if (pDrawable->type == DRAWABLE_WINDOW) {
pWin = (WindowPtr)pDrawable;
if ((pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pWin))) {
if (pDRIDrawablePriv->drawableIndex == -1) {
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++;
}
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;
pOldWin = (WindowPtr)pDRIPriv->DRIDrawables[oldestIndex];
pOldDrawPriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pOldWin);
pOldDrawPriv->drawableIndex = -1;
pDRIPriv->DRIDrawables[oldestIndex] = pDrawable;
pDRIPriv->pSAREA->drawableTable[oldestIndex].stamp =
DRIDrawableValidationStamp++;
if (oldestStamp > DRIDrawableValidationStamp) {
for( i=0;
i < pDRIPriv->pDriverInfo->maxDrawableTableEntry;
i++) {
pDRIPriv->pSAREA->drawableTable[i].stamp =
DRIDrawableValidationStamp++;
}
}
}
if (pDRIPriv->pDriverInfo->SetDrawableIndex)
pDRIPriv->pDriverInfo->SetDrawableIndex(pWin,
pDRIDrawablePriv->drawableIndex);
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 = (XF86DRIClipRectPtr)REGION_RECTS(&pWin->clipList);
if (!*numClipRects && pDRIPriv->fullscreen) {
pDRIPriv->fullscreen_rect.x1 = *X;
pDRIPriv->fullscreen_rect.y1 = *Y;
pDRIPriv->fullscreen_rect.x2 = *X + *W;
pDRIPriv->fullscreen_rect.y2 = *Y + *H;
*numClipRects = 1;
*pClipRects = &pDRIPriv->fullscreen_rect;
}
*backX = *X;
*backY = *Y;
if (pDRIPriv->nrWindows == 1 && *numClipRects) {
int x0 = *X;
int y0 = *Y;
int x1 = x0 + *W;
int y1 = y0 + *H;
if (x0 < 0) x0 = 0;
if (y0 < 0) y0 = 0;
if (x1 > pScreen->width) x1 = pScreen->width;
if (y1 > pScreen->height) y1 = pScreen->height;
pDRIPriv->private_buffer_rect.x1 = x0;
pDRIPriv->private_buffer_rect.y1 = y0;
pDRIPriv->private_buffer_rect.x2 = x1;
pDRIPriv->private_buffer_rect.y2 = y1;
*numBackClipRects = 1;
*pBackClipRects = &(pDRIPriv->private_buffer_rect);
} else {
*numBackClipRects = 0;
*pBackClipRects = 0;
}
}
else {
return FALSE;
}
}
else {
return FALSE;
}
return TRUE;
}
Bool
DRIGetDeviceInfo(ScreenPtr pScreen,
drmHandlePtr hFrameBuffer,
int* fbOrigin,
int* fbSize,
int* fbStride,
int* devPrivateSize,
void** pDevPrivate)
{
DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
*hFrameBuffer = pDRIPriv->hFrameBuffer;
*fbOrigin = 0;
*fbSize = pDRIPriv->pDriverInfo->frameBufferSize;
*fbStride = pDRIPriv->pDriverInfo->frameBufferStride;
*devPrivateSize = pDRIPriv->pDriverInfo->devPrivateSize;
*pDevPrivate = pDRIPriv->pDriverInfo->devPrivate;
return TRUE;
}
DRIInfoPtr
DRICreateInfoRec(void)
{
DRIInfoPtr inforec = (DRIInfoPtr)xcalloc(1, sizeof(DRIInfoRec));
if (!inforec) return NULL;
inforec->busIdString = NULL;
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) {
(*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) {
(*pDRIPriv->pDriverInfo->SwapContext)(pScreen,
DRI_2D_SYNC,
DRI_NO_CONTEXT,
NULL,
DRI_2D_CONTEXT,
pDRIPriv->partial3DContextStore);
}
DRIUnlock(pScreen);
}
void
DRISwapContext(int drmFD, void *oldctx, void *newctx)
{
DRIContextPrivPtr oldContext = (DRIContextPrivPtr)oldctx;
DRIContextPrivPtr newContext = (DRIContextPrivPtr)newctx;
ScreenPtr pScreen = newContext->pScreen;
DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
void* oldContextStore = NULL;
DRIContextType oldContextType;
void* newContextStore = NULL;
DRIContextType newContextType;
DRISyncType syncType;
#ifdef DEBUG
static int count = 0;
#endif
if (!newContext) {
DRIDrvMsg(pScreen->myNum, X_ERROR,
"[DRI] Context Switch Error: oldContext=%x, newContext=%x\n",
oldContext, newContext);
return;
}
#ifdef DEBUG
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) {
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 {
if (newContext->flags & DRI_CONTEXT_2DONLY) {
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) {
oldContextStore = DRIGetContextStore(oldContext);
oldContextType = DRI_2D_CONTEXT;
newContextStore = DRIGetContextStore(newContext);
newContextType = DRI_2D_CONTEXT;
syncType = DRI_2D_SYNC;
}
else {
oldContextStore = DRIGetContextStore(oldContext);
newContextStore =
DRIGetContextStore(pDRIPriv->lastPartial3DContext);
(*pDRIPriv->pDriverInfo->SwapContext)(pScreen,
DRI_2D_SYNC,
DRI_2D_CONTEXT,
oldContextStore,
DRI_2D_CONTEXT,
newContextStore);
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 {
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;
}
}
(*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);
}
if (pDRIPriv && pDRIPriv->wrap.WindowExposures) {
pScreen->WindowExposures = pDRIPriv->wrap.WindowExposures;
(*pScreen->WindowExposures)(pWin, prgn, bsreg);
pDRIPriv->wrap.WindowExposures = pScreen->WindowExposures;
pScreen->WindowExposures = DRIWindowExposures;
}
}
static int
DRITreeTraversal(WindowPtr pWin, pointer data)
{
DRIDrawablePrivPtr pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pWin);
if(pDRIDrawablePriv) {
ScreenPtr pScreen = pWin->drawable.pScreen;
DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
RegionPtr reg = (RegionPtr)data;
REGION_UNION(pScreen, reg, reg, &(pWin->clipList));
if(pDRIPriv->nrWindows == 1)
return WT_STOPWALKING;
}
return WT_WALKCHILDREN;
}
void
DRICopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc)
{
ScreenPtr pScreen = pWin->drawable.pScreen;
DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
if(!pDRIPriv) return;
if(pDRIPriv->nrWindows > 0) {
RegionRec reg;
REGION_NULL(pScreen, ®);
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);
(*pDRIPriv->pDriverInfo->MoveBuffers)(pWin, ptOldOrg, ®,
pDRIPriv->pDriverInfo->ddxDrawableTableEntry);
}
REGION_UNINIT(pScreen, ®);
}
if(pDRIPriv->wrap.CopyWindow) {
pScreen->CopyWindow = pDRIPriv->wrap.CopyWindow;
(*pScreen->CopyWindow)(pWin, ptOldOrg, prgnSrc);
pDRIPriv->wrap.CopyWindow = pScreen->CopyWindow;
pScreen->CopyWindow = DRICopyWindow;
}
}
static void
DRIGetSecs(long *secs, long *usecs)
{
#ifdef XFree86LOADER
getsecs(secs,usecs);
#else
struct timeval tv;
gettimeofday(&tv, NULL);
*secs = tv.tv_sec;
*usecs = tv.tv_usec;
#endif
}
static unsigned long
DRIComputeMilliSeconds(unsigned long s_secs, unsigned long s_usecs,
unsigned long f_secs, unsigned long f_usecs)
{
if (f_usecs < s_usecs) {
--f_secs;
f_usecs += 1000000;
}
return (f_secs - s_secs) * 1000 + (f_usecs - s_usecs) / 1000;
}
static void
DRISpinLockTimeout(drmLock *lock, int val, unsigned long timeout )
{
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;
DRIGetSecs(&f_secs, &f_usecs);
msecs = DRIComputeMilliSeconds(s_secs, s_usecs, f_secs, f_usecs);
if (msecs - prev < 250) count *= 2;
} while (msecs < timeout);
DRM_SPINLOCK_TAKE(lock, val);
}
static void
DRILockTree(ScreenPtr pScreen)
{
DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
if(!pDRIPriv) return;
if (pDRIPriv->pDriverInfo->driverSwapMethod == DRI_HIDE_X_CONTEXT) {
(*pDRIPriv->pDriverInfo->SwapContext)(pScreen,
DRI_2D_SYNC,
DRI_NO_CONTEXT,
NULL,
DRI_2D_CONTEXT,
pDRIPriv->partial3DContextStore);
}
DRIUnlock(pScreen);
DRISpinLockTimeout(&pDRIPriv->pSAREA->drawable_lock, 1, 10000);
DRILock(pScreen, DRM_LOCK_QUIESCENT|DRM_LOCK_FLUSH_ALL);
if (pDRIPriv->pDriverInfo->driverSwapMethod == DRI_HIDE_X_CONTEXT) {
(*pDRIPriv->pDriverInfo->SwapContext)(pScreen,
DRI_3D_SYNC,
DRI_2D_CONTEXT,
pDRIPriv->partial3DContextStore,
DRI_2D_CONTEXT,
pDRIPriv->hiddenContextStore);
}
}
#define DRI_BROKEN
static Bool DRIWindowsTouched = FALSE;
int
DRIValidateTree(WindowPtr pParent, WindowPtr pChild, VTKind kind)
{
ScreenPtr pScreen = pParent->drawable.pScreen;
DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
int returnValue = 1;
if(!pDRIPriv) return returnValue;
DRIWindowsTouched = FALSE;
#ifdef DRI_BROKEN
if(!DRIWindowsTouched) {
DRILockTree(pScreen);
DRIWindowsTouched = TRUE;
}
#endif
if(pDRIPriv->wrap.ValidateTree) {
pScreen->ValidateTree = pDRIPriv->wrap.ValidateTree;
returnValue = (*pScreen->ValidateTree)(pParent, pChild, kind);
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) {
pScreen->PostValidateTree = pDRIPriv->wrap.PostValidateTree;
(*pScreen->PostValidateTree)(pParent, pChild, kind);
pDRIPriv->wrap.PostValidateTree = pScreen->PostValidateTree;
pScreen->PostValidateTree = DRIPostValidateTree;
}
if (DRIWindowsTouched) {
DRM_SPINUNLOCK(&pDRIPriv->pSAREA->drawable_lock, 1);
DRIWindowsTouched = FALSE;
}
}
void
DRIClipNotify(WindowPtr pWin, int dx, int dy)
{
ScreenPtr pScreen = pWin->drawable.pScreen;
DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
DRIDrawablePrivPtr pDRIDrawablePriv;
if(!pDRIPriv) return;
if ((pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pWin))) {
#ifndef DRI_BROKEN
if(!DRIWindowsTouched) {
DRILockTree(pScreen);
DRIWindowsTouched = TRUE;
}
#endif
pDRIPriv->pSAREA->drawableTable[pDRIDrawablePriv->drawableIndex].stamp
= DRIDrawableValidationStamp++;
}
if(pDRIPriv->wrap.ClipNotify) {
pScreen->ClipNotify = pDRIPriv->wrap.ClipNotify;
(*pScreen->ClipNotify)(pWin, dx, dy);
pDRIPriv->wrap.ClipNotify = pScreen->ClipNotify;
pScreen->ClipNotify = DRIClipNotify;
}
}
CARD32
DRIGetDrawableIndex(WindowPtr pWin)
{
ScreenPtr pScreen = pWin->drawable.pScreen;
DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
DRIDrawablePrivPtr pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pWin);
CARD32 index;
if (pDRIDrawablePriv) {
index = pDRIDrawablePriv->drawableIndex;
}
else {
index = pDRIPriv->pDriverInfo->ddxDrawableTableEntry;
}
return index;
}
unsigned int
DRIGetDrawableStamp(ScreenPtr pScreen, CARD32 drawable_index)
{
DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
return pDRIPriv->pSAREA->drawableTable[drawable_index].stamp;
}
void
DRIPrintDrawableLock(ScreenPtr pScreen, char *msg)
{
DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
ErrorF("%s: %d\n", msg, pDRIPriv->pSAREA->drawable_lock.lock);
}
void
DRILock(ScreenPtr pScreen, int flags)
{
DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
if(!pDRIPriv) return;
if (!lockRefCount)
DRM_LOCK(pDRIPriv->drmFD, pDRIPriv->pSAREA, pDRIPriv->myContext, flags);
lockRefCount++;
}
void
DRIUnlock(ScreenPtr pScreen)
{
DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
if(!pDRIPriv) return;
if (lockRefCount > 0) {
lockRefCount--;
}
else {
ErrorF("DRIUnlock called when not locked\n");
return;
}
if (!lockRefCount)
DRM_UNLOCK(pDRIPriv->drmFD, pDRIPriv->pSAREA, pDRIPriv->myContext);
}
void *
DRIGetSAREAPrivate(ScreenPtr pScreen)
{
DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
if (!pDRIPriv) return 0;
return (void *)(((char*)pDRIPriv->pSAREA)+sizeof(XF86DRISAREARec));
}
drmContext
DRIGetContext(ScreenPtr pScreen)
{
DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
if (!pDRIPriv) return 0;
return pDRIPriv->myContext;
}
DRIWrappedFuncsRec *
DRIGetWrappedFuncs(ScreenPtr pScreen)
{
return &(DRI_SCREEN_PRIV(pScreen)->wrap);
}
void
DRIQueryVersion(int *majorVersion,
int *minorVersion,
int *patchVersion)
{
*majorVersion = XF86DRI_MAJOR_VERSION;
*minorVersion = XF86DRI_MINOR_VERSION;
*patchVersion = XF86DRI_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) {
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;
miPointerPosition(&px, &py);
if (px < pScrn->frameX0) px = pScrn->frameX0;
if (px > pScrn->frameX1) px = pScrn->frameX1;
if (py < pScrn->frameY0) py = pScrn->frameY0;
if (py > pScrn->frameY1) py = pScrn->frameY1;
pScreen->SetCursorPosition(pScreen, px, py, TRUE);
return;
}
if (pDRIPriv->wrap.AdjustFrame) {
pScrn->AdjustFrame = pDRIPriv->wrap.AdjustFrame;
(*pScrn->AdjustFrame)(scrnIndex, x, y, flags);
pDRIPriv->wrap.AdjustFrame = pScrn->AdjustFrame;
pScrn->AdjustFrame = DRIAdjustFrame;
}
_DRIAdjustFrame(pScrn, pDRIPriv, x, y);
}
Bool
DRIOpenFullScreen(ScreenPtr pScreen, DrawablePtr pDrawable)
{
DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
WindowPtr pWin = (WindowPtr)pDrawable;
XF86DRIClipRectPtr pClipRects = (void *)REGION_RECTS(&pWin->clipList);
_DRIAdjustFrame(pScrn, pDRIPriv, pScrn->frameX0, pScrn->frameY0);
if (pDrawable->type != DRAWABLE_WINDOW) return FALSE;
if (!pScrn->vtSema) return FALSE;
if (pDrawable->x != pScrn->frameX0
|| pDrawable->y != pScrn->frameY0
|| pDrawable->width != pScrn->frameX1 - pScrn->frameX0 + 1
|| pDrawable->height != pScrn->frameY1 - pScrn->frameY0 + 1) {
return FALSE;
}
if (REGION_NUM_RECTS(&pWin->clipList) != 1) return FALSE;
if (pDrawable->x != pClipRects[0].x1
|| pDrawable->y != pClipRects[0].y1
|| pDrawable->width != pClipRects[0].x2 - pClipRects[0].x1
|| pDrawable->height != pClipRects[0].y2 - pClipRects[0].y1) {
return FALSE;
}
AddResource(pDrawable->id, DRIFullScreenResType, (pointer)pWin);
xf86EnableVTSwitch(FALSE);
pScrn->EnableDisableFBAccess(pScreen->myNum, FALSE);
pScrn->vtSema = FALSE;
pDRIPriv->fullscreen = pDrawable;
DRIClipNotify(pWin, 0, 0);
if (pDRIPriv->pDriverInfo->OpenFullScreen)
pDRIPriv->pDriverInfo->OpenFullScreen(pScreen);
pDRIPriv->pSAREA->frame.fullscreen = 1;
return TRUE;
}
static Bool
_DRICloseFullScreen(pointer pResource, XID id)
{
DrawablePtr pDrawable = (DrawablePtr)pResource;
ScreenPtr pScreen = pDrawable->pScreen;
DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
WindowPtr pWin = (WindowPtr)pDrawable;
WindowOptPtr optional = pWin->optional;
Mask mask = pWin->eventMask;
if (pDRIPriv->pDriverInfo->CloseFullScreen)
pDRIPriv->pDriverInfo->CloseFullScreen(pScreen);
pDRIPriv->fullscreen = NULL;
pScrn->vtSema = TRUE;
pWin->eventMask &= ~ExposureMask;
pWin->optional = NULL;
pScrn->EnableDisableFBAccess(pScreen->myNum, TRUE);
pWin->eventMask = mask;
pWin->optional = optional;
xf86EnableVTSwitch(TRUE);
pDRIPriv->pSAREA->frame.fullscreen = 0;
return TRUE;
}
Bool
DRICloseFullScreen(ScreenPtr pScreen, DrawablePtr pDrawable)
{
FreeResourceByType(pDrawable->id, DRIFullScreenResType, FALSE);
return TRUE;
}
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;
}