diff options
-rw-r--r-- | src/atidri.c | 1508 | ||||
-rw-r--r-- | src/atidri.h | 47 | ||||
-rw-r--r-- | src/atidripriv.h | 59 | ||||
-rw-r--r-- | src/mach64_common.h | 131 | ||||
-rw-r--r-- | src/mach64_dri.h | 126 | ||||
-rw-r--r-- | src/mach64_sarea.h | 163 | ||||
-rw-r--r-- | src/radeon_mergedfb.c | 1560 | ||||
-rw-r--r-- | src/radeon_mergedfb.h | 124 |
8 files changed, 3718 insertions, 0 deletions
diff --git a/src/atidri.c b/src/atidri.c new file mode 100644 index 0000000..d5e1c89 --- /dev/null +++ b/src/atidri.c @@ -0,0 +1,1508 @@ +/* $XFree86$ */ /* -*- mode: c; c-basic-offset: 3 -*- */ +/* + * Copyright 2000 Gareth Hughes + * 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, sublicense, + * 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 NONINFRINGEMENT. IN NO EVENT SHALL + * GARETH HUGHES 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: + * Gareth Hughes <gareth@valinux.com> + * Leif Delgass <ldelgass@retinalburn.net> + */ + +/* Driver data structures */ +#include "ati.h" +#include "atibus.h" +#include "atidri.h" +#include "atiregs.h" +#include "atistruct.h" +#include "ativersion.h" + +#include "atimach64io.h" +#include "mach64_dri.h" +#include "mach64_common.h" +#include "mach64_sarea.h" + +/* X and server generic header files */ +#include "xf86.h" +#include "windowstr.h" + +/* GLX/DRI/DRM definitions */ +#define _XF86DRI_SERVER_ +#include "GL/glxtokens.h" +#include "sarea.h" + +static char ATIKernelDriverName[] = "mach64"; +static char ATIClientDriverName[] = "mach64"; + +/* Initialize the visual configs that are supported by the hardware. + * These are combined with the visual configs that the indirect + * rendering core supports, and the intersection is exported to the + * client. + */ +static Bool ATIInitVisualConfigs( ScreenPtr pScreen ) +{ + ScrnInfoPtr pScreenInfo = xf86Screens[pScreen->myNum]; + ATIPtr pATI = ATIPTR(pScreenInfo); + int numConfigs = 0; + __GLXvisualConfig *pConfigs = NULL; + ATIConfigPrivPtr pATIConfigs = NULL; + ATIConfigPrivPtr *pATIConfigPtrs = NULL; + int i, accum, stencil, db; + + switch ( pATI->bitsPerPixel ) { + case 8: /* 8bpp mode is not support */ + case 15: /* FIXME */ + case 24: /* FIXME */ + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[dri] ATIInitVisualConfigs failed (%d bpp not supported). " + "Disabling DRI.\n", pATI->bitsPerPixel); + return FALSE; + +#define ATI_USE_ACCUM 1 +#define ATI_USE_STENCIL 1 + + case 16: + + if ( pATI->depth != 16) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[dri] ATIInitVisualConfigs failed (depth %d at 16 bpp not supported). " + "Disabling DRI.\n", pATI->depth); + return FALSE; + } + + numConfigs = 1; + if ( ATI_USE_ACCUM ) numConfigs *= 2; + if ( ATI_USE_STENCIL ) numConfigs *= 2; + numConfigs *= 2; /* single- and double-buffered */ + + pConfigs = (__GLXvisualConfig*) + xnfcalloc( sizeof(__GLXvisualConfig), numConfigs ); + if ( !pConfigs ) { + return FALSE; + } + pATIConfigs = (ATIConfigPrivPtr) + xnfcalloc( sizeof(ATIConfigPrivRec), numConfigs ); + if ( !pATIConfigs ) { + xfree( pConfigs ); + return FALSE; + } + pATIConfigPtrs = (ATIConfigPrivPtr*) + xnfcalloc( sizeof(ATIConfigPrivPtr), numConfigs ); + if ( !pATIConfigPtrs ) { + xfree( pConfigs ); + xfree( pATIConfigs ); + return FALSE; + } + + i = 0; + for (db = 0; db <= 1; db++) { + for ( accum = 0 ; accum <= ATI_USE_ACCUM ; accum++ ) { + for ( stencil = 0 ; stencil <= ATI_USE_STENCIL ; stencil++ ) { + pATIConfigPtrs[i] = &pATIConfigs[i]; + + pConfigs[i].vid = -1; + pConfigs[i].class = -1; + pConfigs[i].rgba = TRUE; + pConfigs[i].redSize = 5; + pConfigs[i].greenSize = 6; + pConfigs[i].blueSize = 5; + pConfigs[i].alphaSize = 0; + pConfigs[i].redMask = 0x0000F800; + pConfigs[i].greenMask = 0x000007E0; + pConfigs[i].blueMask = 0x0000001F; + pConfigs[i].alphaMask = 0x00000000; + if ( accum ) { /* Simulated in software */ + pConfigs[i].accumRedSize = 16; + pConfigs[i].accumGreenSize = 16; + pConfigs[i].accumBlueSize = 16; + pConfigs[i].accumAlphaSize = 0; + } else { + pConfigs[i].accumRedSize = 0; + pConfigs[i].accumGreenSize = 0; + pConfigs[i].accumBlueSize = 0; + pConfigs[i].accumAlphaSize = 0; + } + pConfigs[i].doubleBuffer = db ? TRUE : FALSE; + pConfigs[i].stereo = FALSE; + pConfigs[i].bufferSize = 16; + pConfigs[i].depthSize = 16; + if ( stencil ) { /* Simulated in software */ + pConfigs[i].stencilSize = 8; + } else { + pConfigs[i].stencilSize = 0; + } + pConfigs[i].auxBuffers = 0; + pConfigs[i].level = 0; + if ( accum || stencil ) { + pConfigs[i].visualRating = GLX_SLOW_CONFIG; + } else { + pConfigs[i].visualRating = GLX_NONE; + } + pConfigs[i].transparentPixel = GLX_NONE; + pConfigs[i].transparentRed = 0; + pConfigs[i].transparentGreen = 0; + pConfigs[i].transparentBlue = 0; + pConfigs[i].transparentAlpha = 0; + pConfigs[i].transparentIndex = 0; + i++; + } + } + } + break; + + case 32: + numConfigs = 1; + if ( ATI_USE_ACCUM ) numConfigs *= 2; + if ( ATI_USE_STENCIL ) numConfigs *= 2; + numConfigs *= 2; /* single- and double-buffered */ + + pConfigs = (__GLXvisualConfig*) + xnfcalloc( sizeof(__GLXvisualConfig), numConfigs ); + if ( !pConfigs ) { + return FALSE; + } + pATIConfigs = (ATIConfigPrivPtr) + xnfcalloc( sizeof(ATIConfigPrivRec), numConfigs ); + if ( !pATIConfigs ) { + xfree( pConfigs ); + return FALSE; + } + pATIConfigPtrs = (ATIConfigPrivPtr*) + xnfcalloc( sizeof(ATIConfigPrivPtr), numConfigs ); + if ( !pATIConfigPtrs ) { + xfree( pConfigs ); + xfree( pATIConfigs ); + return FALSE; + } + + i = 0; + for (db = 0; db <= 1; db++) { + for ( accum = 0 ; accum <= ATI_USE_ACCUM ; accum++ ) { + for ( stencil = 0 ; stencil <= ATI_USE_STENCIL ; stencil++ ) { + pATIConfigPtrs[i] = &pATIConfigs[i]; + + pConfigs[i].vid = -1; + pConfigs[i].class = -1; + pConfigs[i].rgba = TRUE; + pConfigs[i].redSize = 8; + pConfigs[i].greenSize = 8; + pConfigs[i].blueSize = 8; + pConfigs[i].alphaSize = 0; + pConfigs[i].redMask = 0x00FF0000; + pConfigs[i].greenMask = 0x0000FF00; + pConfigs[i].blueMask = 0x000000FF; + pConfigs[i].alphaMask = 0x00000000; + if ( accum ) { /* Simulated in software */ + pConfigs[i].accumRedSize = 16; + pConfigs[i].accumGreenSize = 16; + pConfigs[i].accumBlueSize = 16; + pConfigs[i].accumAlphaSize = 0; + } else { + pConfigs[i].accumRedSize = 0; + pConfigs[i].accumGreenSize = 0; + pConfigs[i].accumBlueSize = 0; + pConfigs[i].accumAlphaSize = 0; + } + pConfigs[i].doubleBuffer = db ? TRUE : FALSE; + pConfigs[i].stereo = FALSE; + pConfigs[i].bufferSize = 24; + if ( stencil ) { /* Simulated in software */ + pConfigs[i].depthSize = 16; + pConfigs[i].stencilSize = 8; + } else { + pConfigs[i].depthSize = 16; + pConfigs[i].stencilSize = 0; + } + pConfigs[i].auxBuffers = 0; + pConfigs[i].level = 0; + if ( accum || stencil ) { + pConfigs[i].visualRating = GLX_SLOW_CONFIG; + } else { + pConfigs[i].visualRating = GLX_NONE; + } + pConfigs[i].transparentPixel = GLX_NONE; + pConfigs[i].transparentRed = 0; + pConfigs[i].transparentGreen = 0; + pConfigs[i].transparentBlue = 0; + pConfigs[i].transparentAlpha = 0; + pConfigs[i].transparentIndex = 0; + i++; + } + } + } + break; + } + + pATI->numVisualConfigs = numConfigs; + pATI->pVisualConfigs = pConfigs; + pATI->pVisualConfigsPriv = pATIConfigs; + GlxSetVisualConfigs( numConfigs, pConfigs, (void**)pATIConfigPtrs ); + return TRUE; +} + +/* Create the ATI-specific context information */ +static Bool ATICreateContext( ScreenPtr pScreen, VisualPtr visual, + drm_context_t hwContext, void *pVisualConfigPriv, + DRIContextType contextStore ) +{ + /* Nothing yet */ + return TRUE; +} + +/* Destroy the ATI-specific context information */ +static void ATIDestroyContext( ScreenPtr pScreen, drm_context_t hwContext, + DRIContextType contextStore ) +{ + /* Nothing yet */ +} + +/* Called when the X server is woken up to allow the last client's + * context to be saved and the X server's context to be loaded. + * The client detects when it's context is not currently loaded and + * then loads it itself. The X server's context is loaded in the + * XAA Sync callback if NeedDRISync is set. + */ +static void ATIEnterServer( ScreenPtr pScreen ) +{ + ScrnInfoPtr pScreenInfo = xf86Screens[pScreen->myNum]; + ATIPtr pATI = ATIPTR(pScreenInfo); + + if ( pATI->directRenderingEnabled && pATI->pXAAInfo ) { + pATI->pXAAInfo->NeedToSync = TRUE; + pATI->NeedDRISync = TRUE; + } +} + +/* Called when the X server goes to sleep to allow the X server's + * context to be saved and the last client's context to be loaded. + * The client detects when it's context is not currently loaded and + * then loads it itself. The X server keeps track of it's own state. + */ +static void ATILeaveServer( ScreenPtr pScreen ) +{ + /* Nothing yet */ +} + +/* Contexts can be swapped by the X server if necessary. This callback + * is currently only used to perform any functions necessary when + * entering or leaving the X server, and in the future might not be + * necessary. + */ +static void ATIDRISwapContext( ScreenPtr pScreen, + DRISyncType syncType, + DRIContextType oldContextType, + void *oldContext, + DRIContextType newContextType, + void *newContext ) +{ + if ( ( syncType == DRI_3D_SYNC ) && ( oldContextType == DRI_2D_CONTEXT ) && + ( newContextType == DRI_2D_CONTEXT ) ) { + /* Entering from Wakeup */ + ATIEnterServer( pScreen ); + } + if ( ( syncType == DRI_2D_SYNC ) && ( oldContextType == DRI_NO_CONTEXT ) && + ( newContextType == DRI_2D_CONTEXT ) ) { + /* Exiting from Block Handler */ + ATILeaveServer( pScreen ); + } +} + +static void ATIDRITransitionTo2d(ScreenPtr pScreen) +{ + ScrnInfoPtr pScreenInfo = xf86Screens[pScreen->myNum]; + ATIPtr pATI = ATIPTR(pScreenInfo); + + if (pATI->backArea) { + xf86FreeOffscreenArea(pATI->backArea); + pATI->backArea = NULL; + } + if (pATI->depthTexArea) { + xf86FreeOffscreenArea(pATI->depthTexArea); + pATI->depthTexArea = NULL; + } + pATI->have3DWindows = FALSE; +} + +static void ATIDRITransitionTo3d(ScreenPtr pScreen) +{ + ScrnInfoPtr pScreenInfo = xf86Screens[pScreen->myNum]; + ATIPtr pATI = ATIPTR(pScreenInfo); + FBAreaPtr fbArea; + int width, height; + + xf86PurgeUnlockedOffscreenAreas(pScreen); + + xf86QueryLargestOffscreenArea(pScreen, &width, &height, 0, 0, 0); + + xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO, + "Largest offscreen area available: %d x %d\n", + width, height); + + fbArea = xf86AllocateOffscreenArea(pScreen, pScreenInfo->displayWidth, + height - pATI->depthTexLines - + pATI->backLines, + pScreenInfo->displayWidth, NULL, NULL, NULL); + + if (!fbArea) + xf86DrvMsg(pScreen->myNum, X_ERROR, "Unable to reserve placeholder " + "offscreen area, you might experience screen corruption\n"); + + if (!pATI->backArea) { + pATI->backArea = + xf86AllocateOffscreenArea(pScreen, pScreenInfo->displayWidth, + pATI->backLines, + pScreenInfo->displayWidth, + NULL, NULL, NULL); + } + if (!pATI->backArea) + xf86DrvMsg(pScreen->myNum, X_ERROR, "Unable to reserve offscreen area " + "for back buffer, you might experience screen corruption\n"); + + if (!pATI->depthTexArea) { + pATI->depthTexArea = + xf86AllocateOffscreenArea(pScreen, pScreenInfo->displayWidth, + pATI->depthTexLines, + pScreenInfo->displayWidth, + NULL, NULL, NULL); + } + if (!pATI->depthTexArea) + xf86DrvMsg(pScreen->myNum, X_ERROR, "Unable to reserve offscreen area " + "for depth buffer and textures, you might experience screen corruption\n"); + + if (fbArea) + xf86FreeOffscreenArea(fbArea); + + pATI->have3DWindows = TRUE; +} + +/* Initialize the state of the back and depth buffers. */ +static void ATIDRIInitBuffers( WindowPtr pWin, RegionPtr prgn, CARD32 indx ) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + ScrnInfoPtr pScreenInfo = xf86Screens[pScreen->myNum]; + ATIPtr pATI = ATIPTR(pScreenInfo); + ATIDRIServerInfoPtr pATIDRIServer = pATI->pDRIServerInfo; + XAAInfoRecPtr pXAAInfo = pATI->pXAAInfo; + BoxPtr pbox, pboxSave; + int nbox, nboxSave; + int depth; + + depth = 0x0000ffff; + + if (!pXAAInfo) + return; + + if (!pXAAInfo->SetupForSolidFill) + return; + + /* FIXME: Only initialize the back and depth buffers for contexts + that request them */ + + /* FIXME: Use drm clear? (see Radeon driver) */ + + pboxSave = pbox = REGION_RECTS(prgn); + nboxSave = nbox = REGION_NUM_RECTS(prgn); + + (*pXAAInfo->SetupForSolidFill)(pScreenInfo, 0, GXcopy, (CARD32)(-1)); + for (; nbox; nbox--, pbox++) { + (*pXAAInfo->SubsequentSolidFillRect)(pScreenInfo, + pbox->x1 + pATIDRIServer->fbX, + pbox->y1 + pATIDRIServer->fbY, + pbox->x2 - pbox->x1, + pbox->y2 - pbox->y1); + (*pXAAInfo->SubsequentSolidFillRect)(pScreenInfo, + pbox->x1 + pATIDRIServer->backX, + pbox->y1 + pATIDRIServer->backY, + pbox->x2 - pbox->x1, + pbox->y2 - pbox->y1); + } + + pbox = pboxSave; + nbox = nboxSave; + + (*pXAAInfo->SetupForSolidFill)(pScreenInfo, depth, GXcopy, (CARD32)(-1)); + for (; nbox; nbox--, pbox++) + (*pXAAInfo->SubsequentSolidFillRect)(pScreenInfo, + pbox->x1 + pATIDRIServer->depthX, + pbox->y1 + pATIDRIServer->depthY, + pbox->x2 - pbox->x1, + pbox->y2 - pbox->y1); + + pXAAInfo->NeedToSync = TRUE; +} + +/* Copy the back and depth buffers when the X server moves a window. + * + * Note: this function was copied from the Radeon driver... + * + * This routine is a modified form of XAADoBitBlt with the calls to + * ScreenToScreenBitBlt built in. My routine has the prgnSrc as source + * instead of destination. My origin is upside down so the ydir cases + * are reversed. + */ +static void ATIDRIMoveBuffers( WindowPtr pWin, DDXPointRec ptOldOrg, + RegionPtr prgnSrc, CARD32 indx ) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + ScrnInfoPtr pScreenInfo = xf86Screens[pScreen->myNum]; + ATIPtr pATI = ATIPTR(pScreenInfo); + XAAInfoRecPtr pXAAInfo = pATI->pXAAInfo; + + int backOffsetPitch = (((pATI->pDRIServerInfo->backPitch/8) << 22) | + (pATI->pDRIServerInfo->backOffset >> 3)); +#if 0 + int depthOffsetPitch = (((pATI->pDRIServerInfo->depthPitch/8) << 22) | + (pATI->pDRIServerInfo->depthOffset >> 3)); +#endif + BoxPtr pboxTmp, pboxNext, pboxBase; + DDXPointPtr pptTmp; + int xdir, ydir; + + int screenwidth = pScreenInfo->virtualX; + int screenheight = pScreenInfo->virtualY; + + BoxPtr pbox = REGION_RECTS(prgnSrc); + int nbox = REGION_NUM_RECTS(prgnSrc); + + BoxPtr pboxNew1 = NULL; + BoxPtr pboxNew2 = NULL; + DDXPointPtr pptNew1 = NULL; + DDXPointPtr pptNew2 = NULL; + DDXPointPtr pptSrc = &ptOldOrg; + + int dx = pWin->drawable.x - ptOldOrg.x; + int dy = pWin->drawable.y - ptOldOrg.y; + + if (!pXAAInfo) + return; + + if (!pXAAInfo->SetupForScreenToScreenCopy) + return; + + /* FIXME: Only move the back and depth buffers for contexts + * that request them. + */ + + /* If the copy will overlap in Y, reverse the order */ + if (dy > 0) { + ydir = -1; + + if (nbox > 1) { + /* Keep ordering in each band, reverse order of bands */ + pboxNew1 = (BoxPtr)ALLOCATE_LOCAL(sizeof(BoxRec)*nbox); + if (!pboxNew1) return; + pptNew1 = (DDXPointPtr)ALLOCATE_LOCAL(sizeof(DDXPointRec)*nbox); + if (!pptNew1) { + DEALLOCATE_LOCAL(pboxNew1); + return; + } + pboxBase = pboxNext = pbox+nbox-1; + while (pboxBase >= pbox) { + while ((pboxNext >= pbox) && (pboxBase->y1 == pboxNext->y1)) + pboxNext--; + pboxTmp = pboxNext+1; + pptTmp = pptSrc + (pboxTmp - pbox); + while (pboxTmp <= pboxBase) { + *pboxNew1++ = *pboxTmp++; + *pptNew1++ = *pptTmp++; + } + pboxBase = pboxNext; + } + pboxNew1 -= nbox; + pbox = pboxNew1; + pptNew1 -= nbox; + pptSrc = pptNew1; + } + } else { + /* No changes required */ + ydir = 1; + } + + /* If the regions will overlap in X, reverse the order */ + if (dx > 0) { + xdir = -1; + + if (nbox > 1) { + /* reverse order of rects in each band */ + pboxNew2 = (BoxPtr)ALLOCATE_LOCAL(sizeof(BoxRec)*nbox); + pptNew2 = (DDXPointPtr)ALLOCATE_LOCAL(sizeof(DDXPointRec)*nbox); + if (!pboxNew2 || !pptNew2) { + DEALLOCATE_LOCAL(pptNew2); + DEALLOCATE_LOCAL(pboxNew2); + DEALLOCATE_LOCAL(pptNew1); + DEALLOCATE_LOCAL(pboxNew1); + return; + } + pboxBase = pboxNext = pbox; + while (pboxBase < pbox+nbox) { + while ((pboxNext < pbox+nbox) + && (pboxNext->y1 == pboxBase->y1)) + pboxNext++; + pboxTmp = pboxNext; + pptTmp = pptSrc + (pboxTmp - pbox); + while (pboxTmp != pboxBase) { + *pboxNew2++ = *--pboxTmp; + *pptNew2++ = *--pptTmp; + } + pboxBase = pboxNext; + } + pboxNew2 -= nbox; + pbox = pboxNew2; + pptNew2 -= nbox; + pptSrc = pptNew2; + } + } else { + /* No changes are needed */ + xdir = 1; + } + + (*pXAAInfo->SetupForScreenToScreenCopy)(pScreenInfo, xdir, ydir, GXcopy, + (CARD32)(-1), -1); + + for (; nbox-- ; pbox++) { + int xa = pbox->x1; + int ya = pbox->y1; + int destx = xa + dx; + int desty = ya + dy; + int w = pbox->x2 - xa + 1; + int h = pbox->y2 - ya + 1; + + if (destx < 0) xa -= destx, w += destx, destx = 0; + if (desty < 0) ya -= desty, h += desty, desty = 0; + if (destx + w > screenwidth) w = screenwidth - destx; + if (desty + h > screenheight) h = screenheight - desty; + + if (w <= 0) continue; + if (h <= 0) continue; + + ATIMach64WaitForFIFO(pATI, 2); + outf(SRC_OFF_PITCH, backOffsetPitch); + outf(DST_OFF_PITCH, backOffsetPitch); + + (*pXAAInfo->SubsequentScreenToScreenCopy)(pScreenInfo, + xa, ya, + destx, desty, + w, h); +#if 0 + /* FIXME: Move depth buffers? */ + ATIMach64WaitForFIFO(pATI, 2); + outf(SRC_OFF_PITCH, depthOffsetPitch); + outf(DST_OFF_PITCH, depthOffsetPitch); + + if (pATI->depthMoves) + ATIScreenToScreenCopyDepth(pScreenInfo, + xa, ya, + destx, desty, + w, h); +#endif + } + + ATIMach64WaitForFIFO(pATI, 2); + outf(SRC_OFF_PITCH, pATI->NewHW.dst_off_pitch); + outf(DST_OFF_PITCH, pATI->NewHW.src_off_pitch); + + DEALLOCATE_LOCAL(pptNew2); + DEALLOCATE_LOCAL(pboxNew2); + DEALLOCATE_LOCAL(pptNew1); + DEALLOCATE_LOCAL(pboxNew1); + + pXAAInfo->NeedToSync = TRUE; +} + +/* Compute log base 2 of val. */ +static int Mach64MinBits(int val) +{ + int bits; + + if (!val) return 1; + for (bits = 0; val; val >>= 1, ++bits); + return bits; +} + +/* Initialize the AGP state. Request memory for use in AGP space, and + * initialize the Rage Pro registers to point to that memory. + */ +static Bool ATIDRIAgpInit( ScreenPtr pScreen ) +{ + ScrnInfoPtr pScreenInfo = xf86Screens[pScreen->myNum]; + ATIPtr pATI = ATIPTR(pScreenInfo); + ATIDRIServerInfoPtr pATIDRIServer = pATI->pDRIServerInfo; + + unsigned long mode; + unsigned int vendor, device; + int ret; + unsigned long cntl; + int s, l; + + pATIDRIServer->agpSize = ATI_DEFAULT_AGP_SIZE; + pATIDRIServer->agpMode = ATI_DEFAULT_AGP_MODE; + pATIDRIServer->bufferSize = ATI_DEFAULT_BUFFER_SIZE; + pATIDRIServer->ringSize = 16; /* 16 kB ring */ + + if ( drmAgpAcquire( pATI->drmFD ) < 0 ) { + xf86DrvMsg( pScreen->myNum, X_WARNING, "[agp] AGP not available\n" ); + return FALSE; + } + + mode = drmAgpGetMode( pATI->drmFD ); /* Default mode */ + vendor = drmAgpVendorId( pATI->drmFD ); + device = drmAgpDeviceId( pATI->drmFD ); + + if (pATI->OptionAGPMode > 0 && pATI->OptionAGPMode <= ATI_AGP_MAX_MODE) { + pATIDRIServer->agpMode = pATI->OptionAGPMode; + xf86DrvMsg( pScreen->myNum, X_CONFIG, "[agp] Using AGP %dx Mode\n", + pATIDRIServer->agpMode ); + } else if (pATI->OptionAGPMode > 0) { + xf86DrvMsg( pScreen->myNum, X_ERROR, "[agp] Illegal AGP Mode: %d\n", + pATI->OptionAGPMode ); + return FALSE; + } else { + /* If no mode configured, use the default mode obtained from agpgart */ + if ( mode & AGP_MODE_2X ) { + pATIDRIServer->agpMode = 2; + } else if ( mode & AGP_MODE_1X ) { + pATIDRIServer->agpMode = 1; + } + xf86DrvMsg( pScreen->myNum, X_DEFAULT, "[agp] Using AGP %dx Mode\n", + pATIDRIServer->agpMode ); + } + + mode &= ~AGP_MODE_MASK; + switch ( pATIDRIServer->agpMode ) { + case 2: mode |= AGP_MODE_2X; + case 1: default: mode |= AGP_MODE_1X; + } + + if (pATI->OptionAGPSize) { + switch (pATI->OptionAGPSize) { + case 256: + case 128: + case 64: + case 32: + case 16: + case 8: + case 4: + pATIDRIServer->agpSize = pATI->OptionAGPSize; + xf86DrvMsg( pScreen->myNum, X_CONFIG, "[agp] Using %d MB AGP aperture\n", + pATIDRIServer->agpSize ); + break; + default: + xf86DrvMsg( pScreen->myNum, X_ERROR, + "[agp] Illegal aperture size %d MB\n", pATI->OptionAGPSize ); + return FALSE; + } + } else { + xf86DrvMsg( pScreen->myNum, X_DEFAULT, "[agp] Using %d MB AGP aperture\n", + pATIDRIServer->agpSize ); + } + + xf86DrvMsg( pScreen->myNum, X_INFO, + "[agp] Mode 0x%08lx [AGP 0x%04x/0x%04x; Card 0x%04x/0x%04x]\n", + mode, vendor, device, + pATI->PCIInfo->vendor, + pATI->PCIInfo->chipType ); + + if ( drmAgpEnable( pATI->drmFD, mode ) < 0 ) { + xf86DrvMsg( pScreen->myNum, X_ERROR, "[agp] AGP not enabled\n" ); + drmAgpRelease( pATI->drmFD ); + return FALSE; + } + + pATIDRIServer->agpOffset = 0; + + ret = drmAgpAlloc( pATI->drmFD, pATIDRIServer->agpSize*1024*1024, + 0, NULL, &pATIDRIServer->agpHandle ); + if ( ret < 0 ) { + xf86DrvMsg( pScreen->myNum, X_ERROR, "[agp] Out of memory (%d)\n", ret ); + drmAgpRelease( pATI->drmFD ); + return FALSE; + } + xf86DrvMsg( pScreen->myNum, X_INFO, + "[agp] %d kB allocated with handle 0x%08x\n", + pATIDRIServer->agpSize*1024, pATIDRIServer->agpHandle ); + + if ( drmAgpBind( pATI->drmFD, pATIDRIServer->agpHandle, pATIDRIServer->agpOffset) < 0 ) { + xf86DrvMsg( pScreen->myNum, X_ERROR, "[agp] Could not bind\n" ); + drmAgpFree( pATI->drmFD, pATIDRIServer->agpHandle ); + drmAgpRelease( pATI->drmFD ); + return FALSE; + } + + xf86DrvMsg(pScreen->myNum, X_INFO, + "[agp] Using %d kB for DMA descriptor ring\n", pATIDRIServer->ringSize); + + if (pATI->OptionBufferSize) { + if (pATI->OptionBufferSize < 1 || pATI->OptionBufferSize > pATIDRIServer->agpSize ) { + xf86DrvMsg( pScreen->myNum, X_ERROR, "[agp] Illegal DMA buffers size: %d MB\n", + pATI->OptionBufferSize ); + return FALSE; + } + if (pATI->OptionBufferSize > 2) { + xf86DrvMsg( pScreen->myNum, X_WARNING, "[agp] Illegal DMA buffers size: %d MB\n", + pATI->OptionBufferSize ); + xf86DrvMsg( pScreen->myNum, X_WARNING, "[agp] Clamping DMA buffers size to 2 MB\n", + pATI->OptionBufferSize ); + pATIDRIServer->bufferSize = 2; + } else { + pATIDRIServer->bufferSize = pATI->OptionBufferSize; + xf86DrvMsg( pScreen->myNum, X_CONFIG, "[agp] Using %d MB for DMA buffers\n", + pATIDRIServer->bufferSize ); + } + } else { + xf86DrvMsg( pScreen->myNum, X_DEFAULT, "[agp] Using %d MB for DMA buffers\n", + pATIDRIServer->bufferSize ); + } + + pATIDRIServer->agpTexSize = pATIDRIServer->agpSize - pATIDRIServer->bufferSize; + + /* Reserve space for the DMA descriptor ring */ + pATIDRIServer->ringStart = pATIDRIServer->agpOffset; + pATIDRIServer->ringMapSize = pATIDRIServer->ringSize*1024; /* ringSize is in kB */ + + /* Reserve space for the vertex buffer */ + pATIDRIServer->bufferStart = pATIDRIServer->ringStart + pATIDRIServer->ringMapSize; + pATIDRIServer->bufferMapSize = pATIDRIServer->bufferSize*1024*1024; + + /* Reserve the rest for AGP textures */ + pATIDRIServer->agpTexStart = pATIDRIServer->bufferStart + pATIDRIServer->bufferMapSize; + s = (pATIDRIServer->agpSize*1024*1024 - pATIDRIServer->agpTexStart); + l = Mach64MinBits((s-1) / MACH64_NR_TEX_REGIONS); + if (l < MACH64_LOG_TEX_GRANULARITY) l = MACH64_LOG_TEX_GRANULARITY; + pATIDRIServer->agpTexMapSize = (s >> l) << l; + pATIDRIServer->log2AGPTexGran = l; + + xf86DrvMsg(pScreen->myNum, X_INFO, + "[agp] Using %d kB for AGP textures\n", pATIDRIServer->agpTexMapSize/1024); + + /* Map DMA descriptor ring */ + if ( drmAddMap( pATI->drmFD, pATIDRIServer->ringStart, pATIDRIServer->ringMapSize, + DRM_AGP, DRM_RESTRICTED, &pATIDRIServer->ringHandle ) < 0 ) { + xf86DrvMsg( pScreen->myNum, X_ERROR, + "[agp] Could not add ring mapping\n" ); + return FALSE; + } + xf86DrvMsg( pScreen->myNum, X_INFO, + "[agp] ring handle = 0x%08lx\n", + pATIDRIServer->ringHandle ); + + if ( drmMap( pATI->drmFD, pATIDRIServer->ringHandle, + pATIDRIServer->ringMapSize, &pATIDRIServer->ringMap ) < 0 ) { + xf86DrvMsg( pScreen->myNum, X_ERROR, + "[agp] Could not map ring\n" ); + return FALSE; + } + xf86DrvMsg( pScreen->myNum, X_INFO, + "[agp] Ring mapped at 0x%08lx\n", + (unsigned long)pATIDRIServer->ringMap ); + + /* Map vertex buffers */ + if ( drmAddMap( pATI->drmFD, pATIDRIServer->bufferStart, pATIDRIServer->bufferMapSize, + DRM_AGP, 0, &pATIDRIServer->bufferHandle ) < 0 ) { + xf86DrvMsg( pScreen->myNum, X_ERROR, + "[agp] Could not add vertex buffers mapping\n" ); + return FALSE; + } + xf86DrvMsg( pScreen->myNum, X_INFO, + "[agp] vertex buffers handle = 0x%08lx\n", + pATIDRIServer->bufferHandle ); + + if ( drmMap( pATI->drmFD, pATIDRIServer->bufferHandle, + pATIDRIServer->bufferMapSize, &pATIDRIServer->bufferMap ) < 0 ) { + xf86DrvMsg( pScreen->myNum, X_ERROR, + "[agp] Could not map vertex buffers\n" ); + return FALSE; + } + xf86DrvMsg( pScreen->myNum, X_INFO, + "[agp] Vertex buffers mapped at 0x%08lx\n", + (unsigned long)pATIDRIServer->bufferMap ); + + /* Map AGP Textures */ + if (drmAddMap(pATI->drmFD, pATIDRIServer->agpTexStart, pATIDRIServer->agpTexMapSize, + DRM_AGP, 0, &pATIDRIServer->agpTexHandle) < 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[agp] Could not add AGP texture region mapping\n"); + return FALSE; + } + xf86DrvMsg(pScreen->myNum, X_INFO, + "[agp] AGP texture region handle = 0x%08lx\n", + pATIDRIServer->agpTexHandle); + + if (drmMap(pATI->drmFD, pATIDRIServer->agpTexHandle, pATIDRIServer->agpTexMapSize, + &pATIDRIServer->agpTexMap) < 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[agp] Could not map AGP texture region\n"); + return FALSE; + } + xf86DrvMsg(pScreen->myNum, X_INFO, + "[agp] AGP Texture region mapped at 0x%08lx\n", + (unsigned long)pATIDRIServer->agpTexMap); + + /* Initialize Mach64's AGP registers */ + cntl = inm( AGP_CNTL ); + cntl &= ~AGP_APER_SIZE_MASK; + switch ( pATIDRIServer->agpSize ) { + case 256: cntl |= AGP_APER_SIZE_256MB; break; + case 128: cntl |= AGP_APER_SIZE_128MB; break; + case 64: cntl |= AGP_APER_SIZE_64MB; break; + case 32: cntl |= AGP_APER_SIZE_32MB; break; + case 16: cntl |= AGP_APER_SIZE_16MB; break; + case 8: cntl |= AGP_APER_SIZE_8MB; break; + case 4: cntl |= AGP_APER_SIZE_4MB; break; + default: + xf86DrvMsg( pScreen->myNum, X_ERROR, + "[agp] Illegal aperture size %d kB\n", + pATIDRIServer->agpSize*1024 ); + return FALSE; + } + + /* 1 = DATA comes in clock in which TRDY sampled (default) */ + /* 0 = DATA comes in clock after TRDY sampled */ + cntl |= AGP_TRDY_MODE; + + /* 1 = generate all reads as high priority */ + /* 0 = generate all reads as their default priority (default) */ + /* Setting this only works for me at AGP 1x mode (LLD) */ + if (pATIDRIServer->agpMode == 1) { + cntl |= HIGH_PRIORITY_READ_EN; + } else { + cntl &= ~HIGH_PRIORITY_READ_EN; + } + + outm( AGP_BASE, drmAgpBase(pATI->drmFD) ); + outm( AGP_CNTL, cntl ); + + return TRUE; +} + +/* Add a map for the MMIO registers that will be accessed by any + * DRI-based clients. + */ +static Bool ATIDRIMapInit( ScreenPtr pScreen ) +{ + ScrnInfoPtr pScreenInfo = xf86Screens[pScreen->myNum]; + ATIPtr pATI = ATIPTR(pScreenInfo); + ATIDRIServerInfoPtr pATIDRIServer = pATI->pDRIServerInfo; + + pATIDRIServer->regsSize = getpagesize(); + if ( drmAddMap( pATI->drmFD, pATI->Block1Base, + pATIDRIServer->regsSize, + DRM_REGISTERS, DRM_READ_ONLY, + &pATIDRIServer->regsHandle ) < 0 ) { + xf86DrvMsg( pScreen->myNum, X_ERROR, + "[drm] failed to map registers\n" ); + return FALSE; + } + xf86DrvMsg( pScreen->myNum, X_INFO, + "[drm] register handle = 0x%08lx\n", + pATIDRIServer->regsHandle ); + + return TRUE; +} + +/* Initialize the kernel data structures. */ +static Bool ATIDRIKernelInit( ScreenPtr pScreen ) +{ + ScrnInfoPtr pScreenInfo = xf86Screens[pScreen->myNum]; + ATIPtr pATI = ATIPTR(pScreenInfo); + ATIDRIServerInfoPtr pATIDRIServer = pATI->pDRIServerInfo; + drmMach64Init info; + + memset( &info, 0, sizeof(drmMach64Init) ); + + info.func = DRM_MACH64_INIT_DMA; + info.sarea_priv_offset = sizeof(XF86DRISAREARec); + info.is_pci = pATIDRIServer->IsPCI; + info.dma_mode = pATI->OptionDMAMode; + + info.fb_bpp = pATI->bitsPerPixel; + info.front_offset = pATIDRIServer->frontOffset; + info.front_pitch = pATIDRIServer->frontPitch; + info.back_offset = pATIDRIServer->backOffset; + info.back_pitch = pATIDRIServer->backPitch; + + info.depth_bpp = 16; + info.depth_offset = pATIDRIServer->depthOffset; + info.depth_pitch = pATIDRIServer->depthPitch; + + info.fb_offset = pATI->LinearBase; + info.mmio_offset = pATIDRIServer->regsHandle; + info.ring_offset = pATIDRIServer->ringHandle; + info.buffers_offset = pATIDRIServer->bufferHandle; + info.agp_textures_offset = pATIDRIServer->agpTexHandle; + + if ( drmCommandWrite( pATI->drmFD, DRM_MACH64_INIT, + &info, sizeof(drmMach64Init) ) < 0 ) { + return FALSE; + } else { + return TRUE; + } +} + +/* Add a map for the DMA buffers that will be accessed by any + * DRI-based clients. + */ +static Bool ATIDRIAddBuffers( ScreenPtr pScreen ) +{ + ScrnInfoPtr pScreenInfo = xf86Screens[pScreen->myNum]; + ATIPtr pATI = ATIPTR(pScreenInfo); + ATIDRIServerInfoPtr pATIDRIServer = pATI->pDRIServerInfo; + + /* Initialize vertex buffers */ + if ( pATIDRIServer->IsPCI ) { + pATIDRIServer->numBuffers = drmAddBufs( pATI->drmFD, + (pATIDRIServer->bufferSize*1024*1024)/MACH64_BUFFER_SIZE, + MACH64_BUFFER_SIZE, + 0, + 0 ); + } else { + pATIDRIServer->numBuffers = drmAddBufs( pATI->drmFD, + pATIDRIServer->bufferMapSize/MACH64_BUFFER_SIZE, + MACH64_BUFFER_SIZE, + DRM_AGP_BUFFER, + pATIDRIServer->bufferStart ); + } + if ( pATIDRIServer->numBuffers <= 0 ) { + xf86DrvMsg( pScreen->myNum, X_ERROR, + "[drm] Could not create DMA buffers list\n" ); + return FALSE; + } + xf86DrvMsg( pScreen->myNum, X_INFO, + "[drm] Added %d %d byte DMA buffers\n", + pATIDRIServer->numBuffers, MACH64_BUFFER_SIZE ); + + return TRUE; +} + +static Bool ATIDRIMapBuffers( ScreenPtr pScreen ) +{ + ScrnInfoPtr pScreenInfo = xf86Screens[pScreen->myNum]; + ATIPtr pATI = ATIPTR(pScreenInfo); + ATIDRIServerInfoPtr pATIDRIServer = pATI->pDRIServerInfo; + + pATIDRIServer->drmBuffers = drmMapBufs( pATI->drmFD ); + if ( !pATIDRIServer->drmBuffers ) { + xf86DrvMsg( pScreen->myNum, X_ERROR, + "[drm] Failed to map DMA buffers list\n" ); + return FALSE; + } + xf86DrvMsg( pScreen->myNum, X_INFO, + "[drm] Mapped %d DMA buffers at 0x%08lx\n", + pATIDRIServer->drmBuffers->count, + pATIDRIServer->drmBuffers->list->address ); + + return TRUE; +} + +static Bool ATIDRIIrqInit( ScreenPtr pScreen ) +{ + ScrnInfoPtr pScreenInfo = xf86Screens[pScreen->myNum]; + ATIPtr pATI = ATIPTR(pScreenInfo); + + if ( pATI->irq <= 0 ) { + pATI->irq = drmGetInterruptFromBusID(pATI->drmFD, + ((pciConfigPtr)pATI->PCIInfo + ->thisCard)->busnum, + ((pciConfigPtr)pATI->PCIInfo + ->thisCard)->devnum, + ((pciConfigPtr)pATI->PCIInfo + ->thisCard)->funcnum); + if ( pATI->irq <= 0 ) { + xf86DrvMsg(pScreenInfo->scrnIndex, X_ERROR, + "[drm] Couldn't find IRQ for bus id %d:%d:%d\n", + ((pciConfigPtr)pATI->PCIInfo->thisCard)->busnum, + ((pciConfigPtr)pATI->PCIInfo->thisCard)->devnum, + ((pciConfigPtr)pATI->PCIInfo->thisCard)->funcnum); + pATI->irq = 0; + } else if ((drmCtlInstHandler(pATI->drmFD, pATI->irq)) != 0) { + xf86DrvMsg(pScreenInfo->scrnIndex, X_ERROR, + "[drm] Failed to initialize interrupt handler with IRQ %d\n", + pATI->irq); + pATI->irq = 0; + } + + if (pATI->irq) + xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO, + "[drm] Installed interrupt handler, using IRQ %d\n", + pATI->irq); + else { + xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO, + "[drm] Falling back to irq-free operation\n", + pATI->irq); + return FALSE; + } + } + + return TRUE; + +} + +/* Initialize the screen-specific data structures for the DRI and the + * Rage Pro. This is the main entry point to the device-specific + * initialization code. It calls device-independent DRI functions to + * create the DRI data structures and initialize the DRI state. + */ +Bool ATIDRIScreenInit( ScreenPtr pScreen ) +{ + ScrnInfoPtr pScreenInfo = xf86Screens[pScreen->myNum]; + ATIPtr pATI = ATIPTR(pScreenInfo); + DRIInfoPtr pDRIInfo; + ATIDRIPtr pATIDRI; + ATIDRIServerInfoPtr pATIDRIServer; + drmVersionPtr version; + int major, minor, patch; + + /* Check that the GLX, DRI, and DRM modules have been loaded by testing + * for known symbols in each module. + */ + if ( !xf86LoaderCheckSymbol("GlxSetVisualConfigs") ) return FALSE; + if ( !xf86LoaderCheckSymbol("DRIScreenInit") ) return FALSE; + if ( !xf86LoaderCheckSymbol("drmAvailable") ) return FALSE; + if ( !xf86LoaderCheckSymbol("DRIQueryVersion") ) { + xf86DrvMsg( pScreen->myNum, X_ERROR, + "[dri] ATIDRIScreenInit failed (libdri.a too old)\n" ); + return FALSE; + } + + /* Check the DRI version */ + DRIQueryVersion( &major, &minor, &patch ); + if ( major != 4 || minor < 0 ) { + xf86DrvMsg( pScreen->myNum, X_ERROR, + "[dri] ATIDRIScreenInit failed because of a version mismatch.\n" + "[dri] libDRI version is %d.%d.%d but version 4.0.x is needed.\n" + "[dri] Disabling the DRI.\n", + major, minor, patch ); + return FALSE; + } + + switch ( pATI->bitsPerPixel ) { + case 8: + /* These modes are not supported (yet). */ + case 15: + case 24: + xf86DrvMsg( pScreen->myNum, X_ERROR, + "[dri] Direct rendering only supported in 16 and 32 bpp modes\n"); + return FALSE; + + /* Only 16 and 32 color depths are supported currently. */ + case 16: + if ( pATI->depth != 16) { + xf86DrvMsg( pScreen->myNum, X_ERROR, + "[dri] Direct rendering not supported for depth %d at fbbpp 16.\n", pATI->depth ); + return FALSE; + } + break; + case 32: + break; + } + + /* Create the DRI data structure, and fill it in before calling the + * DRIScreenInit(). + */ + pDRIInfo = DRICreateInfoRec(); + if ( !pDRIInfo ) return FALSE; + + pATI->pDRIInfo = pDRIInfo; + pDRIInfo->drmDriverName = ATIKernelDriverName; + pDRIInfo->clientDriverName = ATIClientDriverName; + if (xf86LoaderCheckSymbol("DRICreatePCIBusID")) { + pDRIInfo->busIdString = DRICreatePCIBusID(pATI->PCIInfo); + } else { + pDRIInfo->busIdString = xalloc( 64 ); + sprintf( pDRIInfo->busIdString, + "PCI:%d:%d:%d", + pATI->PCIInfo->bus, + pATI->PCIInfo->device, + pATI->PCIInfo->func ); + } + pDRIInfo->ddxDriverMajorVersion = ATI_VERSION_MAJOR; + pDRIInfo->ddxDriverMinorVersion = ATI_VERSION_MINOR; + pDRIInfo->ddxDriverPatchVersion = ATI_VERSION_PATCH; + pDRIInfo->frameBufferPhysicalAddress = pATI->LinearBase; + pDRIInfo->frameBufferSize = pATI->LinearSize; + pDRIInfo->frameBufferStride = (pScreenInfo->displayWidth * + pATI->FBBytesPerPixel); + pDRIInfo->ddxDrawableTableEntry = ATI_MAX_DRAWABLES; + + if ( SAREA_MAX_DRAWABLES < ATI_MAX_DRAWABLES ) { + pDRIInfo->maxDrawableTableEntry = SAREA_MAX_DRAWABLES; + } else { + pDRIInfo->maxDrawableTableEntry = ATI_MAX_DRAWABLES; + } + + /* For now the mapping works by using a fixed size defined + * in the SAREA header + */ + if ( sizeof(XF86DRISAREARec) + sizeof(ATISAREAPrivRec) > SAREA_MAX ) { + ErrorF( "[dri] Data does not fit in SAREA\n" ); + return FALSE; + } + xf86DrvMsg( pScreenInfo->scrnIndex, X_INFO, "[drm] SAREA %d+%d: %d\n", + sizeof(XF86DRISAREARec), sizeof(ATISAREAPrivRec), + sizeof(XF86DRISAREARec) + sizeof(ATISAREAPrivRec) ); + pDRIInfo->SAREASize = SAREA_MAX; + + pATIDRI = (ATIDRIPtr) xnfcalloc( sizeof(ATIDRIRec), 1 ); + if ( !pATIDRI ) { + DRIDestroyInfoRec( pATI->pDRIInfo ); + pATI->pDRIInfo = NULL; + xf86DrvMsg( pScreenInfo->scrnIndex, X_ERROR, + "[dri] Failed to allocate memory for private record\n" ); + return FALSE; + } + pATIDRIServer = (ATIDRIServerInfoPtr) + xnfcalloc( sizeof(ATIDRIServerInfoRec), 1 ); + if ( !pATIDRIServer ) { + xfree( pATIDRI ); + DRIDestroyInfoRec( pATI->pDRIInfo ); + pATI->pDRIInfo = NULL; + xf86DrvMsg( pScreenInfo->scrnIndex, X_ERROR, + "[dri] Failed to allocate memory for private record\n" ); + return FALSE; + } + + pATI->pDRIServerInfo = pATIDRIServer; + + pDRIInfo->devPrivate = pATIDRI; + pDRIInfo->devPrivateSize = sizeof(ATIDRIRec); + pDRIInfo->contextSize = sizeof(ATIDRIContextRec); + + pDRIInfo->CreateContext = ATICreateContext; + pDRIInfo->DestroyContext = ATIDestroyContext; + pDRIInfo->SwapContext = ATIDRISwapContext; + pDRIInfo->InitBuffers = ATIDRIInitBuffers; + pDRIInfo->MoveBuffers = ATIDRIMoveBuffers; + pDRIInfo->TransitionTo2d = ATIDRITransitionTo2d; + pDRIInfo->TransitionTo3d = ATIDRITransitionTo3d; + pDRIInfo->bufferRequests = DRI_ALL_WINDOWS; + + pDRIInfo->createDummyCtx = TRUE; + pDRIInfo->createDummyCtxPriv = FALSE; + + pATI->have3DWindows = FALSE; + + if ( !DRIScreenInit( pScreen, pDRIInfo, &pATI->drmFD ) ) { + xfree( pATIDRIServer ); + pATI->pDRIServerInfo = NULL; + xfree( pDRIInfo->devPrivate ); + pDRIInfo->devPrivate = NULL; + DRIDestroyInfoRec( pDRIInfo ); + pDRIInfo = NULL; + xf86DrvMsg( pScreen->myNum, X_ERROR, + "[dri] DRIScreenInit Failed\n" ); + return FALSE; + } + + /* Check the DRM lib version. + drmGetLibVersion was not supported in version 1.0, so check for + symbol first to avoid possible crash or hang. + */ + if (xf86LoaderCheckSymbol("drmGetLibVersion")) { + version = drmGetLibVersion(pATI->drmFD); + } else { + /* drmlib version 1.0.0 didn't have the drmGetLibVersion + entry point. Fake it by allocating a version record + via drmGetVersion and changing it to version 1.0.0 + */ + version = drmGetVersion(pATI->drmFD); + version->version_major = 1; + version->version_minor = 0; + version->version_patchlevel = 0; + } + + if (version) { + if (version->version_major != 1 || + version->version_minor < 1) { + /* incompatible drm library version */ + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[dri] ATIDRIScreenInit failed because of a version mismatch.\n" + "[dri] libdrm.a module version is %d.%d.%d but version 1.1.x is needed.\n" + "[dri] Disabling DRI.\n", + version->version_major, + version->version_minor, + version->version_patchlevel); + drmFreeVersion(version); + ATIDRICloseScreen(pScreen); + return FALSE; + } + drmFreeVersion(version); + } + + /* Check the mach64 DRM version */ + version = drmGetVersion( pATI->drmFD ); + if ( version ) { + if ( version->version_major != 1 || + version->version_minor < 0 ) { + /* Incompatible DRM version */ + xf86DrvMsg( pScreen->myNum, X_ERROR, + "[dri] ATIDRIScreenInit failed because of a version mismatch.\n" + "[dri] mach64.o kernel module version is %d.%d.%d, but version 1.0 or greater is needed.\n" + "[dri] Disabling DRI.\n", + version->version_major, + version->version_minor, + version->version_patchlevel ); + drmFreeVersion( version ); + ATIDRICloseScreen( pScreen ); + return FALSE; + } + drmFreeVersion( version ); + } + + switch ( pATI->OptionDMAMode ) { + case MACH64_MODE_DMA_ASYNC: + xf86DrvMsg(pScreen->myNum, X_INFO, "[drm] Will request asynchronous DMA mode\n"); + break; + case MACH64_MODE_DMA_SYNC: + xf86DrvMsg(pScreen->myNum, X_INFO, "[drm] Will request synchronous DMA mode\n"); + break; + case MACH64_MODE_MMIO: + xf86DrvMsg(pScreen->myNum, X_INFO, "[drm] Will request pseudo-DMA (MMIO) mode\n"); + break; + default: + xf86DrvMsg(pScreen->myNum, X_WARNING, "[drm] Unknown DMA mode\n"); + } + + pATIDRIServer->IsPCI = (pATI->BusType == ATI_BUS_PCI || pATI->OptionIsPCI) ? TRUE : FALSE; + + if ( pATI->BusType != ATI_BUS_PCI && pATI->OptionIsPCI ) { + outm( AGP_BASE, 0 ); + outm( AGP_CNTL, 0 ); + xf86DrvMsg(pScreen->myNum, X_CONFIG, "[dri] Forcing PCI mode\n"); + } + + /* Check buffer size option for PCI, since it won't be done in ATIDRIAgpInit */ + if ( pATIDRIServer->IsPCI) { + pATIDRIServer->bufferSize = ATI_DEFAULT_BUFFER_SIZE; + if (pATI->OptionBufferSize) { + if (pATI->OptionBufferSize < 1) { + xf86DrvMsg( pScreen->myNum, X_ERROR, "[pci] Illegal DMA buffers size: %d MB\n", + pATI->OptionBufferSize ); + ATIDRICloseScreen( pScreen ); + return FALSE; + } + if (pATI->OptionBufferSize > 2) { + xf86DrvMsg( pScreen->myNum, X_WARNING, "[pci] Illegal DMA buffers size: %d MB\n", + pATI->OptionBufferSize ); + xf86DrvMsg( pScreen->myNum, X_WARNING, "[pci] Clamping DMA buffers size to 2 MB\n", + pATI->OptionBufferSize ); + pATIDRIServer->bufferSize = 2; + } else { + pATIDRIServer->bufferSize = pATI->OptionBufferSize; + xf86DrvMsg( pScreen->myNum, X_CONFIG, "[pci] Using %d MB DMA buffer size\n", + pATIDRIServer->bufferSize ); + } + } else { + xf86DrvMsg( pScreen->myNum, X_DEFAULT, "[pci] Using %d MB DMA buffer size\n", + pATIDRIServer->bufferSize ); + } + } + + /* Initialize AGP */ + if ( !pATIDRIServer->IsPCI && !ATIDRIAgpInit( pScreen ) ) { + pATIDRIServer->IsPCI = TRUE; + if ( pATI->BusType != ATI_BUS_PCI ) { + outm( AGP_BASE, 0 ); + outm( AGP_CNTL, 0 ); + } + xf86DrvMsg( pScreen->myNum, X_WARNING, "[agp] AGP failed to initialize -- falling back to PCI mode.\n" ); + xf86DrvMsg( pScreen->myNum, X_WARNING, "[agp] Make sure you have the agpgart kernel module loaded.\n" ); + } + + if ( !ATIDRIMapInit( pScreen ) ) { + ATIDRICloseScreen( pScreen ); + return FALSE; + } + + if ( !ATIInitVisualConfigs( pScreen ) ) { + ATIDRICloseScreen( pScreen ); + return FALSE; + } + xf86DrvMsg( pScreenInfo->scrnIndex, X_INFO, + "[dri] Visual configs initialized\n" ); + + xf86DrvMsg( pScreenInfo->scrnIndex, X_INFO, + "[dri] Block 0 base at 0x%08lx\n", pATI->Block0Base ); + + return TRUE; +} + +/* Finish initializing the device-dependent DRI state, and call + * DRIFinishScreenInit() to complete the device-independent DRI + * initialization. + */ +Bool ATIDRIFinishScreenInit( ScreenPtr pScreen ) +{ + ScrnInfoPtr pScreenInfo = xf86Screens[pScreen->myNum]; + ATIPtr pATI = ATIPTR(pScreenInfo); + ATISAREAPrivPtr pSAREAPriv; + ATIDRIPtr pATIDRI; + ATIDRIServerInfoPtr pATIDRIServer; + + pATI->pDRIInfo->driverSwapMethod = DRI_HIDE_X_CONTEXT; + + /* NOTE: DRIFinishScreenInit must be called before *DRIKernelInit + * because *DRIKernelInit requires that the hardware lock is held by + * the X server, and the first time the hardware lock is grabbed is + * in DRIFinishScreenInit. + */ + if ( !DRIFinishScreenInit( pScreen ) ) { + ATIDRICloseScreen( pScreen ); + return FALSE; + } + + /* Initialize the DMA buffer list */ + /* Need to do this before ATIDRIKernelInit so we can init the freelist */ + if ( !ATIDRIAddBuffers( pScreen ) ) { + ATIDRICloseScreen( pScreen ); + return FALSE; + } + + /* Initialize the kernel data structures */ + if ( !ATIDRIKernelInit( pScreen ) ) { + xf86DrvMsg(pScreenInfo->scrnIndex, X_ERROR, + "[drm] Failed to initialize the mach64.o kernel module\n"); + xf86DrvMsg(pScreenInfo->scrnIndex, X_ERROR, + "[drm] Check the system log for more information.\n"); + ATIDRICloseScreen( pScreen ); + return FALSE; + } + + if ( !ATIDRIMapBuffers( pScreen ) ) { + ATIDRICloseScreen( pScreen ); + return FALSE; + } + + /* Initialize IRQ */ + ATIDRIIrqInit( pScreen ); + + pSAREAPriv = (ATISAREAPrivPtr) DRIGetSAREAPrivate( pScreen ); + memset( pSAREAPriv, 0, sizeof(*pSAREAPriv) ); + + pATIDRI = (ATIDRIPtr)pATI->pDRIInfo->devPrivate; + pATIDRIServer = pATI->pDRIServerInfo; + + pATIDRI->width = pScreenInfo->virtualX; + pATIDRI->height = pScreenInfo->virtualY; + pATIDRI->mem = pScreenInfo->videoRam * 1024; + pATIDRI->cpp = pScreenInfo->bitsPerPixel / 8; + + pATIDRI->IsPCI = pATIDRIServer->IsPCI; + pATIDRI->AGPMode = pATIDRIServer->agpMode; + + pATIDRI->frontOffset = pATIDRIServer->frontOffset; + pATIDRI->frontPitch = pATIDRIServer->frontPitch; + + pATIDRI->backOffset = pATIDRIServer->backOffset; + pATIDRI->backPitch = pATIDRIServer->backPitch; + + pATIDRI->depthOffset = pATIDRIServer->depthOffset; + pATIDRI->depthPitch = pATIDRIServer->depthPitch; + + pATIDRI->textureOffset = pATIDRIServer->textureOffset; + pATIDRI->textureSize = pATIDRIServer->textureSize; + pATIDRI->logTextureGranularity = pATIDRIServer->logTextureGranularity; + + pATIDRI->regs = pATIDRIServer->regsHandle; + pATIDRI->regsSize = pATIDRIServer->regsSize; + + pATIDRI->agp = pATIDRIServer->agpTexHandle; + pATIDRI->agpSize = pATIDRIServer->agpTexMapSize; + pATIDRI->logAgpTextureGranularity = pATIDRIServer->log2AGPTexGran; + pATIDRI->agpTextureOffset = pATIDRIServer->agpTexStart; + + return TRUE; +} + +/* The screen is being closed, so clean up any state and free any + * resources used by the DRI. + */ +void ATIDRICloseScreen( ScreenPtr pScreen ) +{ + ScrnInfoPtr pScreenInfo = xf86Screens[pScreen->myNum]; + ATIPtr pATI = ATIPTR(pScreenInfo); + ATIDRIServerInfoPtr pATIDRIServer = pATI->pDRIServerInfo; + drmMach64Init info; + + /* Stop interrupt generation and handling if used */ + if ( pATI->irq > 0 ) { + if ( drmCtlUninstHandler(pATI->drmFD) != 0 ) { + xf86DrvMsg(pScreenInfo->scrnIndex, X_ERROR, + "[drm] Error uninstalling interrupt handler for IRQ %d\n", pATI->irq); + } else { + xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO, + "[drm] Uninstalled interrupt handler for IRQ %d\n", pATI->irq); + } + pATI->irq = 0; + } + + /* De-allocate DMA buffers */ + if ( pATIDRIServer->drmBuffers ) { + drmUnmapBufs( pATIDRIServer->drmBuffers ); + pATIDRIServer->drmBuffers = NULL; + } + + /* De-allocate all kernel resources */ + memset(&info, 0, sizeof(drmMach64Init)); + info.func = DRM_MACH64_CLEANUP_DMA; + drmCommandWrite( pATI->drmFD, DRM_MACH64_INIT, + &info, sizeof(drmMach64Init) ); + + /* De-allocate all AGP resources */ + if ( pATIDRIServer->agpTexMap ) { + drmUnmap( pATIDRIServer->agpTexMap, pATIDRIServer->agpTexMapSize ); + pATIDRIServer->agpTexMap = NULL; + } + if ( pATIDRIServer->bufferMap ) { + drmUnmap( pATIDRIServer->bufferMap, pATIDRIServer->bufferMapSize ); + pATIDRIServer->bufferMap = NULL; + } + if ( pATIDRIServer->agpHandle ) { + drmAgpUnbind( pATI->drmFD, pATIDRIServer->agpHandle ); + drmAgpFree( pATI->drmFD, pATIDRIServer->agpHandle ); + pATIDRIServer->agpHandle = 0; + drmAgpRelease( pATI->drmFD ); + } + + /* De-allocate all DRI resources */ + DRICloseScreen( pScreen ); + + /* De-allocate all DRI data structures */ + if ( pATI->pDRIInfo ) { + if ( pATI->pDRIInfo->devPrivate ) { + xfree( pATI->pDRIInfo->devPrivate ); + pATI->pDRIInfo->devPrivate = NULL; + } + DRIDestroyInfoRec( pATI->pDRIInfo ); + pATI->pDRIInfo = NULL; + } + if ( pATI->pDRIServerInfo ) { + xfree( pATI->pDRIServerInfo ); + pATI->pDRIServerInfo = NULL; + } + if ( pATI->pVisualConfigs ) { + xfree( pATI->pVisualConfigs ); + pATI->pVisualConfigs = NULL; + } + if ( pATI->pVisualConfigsPriv ) { + xfree( pATI->pVisualConfigsPriv ); + pATI->pVisualConfigsPriv = NULL; + } +} diff --git a/src/atidri.h b/src/atidri.h new file mode 100644 index 0000000..a0319a6 --- /dev/null +++ b/src/atidri.h @@ -0,0 +1,47 @@ +/* $XFree86$ */ /* -*- mode: c; c-basic-offset: 3 -*- */ +/* + * Copyright 2000 Gareth Hughes + * 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, sublicense, + * 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 NONINFRINGEMENT. IN NO EVENT SHALL + * GARETH HUGHES 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: + * Gareth Hughes <gareth@valinux.com> + * Leif Delgass <ldelgass@retinalburn.net> + */ + +#ifndef __ATIDRI_H__ +#define __ATIDRI_H__ 1 + +#include "atiproto.h" + +/* DRI driver defaults */ +#define ATI_DEFAULT_AGP_SIZE 8 /* MB (must be a power of 2 and > 4MB) */ +#define ATI_DEFAULT_AGP_MODE 1 +#define ATI_DEFAULT_BUFFER_SIZE 2 /* MB (must be page aligned) */ + +#define ATI_AGP_MAX_MODE 2 + +extern Bool ATIDRIScreenInit FunctionPrototype((ScreenPtr)); +extern Bool ATIDRIFinishScreenInit FunctionPrototype((ScreenPtr)); +extern void ATIDRICloseScreen FunctionPrototype((ScreenPtr)); + +#endif /* __ATIDRI_H__ */ diff --git a/src/atidripriv.h b/src/atidripriv.h new file mode 100644 index 0000000..b16b14e --- /dev/null +++ b/src/atidripriv.h @@ -0,0 +1,59 @@ +/* $XFree86$ */ /* -*- mode: c; c-basic-offset: 3 -*- */ +/* + * Copyright 1999, 2000 ATI Technologies Inc., Markham, Ontario, + * Precision Insight, Inc., Cedar Park, Texas, and + * VA Linux Systems Inc., Fremont, California. + * + * 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 on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, 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 ATI, PRECISION INSIGHT, VA LINUX + * SYSTEMS AND/OR THEIR 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: + * Gareth Hughes <gareth@valinux.com> + * Leif Delgass <ldelgass@retinalburn.net> + */ + +#ifndef __ATIDRIPRIV_H__ +#define __ATIDRIPRIV_H__ 1 + +#include "GL/glxint.h" +#include "GL/glxtokens.h" + +#include "atiproto.h" + +#define ATI_MAX_DRAWABLES 256 + +typedef struct { + /* Nothing here yet */ + int dummy; +} ATIConfigPrivRec, *ATIConfigPrivPtr; + +typedef struct { + /* Nothing here yet */ + int dummy; +} ATIDRIContextRec, *ATIDRIContextPtr; + +extern void GlxSetVisualConfigs FunctionPrototype((int, __GLXvisualConfig *, void **)); + +#endif /* __ATIDRIPRIV_H__ */ diff --git a/src/mach64_common.h b/src/mach64_common.h new file mode 100644 index 0000000..00609e3 --- /dev/null +++ b/src/mach64_common.h @@ -0,0 +1,131 @@ +/* $XFree86$ */ /* -*- mode: c; c-basic-offset: 3 -*- */ +/* mach64_common.h -- common header definitions for Rage Pro 2D/3D/DRM suite + * Created: Sun Dec 03 11:34:16 2000 by gareth@valinux.com + * + * Copyright 2000 Gareth Hughes + * 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, sublicense, + * 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 NONINFRINGEMENT. IN NO EVENT SHALL + * GARETH HUGHES 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. + * + * Author: + * Gareth Hughes <gareth@valinux.com> + * Leif Delgass <ldelgass@retinalburn.net> + */ + +#ifndef __MACH64_COMMON_H__ +#define __MACH64_COMMON_H__ 1 + +/* WARNING: If you change any of these defines, make sure to change + * the kernel include file as well (mach64_drm.h) + */ + +/* Driver specific DRM command indices + * NOTE: these are not OS specific, but they are driver specific + */ +#define DRM_MACH64_INIT 0x00 +#define DRM_MACH64_IDLE 0x01 +#define DRM_MACH64_RESET 0x02 +#define DRM_MACH64_SWAP 0x03 +#define DRM_MACH64_CLEAR 0x04 +#define DRM_MACH64_VERTEX 0x05 +#define DRM_MACH64_BLIT 0x06 +#define DRM_MACH64_FLUSH 0x07 +#define DRM_MACH64_GETPARAM 0x08 + +/* Buffer flags for clears + */ +#define MACH64_FRONT 0x1 +#define MACH64_BACK 0x2 +#define MACH64_DEPTH 0x4 + +/* Primitive types for vertex buffers + */ +#define MACH64_PRIM_POINTS 0x00000000 +#define MACH64_PRIM_LINES 0x00000001 +#define MACH64_PRIM_LINE_LOOP 0x00000002 +#define MACH64_PRIM_LINE_STRIP 0x00000003 +#define MACH64_PRIM_TRIANGLES 0x00000004 +#define MACH64_PRIM_TRIANGLE_STRIP 0x00000005 +#define MACH64_PRIM_TRIANGLE_FAN 0x00000006 +#define MACH64_PRIM_QUADS 0x00000007 +#define MACH64_PRIM_QUAD_STRIP 0x00000008 +#define MACH64_PRIM_POLYGON 0x00000009 + + +typedef enum _drmMach64DMAMode { + MACH64_MODE_DMA_ASYNC, + MACH64_MODE_DMA_SYNC, + MACH64_MODE_MMIO +} drmMach64DMAMode; + +typedef struct { + enum { + DRM_MACH64_INIT_DMA = 0x01, + DRM_MACH64_CLEANUP_DMA = 0x02 + } func; + unsigned long sarea_priv_offset; + int is_pci; + drmMach64DMAMode dma_mode; + + unsigned int fb_bpp; + unsigned int front_offset, front_pitch; + unsigned int back_offset, back_pitch; + + unsigned int depth_bpp; + unsigned int depth_offset, depth_pitch; + + unsigned long fb_offset; + unsigned long mmio_offset; + unsigned long ring_offset; + unsigned long buffers_offset; + unsigned long agp_textures_offset; +} drmMach64Init; + +typedef struct { + unsigned int flags; + int x, y, w, h; + unsigned int clear_color; + unsigned int clear_depth; +} drmMach64Clear; + +typedef struct { + int prim; + void *buf; /* Address of vertex buffer */ + unsigned long used; /* Number of bytes in buffer */ + int discard; /* Client finished with buffer? */ +} drmMach64Vertex; + +typedef struct { + int idx; + int pitch; + int offset; + int format; + unsigned short x, y; + unsigned short width, height; +} drmMach64Blit; + +typedef struct { + int param; + int *value; +} drmMach64GetParam; + +#define MACH64_PARAM_FRAMES_QUEUED 1 +#define MACH64_PARAM_IRQ_NR 2 + +#endif /* __MACH64_COMMON_H__ */ diff --git a/src/mach64_dri.h b/src/mach64_dri.h new file mode 100644 index 0000000..139668e --- /dev/null +++ b/src/mach64_dri.h @@ -0,0 +1,126 @@ +/* $XFree86$ */ /* -*- mode: c; c-basic-offset: 3 -*- */ +/* + * Copyright 2000 Gareth Hughes + * 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, sublicense, + * 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 NONINFRINGEMENT. IN NO EVENT SHALL + * GARETH HUGHES 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: + * Gareth Hughes <gareth@valinux.com> + * Leif Delgass <ldelgass@retinalburn.net> + */ + +#ifndef __MACH64_DRI_H__ +#define __MACH64_DRI_H__ 1 + +#include "xf86drm.h" + +typedef struct { + drm_handle_t fbHandle; + + drm_handle_t regsHandle; + drmSize regsSize; + + int IsPCI; + + drm_handle_t agpHandle; /* Handle from drmAgpAlloc */ + unsigned long agpOffset; + drmSize agpSize; + int agpMode; + + /* DMA descriptor ring */ + unsigned long ringStart; /* Offset into AGP space */ + drm_handle_t ringHandle; /* Handle from drmAddMap */ + drmSize ringMapSize; /* Size of map */ + int ringSize; /* Size of ring (in kB) */ + drmAddress ringMap; /* Map */ + + /* vertex buffer data */ + unsigned long bufferStart; /* Offset into AGP space */ + drm_handle_t bufferHandle; /* Handle from drmAddMap */ + drmSize bufferMapSize; /* Size of map */ + int bufferSize; /* Size of buffers (in MB) */ + drmAddress bufferMap; /* Map */ + + drmBufMapPtr drmBuffers; /* Buffer map */ + int numBuffers; /* Number of buffers */ + + /* AGP Texture data */ + unsigned long agpTexStart; /* Offset into AGP space */ + drm_handle_t agpTexHandle; /* Handle from drmAddMap */ + drmSize agpTexMapSize; /* Size of map */ + int agpTexSize; /* Size of AGP tex space (in MB) */ + drmAddress agpTexMap; /* Map */ + int log2AGPTexGran; + + int fbX; + int fbY; + int backX; + int backY; + int depthX; + int depthY; + + int frontOffset; + int frontPitch; + int backOffset; + int backPitch; + int depthOffset; + int depthPitch; + + int textureOffset; + int textureSize; + int logTextureGranularity; +} ATIDRIServerInfoRec, *ATIDRIServerInfoPtr; + +typedef struct { + int chipset; + int width; + int height; + int mem; + int cpp; + + int IsPCI; + int AGPMode; + + unsigned int frontOffset; + unsigned int frontPitch; + + unsigned int backOffset; + unsigned int backPitch; + + unsigned int depthOffset; + unsigned int depthPitch; + + unsigned int textureOffset; + unsigned int textureSize; + int logTextureGranularity; + + drm_handle_t regs; + drmSize regsSize; + + drm_handle_t agp; + drmSize agpSize; + unsigned int agpTextureOffset; + unsigned int agpTextureSize; + int logAgpTextureGranularity; +} ATIDRIRec, *ATIDRIPtr; + +#endif /* __MACH64_DRI_H__ */ diff --git a/src/mach64_sarea.h b/src/mach64_sarea.h new file mode 100644 index 0000000..47a4bf9 --- /dev/null +++ b/src/mach64_sarea.h @@ -0,0 +1,163 @@ +/* $XFree86$ */ /* -*- mode: c; c-basic-offset: 3 -*- */ +/* + * Copyright 2000 Gareth Hughes + * 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, sublicense, + * 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 NONINFRINGEMENT. IN NO EVENT SHALL + * GARETH HUGHES 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: + * Gareth Hughes <gareth@valinux.com> + * Leif Delgass <ldelgass@retinalburn.net> + */ + +#ifndef __MACH64_SAREA_H__ +#define __MACH64_SAREA_H__ 1 + +#include "Xmd.h" + +/* WARNING: If you change any of these defines, make sure to change the + * defines in the kernel file (mach64_drm.h) + */ +#ifndef __MACH64_SAREA_DEFINES__ +#define __MACH64_SAREA_DEFINES__ 1 + +/* What needs to be changed for the current vertex buffer? + * GH: We're going to be pedantic about this. We want the card to do as + * little as possible, so let's avoid having it fetch a whole bunch of + * register values that don't change all that often, if at all. + */ +#define MACH64_UPLOAD_DST_OFF_PITCH 0x0001 +#define MACH64_UPLOAD_Z_OFF_PITCH 0x0002 +#define MACH64_UPLOAD_Z_ALPHA_CNTL 0x0004 +#define MACH64_UPLOAD_SCALE_3D_CNTL 0x0008 +#define MACH64_UPLOAD_DP_FOG_CLR 0x0010 +#define MACH64_UPLOAD_DP_WRITE_MASK 0x0020 +#define MACH64_UPLOAD_DP_PIX_WIDTH 0x0040 +#define MACH64_UPLOAD_SETUP_CNTL 0x0080 +#define MACH64_UPLOAD_MISC 0x0100 +#define MACH64_UPLOAD_TEXTURE 0x0200 +#define MACH64_UPLOAD_TEX0IMAGE 0x0400 +#define MACH64_UPLOAD_TEX1IMAGE 0x0800 +#define MACH64_UPLOAD_CLIPRECTS 0x1000 /* handled client-side */ +#define MACH64_UPLOAD_CONTEXT 0x00ff +#define MACH64_UPLOAD_ALL 0x1fff + +/* DMA buffer size + */ +#define MACH64_BUFFER_SIZE 16384 + +/* Max number of swaps allowed on the ring + * before the client must wait + */ +#define MACH64_MAX_QUEUED_FRAMES 3 + +/* Byte offsets for host blit buffer data + */ +#define MACH64_HOSTDATA_BLIT_OFFSET 104 + +/* Keep these small for testing. + */ +#define MACH64_NR_SAREA_CLIPRECTS 8 + + +#define MACH64_CARD_HEAP 0 +#define MACH64_AGP_HEAP 1 +#define MACH64_NR_TEX_HEAPS 2 +#define MACH64_NR_TEX_REGIONS 64 +#define MACH64_LOG_TEX_GRANULARITY 16 + +#define MACH64_TEX_MAXLEVELS 1 + +#define MACH64_NR_CONTEXT_REGS 15 +#define MACH64_NR_TEXTURE_REGS 4 + +#endif /* __MACH64_SAREA_DEFINES__ */ + +typedef struct { + /* Context state */ + unsigned int dst_off_pitch; /* 0x500 */ + + unsigned int z_off_pitch; /* 0x548 */ /* ****** */ + unsigned int z_cntl; /* 0x54c */ + unsigned int alpha_tst_cntl; /* 0x550 */ + + unsigned int scale_3d_cntl; /* 0x5fc */ + + unsigned int sc_left_right; /* 0x6a8 */ + unsigned int sc_top_bottom; /* 0x6b4 */ + + unsigned int dp_fog_clr; /* 0x6c4 */ + unsigned int dp_write_mask; /* 0x6c8 */ + unsigned int dp_pix_width; /* 0x6d0 */ + unsigned int dp_mix; /* 0x6d4 */ /* ****** */ + unsigned int dp_src; /* 0x6d8 */ /* ****** */ + + unsigned int clr_cmp_cntl; /* 0x708 */ /* ****** */ + unsigned int gui_traj_cntl; /* 0x730 */ /* ****** */ + + unsigned int setup_cntl; /* 0x304 */ + + /* Texture state */ + unsigned int tex_size_pitch; /* 0x770 */ + unsigned int tex_cntl; /* 0x774 */ + unsigned int secondary_tex_off; /* 0x778 */ + unsigned int tex_offset; /* 0x5c0 */ +} mach64_context_regs_t; + +typedef struct { + /* The channel for communication of state information to the kernel + * on firing a vertex buffer. + */ + mach64_context_regs_t ContextState; + unsigned int dirty; + unsigned int vertsize; + +#ifdef XF86DRI + /* The current cliprects, or a subset thereof. + */ + drm_clip_rect_t boxes[MACH64_NR_SAREA_CLIPRECTS]; + unsigned int nbox; +#endif + /* Counter for throttling of rendering clients. + */ + unsigned int frames_queued; + + /* Maintain an LRU of contiguous regions of texture space. If you + * think you own a region of texture memory, and it has an age + * different to the one you set, then you are mistaken and it has + * been stolen by another client. If global texAge hasn't changed, + * there is no need to walk the list. + * + * These regions can be used as a proxy for the fine-grained texture + * information of other clients - by maintaining them in the same + * lru which is used to age their own textures, clients have an + * approximate lru for the whole of global texture space, and can + * make informed decisions as to which areas to kick out. There is + * no need to choose whether to kick out your own texture or someone + * else's - simply eject them all in LRU order. + */ + drmTextureRegion texList[MACH64_NR_TEX_HEAPS][MACH64_NR_TEX_REGIONS+1]; + unsigned int texAge[MACH64_NR_TEX_HEAPS]; + + int ctxOwner; /* last context to upload state */ +} ATISAREAPrivRec, *ATISAREAPrivPtr; + +#endif /* __MACH64_SAREA_H__ */ diff --git a/src/radeon_mergedfb.c b/src/radeon_mergedfb.c new file mode 100644 index 0000000..e9910e8 --- /dev/null +++ b/src/radeon_mergedfb.c @@ -0,0 +1,1560 @@ +/* $XFree86$ */ +/* + * Copyright 2003 Alex Deucher. + * + * 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 on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, 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 ALEX DEUCHER, OR ANY OTHER + * CONTRIBUTORS 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: + * Alex Deucher <agd5f@yahoo.com> + */ + +#include "xf86.h" +#include "xf86Priv.h" +#include "xf86Resources.h" +#include "xf86_OSproc.h" +#include "extnsionst.h" /* required */ +#include "panoramiXproto.h" /* required */ +#include "dixstruct.h" +#include "vbe.h" + + +#include "radeon.h" +#include "radeon_macros.h" +#include "radeon_reg.h" +#include "radeon_mergedfb.h" + +/* psuedo xinerama support */ +static unsigned char RADEONXineramaReqCode = 0; +int RADEONXineramaPixWidth = 0; +int RADEONXineramaPixHeight = 0; +int RADEONXineramaNumScreens = 0; +RADEONXineramaData *RADEONXineramadataPtr = NULL; +static int RADEONXineramaGeneration; +Bool RADEONnoPanoramiXExtension = TRUE; + +int RADEONProcXineramaQueryVersion(ClientPtr client); +int RADEONProcXineramaGetState(ClientPtr client); +int RADEONProcXineramaGetScreenCount(ClientPtr client); +int RADEONProcXineramaGetScreenSize(ClientPtr client); +int RADEONProcXineramaIsActive(ClientPtr client); +int RADEONProcXineramaQueryScreens(ClientPtr client); +int RADEONSProcXineramaDispatch(ClientPtr client); + +static void +RADEONChooseCursorCRTC(ScrnInfoPtr pScrn1, int x, int y); + +/* mergedfb functions */ +/* Helper function for CRT2 monitor vrefresh/hsync options + * (Taken from mga, sis drivers) + */ +int +RADEONStrToRanges(range *r, char *s, int max) +{ + float num = 0.0; + int rangenum = 0; + Bool gotdash = FALSE; + Bool nextdash = FALSE; + char* strnum = NULL; + do { + switch(*s) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '.': + if(strnum == NULL) { + strnum = s; + gotdash = nextdash; + nextdash = FALSE; + } + break; + case '-': + case ' ': + case 0: + if(strnum == NULL) break; + sscanf(strnum, "%f", &num); + strnum = NULL; + if(gotdash) + r[rangenum - 1].hi = num; + else { + r[rangenum].lo = num; + r[rangenum].hi = num; + rangenum++; + } + if(*s == '-') nextdash = (rangenum != 0); + else if(rangenum >= max) return rangenum; + break; + default : + return 0; + } + } while(*(s++) != 0); + + return rangenum; +} + +/* Copy and link two modes form merged-fb mode + * (Taken from mga, sis drivers) + * Copys mode i, links the result to dest, and returns it. + * Links i and j in Private record. + * If dest is NULL, return value is copy of i linked to itself. + * For mergedfb auto-config, we only check the dimension + * against virtualX/Y, if they were user-provided. + */ +static DisplayModePtr +RADEONCopyModeNLink(ScrnInfoPtr pScrn, DisplayModePtr dest, + DisplayModePtr i, DisplayModePtr j, + RADEONScrn2Rel srel) +{ + DisplayModePtr mode; + int dx = 0,dy = 0; + RADEONInfoPtr info = RADEONPTR(pScrn); + + if(!((mode = xalloc(sizeof(DisplayModeRec))))) return dest; + memcpy(mode, i, sizeof(DisplayModeRec)); + if(!((mode->Private = xalloc(sizeof(RADEONMergedDisplayModeRec))))) { + xfree(mode); + return dest; + } + ((RADEONMergedDisplayModePtr)mode->Private)->CRT1 = i; + ((RADEONMergedDisplayModePtr)mode->Private)->CRT2 = j; + ((RADEONMergedDisplayModePtr)mode->Private)->CRT2Position = srel; + mode->PrivSize = 0; + + switch(srel) { + case radeonLeftOf: + case radeonRightOf: + if(!(pScrn->display->virtualX)) { + dx = i->HDisplay + j->HDisplay; + } else { + dx = min(pScrn->virtualX, i->HDisplay + j->HDisplay); + } + dx -= mode->HDisplay; + if(!(pScrn->display->virtualY)) { + dy = max(i->VDisplay, j->VDisplay); + } else { + dy = min(pScrn->virtualY, max(i->VDisplay, j->VDisplay)); + } + dy -= mode->VDisplay; + break; + case radeonAbove: + case radeonBelow: + if(!(pScrn->display->virtualY)) { + dy = i->VDisplay + j->VDisplay; + } else { + dy = min(pScrn->virtualY, i->VDisplay + j->VDisplay); + } + dy -= mode->VDisplay; + if(!(pScrn->display->virtualX)) { + dx = max(i->HDisplay, j->HDisplay); + } else { + dx = min(pScrn->virtualX, max(i->HDisplay, j->HDisplay)); + } + dx -= mode->HDisplay; + break; + case radeonClone: + if(!(pScrn->display->virtualX)) { + dx = max(i->HDisplay, j->HDisplay); + } else { + dx = min(pScrn->virtualX, max(i->HDisplay, j->HDisplay)); + } + dx -= mode->HDisplay; + if(!(pScrn->display->virtualY)) { + dy = max(i->VDisplay, j->VDisplay); + } else { + dy = min(pScrn->virtualY, max(i->VDisplay, j->VDisplay)); + } + dy -= mode->VDisplay; + break; + } + mode->HDisplay += dx; + mode->HSyncStart += dx; + mode->HSyncEnd += dx; + mode->HTotal += dx; + mode->VDisplay += dy; + mode->VSyncStart += dy; + mode->VSyncEnd += dy; + mode->VTotal += dy; + mode->Clock = 0; + + if( ((mode->HDisplay * ((pScrn->bitsPerPixel + 7) / 8) * mode->VDisplay) > + (pScrn->videoRam * 1024)) || + (mode->HDisplay > 8192) || + (mode->VDisplay > 8192) ) { + + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Skipped %dx%d, not enough video RAM or beyond hardware specs\n", + mode->HDisplay, mode->VDisplay); + xfree(mode->Private); + xfree(mode); + + return dest; + } + + if(srel != radeonClone) { + info->AtLeastOneNonClone = TRUE; + } + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Merged %dx%d and %dx%d to %dx%d%s\n", + i->HDisplay, i->VDisplay, j->HDisplay, j->VDisplay, + mode->HDisplay, mode->VDisplay, (srel == radeonClone) ? " (Clone)" : ""); + + mode->next = mode; + mode->prev = mode; + + if(dest) { + mode->next = dest->next; /* Insert node after "dest" */ + dest->next->prev = mode; + mode->prev = dest; + dest->next = mode; + } + + return mode; +} + +/* Helper function to find a mode from a given name + * (Taken from mga driver) + */ +static DisplayModePtr +RADEONGetModeFromName(char* str, DisplayModePtr i) +{ + DisplayModePtr c = i; + if(!i) return NULL; + do { + if(strcmp(str, c->name) == 0) return c; + c = c->next; + } while(c != i); + return NULL; +} + +static DisplayModePtr +RADEONFindWidestTallestMode(DisplayModePtr i, Bool tallest) +{ + DisplayModePtr c = i, d = NULL; + int max = 0; + if(!i) return NULL; + do { + if(tallest) { + if(c->VDisplay > max) { + max = c->VDisplay; + d = c; + } + } else { + if(c->HDisplay > max) { + max = c->HDisplay; + d = c; + } + } + c = c->next; + } while(c != i); + return d; +} + +static DisplayModePtr +RADEONGenerateModeListFromLargestModes(ScrnInfoPtr pScrn, + DisplayModePtr i, DisplayModePtr j, + RADEONScrn2Rel srel) +{ + + RADEONInfoPtr info = RADEONPTR(pScrn); + DisplayModePtr mode1 = NULL; + DisplayModePtr mode2 = NULL; + DisplayModePtr result = NULL; + int p = 0; + int count = 0; + + info->AtLeastOneNonClone = FALSE; + + + switch(srel) { + case radeonLeftOf: + case radeonRightOf: + mode1 = RADEONFindWidestTallestMode(i, FALSE); + mode2 = RADEONFindWidestTallestMode(j, FALSE); + break; + case radeonAbove: + case radeonBelow: + mode1 = RADEONFindWidestTallestMode(i, TRUE); + mode2 = RADEONFindWidestTallestMode(j, TRUE); + break; + case radeonClone: + mode1 = i; + mode2 = j; + while (pScrn->display->modes[count]) count++; + for (p = 0; p < count; p++) { + result = RADEONCopyModeNLink(pScrn, result, mode1, mode2, srel); + mode1 = mode1->next; + mode2 = mode2->next; + } + } + + if(mode1 && mode2) { + if (srel == radeonClone) + return result; + else + return(RADEONCopyModeNLink(pScrn, result, mode1, mode2, srel)); + } else { + return NULL; + } +} + +/* Generate the merged-fb mode modelist + * (Taken from mga driver) + */ +static DisplayModePtr +RADEONGenerateModeListFromMetaModes(ScrnInfoPtr pScrn, char* str, + DisplayModePtr i, DisplayModePtr j, + RADEONScrn2Rel srel) +{ + char* strmode = str; + char modename[256]; + Bool gotdash = FALSE; + RADEONScrn2Rel sr; + DisplayModePtr mode1 = NULL; + DisplayModePtr mode2 = NULL; + DisplayModePtr result = NULL; + RADEONInfoPtr info = RADEONPTR(pScrn); + + info->AtLeastOneNonClone = FALSE; + + do { + switch(*str) { + case 0: + case '-': + case ' ': + if((strmode != str)) { + + strncpy(modename, strmode, str - strmode); + modename[str - strmode] = 0; + + if(gotdash) { + if(mode1 == NULL) return NULL; + mode2 = RADEONGetModeFromName(modename, j); + if(!mode2) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Mode \"%s\" is not a supported mode for CRT2\n", modename); + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Skipping metamode \"%s-%s\".\n", mode1->name, modename); + mode1 = NULL; + } + } else { + mode1 = RADEONGetModeFromName(modename, i); + if(!mode1) { + char* tmps = str; + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Mode \"%s\" is not a supported mode for CRT1\n", modename); + gotdash = FALSE; + while(*tmps == ' ') tmps++; + if(*tmps == '-') { /* skip the next mode */ + tmps++; + while((*tmps == ' ') && (*tmps != 0)) tmps++; /* skip spaces */ + while((*tmps != ' ') && (*tmps != '-') && (*tmps != 0)) tmps++; /* skip modename */ + strncpy(modename,strmode,tmps - strmode); + modename[tmps - strmode] = 0; + str = tmps-1; + } + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Skipping metamode \"%s\".\n", modename); + mode1 = NULL; + } + } + gotdash = FALSE; + } + strmode = str + 1; + gotdash |= (*str == '-'); + + if(*str != 0) break; + /* Fall through otherwise */ + + default: + if(!gotdash && mode1) { + sr = srel; + if(!mode2) { + mode2 = RADEONGetModeFromName(mode1->name, j); + sr = radeonClone; + } + if(!mode2) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Mode: \"%s\" is not a supported mode for CRT2\n", mode1->name); + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Skipping metamode \"%s\".\n"); + mode1 = NULL; + } else { + result = RADEONCopyModeNLink(pScrn, result, mode1, mode2, sr); + mode1 = NULL; + mode2 = NULL; + } + } + break; + + } + + } while(*(str++) != 0); + + return result; +} + +DisplayModePtr +RADEONGenerateModeList(ScrnInfoPtr pScrn, char* str, + DisplayModePtr i, DisplayModePtr j, + RADEONScrn2Rel srel) +{ + if(str != NULL) { + return(RADEONGenerateModeListFromMetaModes(pScrn, str, i, j, srel)); + } else { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "No MetaModes given, linking %s modes by default\n", + (srel == radeonClone) ? "first" : "largest"); + return(RADEONGenerateModeListFromLargestModes(pScrn, i, j, srel)); + } +} + +void +RADEONRecalcDefaultVirtualSize(ScrnInfoPtr pScrn) +{ + DisplayModePtr mode, bmode; + int max; + static const char *str = "MergedFB: Virtual %s %d\n"; + + if(!(pScrn->display->virtualX)) { + mode = bmode = pScrn->modes; + max = 0; + do { + if(mode->HDisplay > max) max = mode->HDisplay; + mode = mode->next; + } while(mode != bmode); + pScrn->virtualX = max; + pScrn->displayWidth = max; + xf86DrvMsg(pScrn->scrnIndex, X_PROBED, str, "width", max); + } + if(!(pScrn->display->virtualY)) { + mode = bmode = pScrn->modes; + max = 0; + do { + if(mode->VDisplay > max) max = mode->VDisplay; + mode = mode->next; + } while(mode != bmode); + pScrn->virtualY = max; + xf86DrvMsg(pScrn->scrnIndex, X_PROBED, str, "height", max); + } +} + +/* Pseudo-Xinerama extension for MergedFB mode */ +void +RADEONUpdateXineramaScreenInfo(ScrnInfoPtr pScrn1) +{ + RADEONInfoPtr info = RADEONPTR(pScrn1); + ScrnInfoPtr pScrn2 = NULL; + int crt1scrnnum = 0, crt2scrnnum = 1; + int x1=0, x2=0, y1=0, y2=0, h1=0, h2=0, w1=0, w2=0; + DisplayModePtr currentMode, firstMode; + Bool infochanged = FALSE; + + if(!info->MergedFB) return; + + if(RADEONnoPanoramiXExtension) return; + + if(!RADEONXineramadataPtr) return; + + if(info->CRT2IsScrn0) { + crt1scrnnum = 1; + crt2scrnnum = 0; + } + + pScrn2 = info->CRT2pScrn; + + /* Attention: Usage of RandR may lead into virtual X and Y values + * actually smaller than our MetaModes! To avoid this, we calculate + * the maxCRT fields here (and not somewhere else, like in CopyNLink) + */ + + if((info->RADEONXineramaVX != pScrn1->virtualX) || (info->RADEONXineramaVY != pScrn1->virtualY)) { + + if(!(pScrn1->modes)) { + xf86DrvMsg(pScrn1->scrnIndex, X_ERROR, + "Internal error: RADEONUpdateXineramaScreenInfo(): pScrn->modes is NULL\n"); + return; + } + + info->maxCRT1_X1 = info->maxCRT1_X2 = 0; + info->maxCRT1_Y1 = info->maxCRT1_Y2 = 0; + info->maxCRT2_X1 = info->maxCRT2_X2 = 0; + info->maxCRT2_Y1 = info->maxCRT2_Y2 = 0; + info->maxClone_X1 = info->maxClone_X2 = 0; + info->maxClone_Y1 = info->maxClone_Y2 = 0; + + currentMode = firstMode = pScrn1->modes; + + do { + + DisplayModePtr p = currentMode->next; + DisplayModePtr i = ((RADEONMergedDisplayModePtr)currentMode->Private)->CRT1; + DisplayModePtr j = ((RADEONMergedDisplayModePtr)currentMode->Private)->CRT2; + RADEONScrn2Rel srel = ((RADEONMergedDisplayModePtr)currentMode->Private)->CRT2Position; + + if((i->HDisplay <= pScrn1->virtualX) && (j->HDisplay <= pScrn1->virtualX) && + (i->VDisplay <= pScrn1->virtualY) && (j->VDisplay <= pScrn1->virtualY)) { + + if(srel != radeonClone) { + if(info->maxCRT1_X1 <= i->HDisplay) { + info->maxCRT1_X1 = i->HDisplay; /* Largest CRT1 mode */ + if(info->maxCRT1_X2 < j->HDisplay) { + info->maxCRT1_X2 = j->HDisplay; /* Largest X of CRT2 mode displayed with largest CRT1 mode */ + } + } + if(info->maxCRT2_X2 <= j->HDisplay) { + info->maxCRT2_X2 = j->HDisplay; /* Largest CRT2 mode */ + if(info->maxCRT2_X1 < i->HDisplay) { + info->maxCRT2_X1 = i->HDisplay; /* Largest X of CRT1 mode displayed with largest CRT2 mode */ + } + } + if(info->maxCRT1_Y1 <= i->VDisplay) { + info->maxCRT1_Y1 = i->VDisplay; + if(info->maxCRT1_Y2 < j->VDisplay) { + info->maxCRT1_Y2 = j->VDisplay; + } + } + if(info->maxCRT2_Y2 <= j->VDisplay) { + info->maxCRT2_Y2 = j->VDisplay; + if(info->maxCRT2_Y1 < i->VDisplay) { + info->maxCRT2_Y1 = i->VDisplay; + } + } + } else { + if(info->maxClone_X1 < i->HDisplay) { + info->maxClone_X1 = i->HDisplay; + } + if(info->maxClone_X2 < j->HDisplay) { + info->maxClone_X2 = j->HDisplay; + } + if(info->maxClone_Y1 < i->VDisplay) { + info->maxClone_Y1 = i->VDisplay; + } + if(info->maxClone_Y2 < j->VDisplay) { + info->maxClone_Y2 = j->VDisplay; + } + } + } + currentMode = p; + + } while((currentMode) && (currentMode != firstMode)); + + info->RADEONXineramaVX = pScrn1->virtualX; + info->RADEONXineramaVY = pScrn1->virtualY; + infochanged = TRUE; + + } + + /* leftof + + V 1: + CRT2: x = 0 + y = 0 + w = (maxCRT2 X) + h = (virtual Y) + CRT1: x = (virtual X) - (maxCRT1 X) + y = 0 + w = (maxCRT1 X) + h = (virtual Y) + + V 2: + CRT2: x = 0 + y = 0 + w = max CRT2 mode X + h = virtual Y size + CRT1: x = (max) CRT2 mode X von dem Metamode, wo CRT1 mode maximal breit ist + y = 0 + w = max CRT1 mode X + h = virtual Y size + + V 3: (current) + CRT1: x = (maxCRT2 X von dem MMode, wo maxCRT1 X) + y = 0 + w = (virtual X) - x + h = (virtual Y) + CRT2: x = 0 + y = 0 + w = (virtual X) - (maxCRT1 X von dem MMode, wo maxCRT2 X) + h = (virtual Y) + + */ + switch(info->CRT2Position) { + case radeonLeftOf: /* V 1 */ + x1 = min(info->maxCRT1_X2, pScrn1->virtualX - info->maxCRT1_X1); /* pScrn1->virtualX - pSiS->maxCRT1_X1; +*/ + if(x1 < 0) x1 = 0; + y1 = 0; /* 0; */ + w1 = pScrn1->virtualX - x1; /* pSiS->maxCRT1_X1; */ + h1 = pScrn1->virtualY; /* pScrn1->virtualY; */ + x2 = 0; /* 0; */ + y2 = 0; /* 0; */ + w2 = max(info->maxCRT2_X2, pScrn1->virtualX - info->maxCRT2_X1); /* pSiS->maxCRT2_X2; */ + if(w2 > pScrn1->virtualX) w2 = pScrn1->virtualX; + h2 = pScrn1->virtualY; /* pScrn1->virtualY; */ + break; + case radeonRightOf: + x1 = 0; /* 0; */ + y1 = 0; /* 0; */ + w1 = max(info->maxCRT1_X1, pScrn1->virtualX - info->maxCRT1_X2); /* pSiS->maxCRT1_X1; */ + if(w1 > pScrn1->virtualX) w1 = pScrn1->virtualX; + h1 = pScrn1->virtualY; /* pScrn1->virtualY; */ + x2 = min(info->maxCRT2_X1, pScrn1->virtualX - info->maxCRT2_X2); /* pScrn1->virtualX - pSiS->maxCRT2_X2; +*/ + if(x2 < 0) x2 = 0; + y2 = 0; /* 0; */ + w2 = pScrn1->virtualX - x2; /* pSiS->maxCRT2_X2; */ + h2 = pScrn1->virtualY; /* pScrn1->virtualY; */ + break; + case radeonAbove: + x1 = 0; /* 0; */ + y1 = min(info->maxCRT1_Y2, pScrn1->virtualY - info->maxCRT1_Y1); /* pScrn1->virtualY - pSiS->maxCRT1_Y1; +*/ + if(y1 < 0) y1 = 0; + w1 = pScrn1->virtualX; /* pScrn1->virtualX; */ + h1 = pScrn1->virtualY - y1; /* pSiS->maxCRT1_Y1; */ + x2 = 0; /* 0; */ + y2 = 0; /* 0; */ + w2 = pScrn1->virtualX; /* pScrn1->virtualX; */ + h2 = max(info->maxCRT2_Y2, pScrn1->virtualY - info->maxCRT2_Y1); /* pSiS->maxCRT2_Y2; */ + if(h2 > pScrn1->virtualY) h2 = pScrn1->virtualY; + break; + case radeonBelow: + x1 = 0; /* 0; */ + y1 = 0; /* 0; */ + w1 = pScrn1->virtualX; /* pScrn1->virtualX; */ + h1 = max(info->maxCRT1_Y1, pScrn1->virtualY - info->maxCRT1_Y2); /* pSiS->maxCRT1_Y1; */ + if(h1 > pScrn1->virtualY) h1 = pScrn1->virtualY; + x2 = 0; /* 0; */ + y2 = min(info->maxCRT2_Y1, pScrn1->virtualY - info->maxCRT2_Y2); /* pScrn1->virtualY - pSiS->maxCRT2_Y2; +*/ + if(y2 < 0) y2 = 0; + w2 = pScrn1->virtualX; /* pScrn1->virtualX; */ + h2 = pScrn1->virtualY - y2; /* pSiS->maxCRT2_Y2; */ + break; + default: + xf86DrvMsg(pScrn1->scrnIndex, X_ERROR, + "Internal error: UpdateXineramaInfo(): unsupported CRT2Position (%d)\n", + info->CRT2Position); + } + RADEONXineramadataPtr[crt1scrnnum].x = x1; + RADEONXineramadataPtr[crt1scrnnum].y = y1; + RADEONXineramadataPtr[crt1scrnnum].width = w1; + RADEONXineramadataPtr[crt1scrnnum].height = h1; + RADEONXineramadataPtr[crt2scrnnum].x = x2; + RADEONXineramadataPtr[crt2scrnnum].y = y2; + RADEONXineramadataPtr[crt2scrnnum].width = w2; + RADEONXineramadataPtr[crt2scrnnum].height = h2; + + if(infochanged) { + xf86DrvMsg(pScrn1->scrnIndex, X_INFO, + "Pseudo-Xinerama: CRT1 (Screen %d) (%d,%d)-(%d,%d)\n", + crt1scrnnum, x1, y1, w1+x1-1, h1+y1-1); + xf86DrvMsg(pScrn1->scrnIndex, X_INFO, + "Pseudo-Xinerama: CRT2 (Screen %d) (%d,%d)-(%d,%d)\n", + crt2scrnnum, x2, y2, w2+x2-1, h2+y2-1); + } + +} + +/* Proc */ + +int +RADEONProcXineramaQueryVersion(ClientPtr client) +{ + xPanoramiXQueryVersionReply rep; + register int n; + + REQUEST_SIZE_MATCH(xPanoramiXQueryVersionReq); + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.majorVersion = RADEON_XINERAMA_MAJOR_VERSION; + rep.minorVersion = RADEON_XINERAMA_MINOR_VERSION; + if(client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swaps(&rep.majorVersion, n); + swaps(&rep.minorVersion, n); + } + WriteToClient(client, sizeof(xPanoramiXQueryVersionReply), (char *)&rep); + return (client->noClientException); +} + +int +RADEONProcXineramaGetState(ClientPtr client) +{ + REQUEST(xPanoramiXGetStateReq); + WindowPtr pWin; + xPanoramiXGetStateReply rep; + register int n; + + REQUEST_SIZE_MATCH(xPanoramiXGetStateReq); + pWin = LookupWindow(stuff->window, client); + if(!pWin) return BadWindow; + + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.state = !RADEONnoPanoramiXExtension; + if(client->swapped) { + swaps (&rep.sequenceNumber, n); + swapl (&rep.length, n); + swaps (&rep.state, n); + } + WriteToClient(client, sizeof(xPanoramiXGetStateReply), (char *)&rep); + return client->noClientException; +} + +int +RADEONProcXineramaGetScreenCount(ClientPtr client) +{ + REQUEST(xPanoramiXGetScreenCountReq); + WindowPtr pWin; + xPanoramiXGetScreenCountReply rep; + register int n; + + REQUEST_SIZE_MATCH(xPanoramiXGetScreenCountReq); + pWin = LookupWindow(stuff->window, client); + if(!pWin) return BadWindow; + + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.ScreenCount = RADEONXineramaNumScreens; + if(client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swaps(&rep.ScreenCount, n); + } + WriteToClient(client, sizeof(xPanoramiXGetScreenCountReply), (char *)&rep); + return client->noClientException; +} + +int +RADEONProcXineramaGetScreenSize(ClientPtr client) +{ + REQUEST(xPanoramiXGetScreenSizeReq); + WindowPtr pWin; + xPanoramiXGetScreenSizeReply rep; + register int n; + + REQUEST_SIZE_MATCH(xPanoramiXGetScreenSizeReq); + pWin = LookupWindow (stuff->window, client); + if(!pWin) return BadWindow; + + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.width = RADEONXineramadataPtr[stuff->screen].width; + rep.height = RADEONXineramadataPtr[stuff->screen].height; + if(client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swaps(&rep.width, n); + swaps(&rep.height, n); + } + WriteToClient(client, sizeof(xPanoramiXGetScreenSizeReply), (char *)&rep); + return client->noClientException; +} + +int +RADEONProcXineramaIsActive(ClientPtr client) +{ + xXineramaIsActiveReply rep; + + REQUEST_SIZE_MATCH(xXineramaIsActiveReq); + + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.state = !RADEONnoPanoramiXExtension; + if(client->swapped) { + register int n; + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swapl(&rep.state, n); + } + WriteToClient(client, sizeof(xXineramaIsActiveReply), (char *) &rep); + return client->noClientException; +} + +int +RADEONProcXineramaQueryScreens(ClientPtr client) +{ + xXineramaQueryScreensReply rep; + + REQUEST_SIZE_MATCH(xXineramaQueryScreensReq); + + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.number = (RADEONnoPanoramiXExtension) ? 0 : RADEONXineramaNumScreens; + rep.length = rep.number * sz_XineramaScreenInfo >> 2; + if(client->swapped) { + register int n; + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swapl(&rep.number, n); + } + WriteToClient(client, sizeof(xXineramaQueryScreensReply), (char *)&rep); + + if(!RADEONnoPanoramiXExtension) { + xXineramaScreenInfo scratch; + int i; + + for(i = 0; i < RADEONXineramaNumScreens; i++) { + scratch.x_org = RADEONXineramadataPtr[i].x; + scratch.y_org = RADEONXineramadataPtr[i].y; + scratch.width = RADEONXineramadataPtr[i].width; + scratch.height = RADEONXineramadataPtr[i].height; + if(client->swapped) { + register int n; + swaps(&scratch.x_org, n); + swaps(&scratch.y_org, n); + swaps(&scratch.width, n); + swaps(&scratch.height, n); + } + WriteToClient(client, sz_XineramaScreenInfo, (char *)&scratch); + } + } + + return client->noClientException; +} + +static int +RADEONProcXineramaDispatch(ClientPtr client) +{ + REQUEST(xReq); + switch (stuff->data) + { + case X_PanoramiXQueryVersion: + return RADEONProcXineramaQueryVersion(client); + case X_PanoramiXGetState: + return RADEONProcXineramaGetState(client); + case X_PanoramiXGetScreenCount: + return RADEONProcXineramaGetScreenCount(client); + case X_PanoramiXGetScreenSize: + return RADEONProcXineramaGetScreenSize(client); + case X_XineramaIsActive: + return RADEONProcXineramaIsActive(client); + case X_XineramaQueryScreens: + return RADEONProcXineramaQueryScreens(client); + } + return BadRequest; +} + +/* SProc */ + +static int +RADEONSProcXineramaQueryVersion (ClientPtr client) +{ + REQUEST(xPanoramiXQueryVersionReq); + register int n; + swaps(&stuff->length,n); + REQUEST_SIZE_MATCH (xPanoramiXQueryVersionReq); + return RADEONProcXineramaQueryVersion(client); +} + +static int +RADEONSProcXineramaGetState(ClientPtr client) +{ + REQUEST(xPanoramiXGetStateReq); + register int n; + swaps (&stuff->length, n); + REQUEST_SIZE_MATCH(xPanoramiXGetStateReq); + return RADEONProcXineramaGetState(client); +} + +static int +RADEONSProcXineramaGetScreenCount(ClientPtr client) +{ + REQUEST(xPanoramiXGetScreenCountReq); + register int n; + swaps (&stuff->length, n); + REQUEST_SIZE_MATCH(xPanoramiXGetScreenCountReq); + return RADEONProcXineramaGetScreenCount(client); +} + +static int +RADEONSProcXineramaGetScreenSize(ClientPtr client) +{ + REQUEST(xPanoramiXGetScreenSizeReq); + register int n; + swaps (&stuff->length, n); + REQUEST_SIZE_MATCH(xPanoramiXGetScreenSizeReq); + return RADEONProcXineramaGetScreenSize(client); +} + +static int +RADEONSProcXineramaIsActive(ClientPtr client) +{ + REQUEST(xXineramaIsActiveReq); + register int n; + swaps (&stuff->length, n); + REQUEST_SIZE_MATCH(xXineramaIsActiveReq); + return RADEONProcXineramaIsActive(client); +} + +static int +RADEONSProcXineramaQueryScreens(ClientPtr client) +{ + REQUEST(xXineramaQueryScreensReq); + register int n; + swaps (&stuff->length, n); + REQUEST_SIZE_MATCH(xXineramaQueryScreensReq); + return RADEONProcXineramaQueryScreens(client); +} + +int +RADEONSProcXineramaDispatch(ClientPtr client) +{ + REQUEST(xReq); + switch (stuff->data) { + case X_PanoramiXQueryVersion: + return RADEONSProcXineramaQueryVersion(client); + case X_PanoramiXGetState: + return RADEONSProcXineramaGetState(client); + case X_PanoramiXGetScreenCount: + return RADEONSProcXineramaGetScreenCount(client); + case X_PanoramiXGetScreenSize: + return RADEONSProcXineramaGetScreenSize(client); + case X_XineramaIsActive: + return RADEONSProcXineramaIsActive(client); + case X_XineramaQueryScreens: + return RADEONSProcXineramaQueryScreens(client); + } + return BadRequest; +} + +static void +RADEONXineramaResetProc(ExtensionEntry* extEntry) +{ + if(RADEONXineramadataPtr) { + Xfree(RADEONXineramadataPtr); + RADEONXineramadataPtr = NULL; + } +} + +void +RADEONXineramaExtensionInit(ScrnInfoPtr pScrn) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + Bool success = FALSE; + + if(!(RADEONXineramadataPtr)) { + + if(!info->MergedFB) { + RADEONnoPanoramiXExtension = TRUE; + return; + } + + if(!noPanoramiXExtension) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Xinerama active, not initializing Radeon Pseudo-Xinerama\n"); + RADEONnoPanoramiXExtension = TRUE; + return; + } + + if(RADEONnoPanoramiXExtension) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Radeon Pseudo-Xinerama disabled\n"); + return; + } + + if(info->CRT2Position == radeonClone) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Running MergedFB in Clone mode, Radeon Pseudo-Xinerama disabled\n"); + RADEONnoPanoramiXExtension = TRUE; + return; + } + + if(!(info->AtLeastOneNonClone)) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Only Clone modes defined, Radeon Pseudo-Xinerama disabled\n"); + RADEONnoPanoramiXExtension = TRUE; + return; + } + + RADEONXineramaNumScreens = 2; + + while(RADEONXineramaGeneration != serverGeneration) { + + info->XineramaExtEntry = AddExtension(PANORAMIX_PROTOCOL_NAME, 0,0, + RADEONProcXineramaDispatch, + RADEONSProcXineramaDispatch, + RADEONXineramaResetProc, + StandardMinorOpcode); + + if(!info->XineramaExtEntry) break; + + RADEONXineramaReqCode = (unsigned char)info->XineramaExtEntry->base; + + if(!(RADEONXineramadataPtr = (RADEONXineramaData *) + xcalloc(RADEONXineramaNumScreens, sizeof(RADEONXineramaData)))) break; + + RADEONXineramaGeneration = serverGeneration; + success = TRUE; + } + + if(!success) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Failed to initialize Radeon Pseudo-Xinerama extension\n"); + RADEONnoPanoramiXExtension = TRUE; + return; + } + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Initialized Radeon Pseudo-Xinerama extension\n"); + + info->RADEONXineramaVX = 0; + info->RADEONXineramaVY = 0; + + } + + RADEONUpdateXineramaScreenInfo(pScrn); + +} +/* End of PseudoXinerama */ + +static Bool +InRegion(int x, int y, region r) +{ + return (r.x0 <= x) && (x <= r.x1) && (r.y0 <= y) && (y <= r.y1); +} + +void +RADEONMergePointerMoved(int scrnIndex, int x, int y) +{ + ScrnInfoPtr pScrn1 = xf86Screens[scrnIndex]; + RADEONInfoPtr info = RADEONPTR(pScrn1); + ScrnInfoPtr pScrn2 = info->CRT2pScrn; + region out, in1, in2, f2, f1; + int deltax, deltay; + + f1.x0 = info->CRT1frameX0; + f1.x1 = info->CRT1frameX1; + f1.y0 = info->CRT1frameY0; + f1.y1 = info->CRT1frameY1; + f2.x0 = pScrn2->frameX0; + f2.x1 = pScrn2->frameX1; + f2.y0 = pScrn2->frameY0; + f2.y1 = pScrn2->frameY1; + + /* Define the outer region. Crossing this causes all frames to move */ + out.x0 = pScrn1->frameX0; + out.x1 = pScrn1->frameX1; + out.y0 = pScrn1->frameY0; + out.y1 = pScrn1->frameY1; + + /* + * Define the inner sliding window. Being outsize both frames but + * inside the outer clipping window will slide corresponding frame + */ + in1 = out; + in2 = out; + switch(((RADEONMergedDisplayModePtr)info->CurrentLayout.mode->Private)->CRT2Position) { + case radeonLeftOf: + in1.x0 = f1.x0; + in2.x1 = f2.x1; + break; + case radeonRightOf: + in1.x1 = f1.x1; + in2.x0 = f2.x0; + break; + case radeonBelow: + in1.y1 = f1.y1; + in2.y0 = f2.y0; + break; + case radeonAbove: + in1.y0 = f1.y0; + in2.y1 = f2.y1; + break; + case radeonClone: + break; + } + + deltay = 0; + deltax = 0; + + if(InRegion(x, y, out)) { /* inside outer region */ + + /* xf86DrvMsg(0, X_INFO, "1: %d %d | %d %d %d %d | %d %d %d %d\n", + x, y, in1.x0, in1.x1, in1.y0, in1.y1, f1.x0, f1.x1, f1.y0, f1.y1); */ + + if(InRegion(x, y, in1) && !InRegion(x, y, f1)) { + REBOUND(f1.x0, f1.x1, x); + REBOUND(f1.y0, f1.y1, y); + deltax = 1; + /* xf86DrvMsg(0, X_INFO, "2: %d %d | %d %d %d %d | %d %d %d %d\n", + x, y, in1.x0, in1.x1, in1.y0, in1.y1, f1.x0, f1.x1, f1.y0, f1.y1); */ + } + if(InRegion(x, y, in2) && !InRegion(x, y, f2)) { + REBOUND(f2.x0, f2.x1, x); + REBOUND(f2.y0, f2.y1, y); + deltax = 1; + } + + } else { /* outside outer region */ + + /* xf86DrvMsg(0, X_INFO, "3: %d %d | %d %d %d %d | %d %d %d %d\n", + x, y, in1.x0, in1.x1, in1.y0, in1.y1, f1.x0, f1.x1, f1.y0, f1.y1); + xf86DrvMsg(0, X_INFO, "3-out: %d %d %d %d\n", + out.x0, out.x1, out.y0, out.y1); */ + + if(out.x0 > x) { + deltax = x - out.x0; + } + if(out.x1 < x) { + deltax = x - out.x1; + } + if(deltax) { + pScrn1->frameX0 += deltax; + pScrn1->frameX1 += deltax; + f1.x0 += deltax; + f1.x1 += deltax; + f2.x0 += deltax; + f2.x1 += deltax; + } + + if(out.y0 > y) { + deltay = y - out.y0; + } + if(out.y1 < y) { + deltay = y - out.y1; + } + if(deltay) { + pScrn1->frameY0 += deltay; + pScrn1->frameY1 += deltay; + f1.y0 += deltay; + f1.y1 += deltay; + f2.y0 += deltay; + f2.y1 += deltay; + } + + switch(((RADEONMergedDisplayModePtr)info->CurrentLayout.mode->Private)->CRT2Position) { + case radeonLeftOf: + if(x >= f1.x0) { REBOUND(f1.y0, f1.y1, y); } + if(x <= f2.x1) { REBOUND(f2.y0, f2.y1, y); } + break; + case radeonRightOf: + if(x <= f1.x1) { REBOUND(f1.y0, f1.y1, y); } + if(x >= f2.x0) { REBOUND(f2.y0, f2.y1, y); } + break; + case radeonBelow: + if(y <= f1.y1) { REBOUND(f1.x0, f1.x1, x); } + if(y >= f2.y0) { REBOUND(f2.x0, f2.x1, x); } + break; + case radeonAbove: + if(y >= f1.y0) { REBOUND(f1.x0, f1.x1, x); } + if(y <= f2.y1) { REBOUND(f2.x0, f2.x1, x); } + break; + case radeonClone: + break; + } + + } + + if(deltax || deltay) { + info->CRT1frameX0 = f1.x0; + info->CRT1frameY0 = f1.y0; + pScrn2->frameX0 = f2.x0; + pScrn2->frameY0 = f2.y0; + + info->CRT1frameX1 = info->CRT1frameX0 + CDMPTR->CRT1->HDisplay - 1; + info->CRT1frameY1 = info->CRT1frameY0 + CDMPTR->CRT1->VDisplay - 1; + pScrn2->frameX1 = pScrn2->frameX0 + CDMPTR->CRT2->HDisplay - 1; + pScrn2->frameY1 = pScrn2->frameY0 + CDMPTR->CRT2->VDisplay - 1; + pScrn1->frameX1 = pScrn1->frameX0 + info->CurrentLayout.mode->HDisplay - 1; + pScrn1->frameY1 = pScrn1->frameY0 + info->CurrentLayout.mode->VDisplay - 1; + + RADEONDoAdjustFrame(pScrn1, info->CRT1frameX0, info->CRT1frameY0, FALSE); + RADEONDoAdjustFrame(pScrn1, pScrn2->frameX0, pScrn2->frameY0, TRUE); + } +} + +static void +RADEONAdjustFrameMergedHelper(int scrnIndex, int x, int y, int flags) +{ + ScrnInfoPtr pScrn1 = xf86Screens[scrnIndex]; + RADEONInfoPtr info = RADEONPTR(pScrn1); + ScrnInfoPtr pScrn2 = info->CRT2pScrn; + int VTotal = info->CurrentLayout.mode->VDisplay; + int HTotal = info->CurrentLayout.mode->HDisplay; + int VMax = VTotal; + int HMax = HTotal; + + BOUND(x, 0, pScrn1->virtualX - HTotal); + BOUND(y, 0, pScrn1->virtualY - VTotal); + + switch(SDMPTR(pScrn1)->CRT2Position) { + case radeonLeftOf: + pScrn2->frameX0 = x; + BOUND(pScrn2->frameY0, y, y + VMax - CDMPTR->CRT2->VDisplay); + info->CRT1frameX0 = x + CDMPTR->CRT2->HDisplay; + BOUND(info->CRT1frameY0, y, y + VMax - CDMPTR->CRT1->VDisplay); + break; + case radeonRightOf: + info->CRT1frameX0 = x; + BOUND(info->CRT1frameY0, y, y + VMax - CDMPTR->CRT1->VDisplay); + pScrn2->frameX0 = x + CDMPTR->CRT1->HDisplay; + BOUND(pScrn2->frameY0, y, y + VMax - CDMPTR->CRT2->VDisplay); + break; + case radeonAbove: + BOUND(pScrn2->frameX0, x, x + HMax - CDMPTR->CRT2->HDisplay); + pScrn2->frameY0 = y; + BOUND(info->CRT1frameX0, x, x + HMax - CDMPTR->CRT1->HDisplay); + info->CRT1frameY0 = y + CDMPTR->CRT2->VDisplay; + break; + case radeonBelow: + BOUND(info->CRT1frameX0, x, x + HMax - CDMPTR->CRT1->HDisplay); + info->CRT1frameY0 = y; + BOUND(pScrn2->frameX0, x, x + HMax - CDMPTR->CRT2->HDisplay); + pScrn2->frameY0 = y + CDMPTR->CRT1->VDisplay; + break; + case radeonClone: + BOUND(info->CRT1frameX0, x, x + HMax - CDMPTR->CRT1->HDisplay); + BOUND(info->CRT1frameY0, y, y + VMax - CDMPTR->CRT1->VDisplay); + BOUND(pScrn2->frameX0, x, x + HMax - CDMPTR->CRT2->HDisplay); + BOUND(pScrn2->frameY0, y, y + VMax - CDMPTR->CRT2->VDisplay); + break; + } + + BOUND(info->CRT1frameX0, 0, pScrn1->virtualX - CDMPTR->CRT1->HDisplay); + BOUND(info->CRT1frameY0, 0, pScrn1->virtualY - CDMPTR->CRT1->VDisplay); + BOUND(pScrn2->frameX0, 0, pScrn1->virtualX - CDMPTR->CRT2->HDisplay); + BOUND(pScrn2->frameY0, 0, pScrn1->virtualY - CDMPTR->CRT2->VDisplay); + + pScrn1->frameX0 = x; + pScrn1->frameY0 = y; + + info->CRT1frameX1 = info->CRT1frameX0 + CDMPTR->CRT1->HDisplay - 1; + info->CRT1frameY1 = info->CRT1frameY0 + CDMPTR->CRT1->VDisplay - 1; + pScrn2->frameX1 = pScrn2->frameX0 + CDMPTR->CRT2->HDisplay - 1; + pScrn2->frameY1 = pScrn2->frameY0 + CDMPTR->CRT2->VDisplay - 1; + pScrn1->frameX1 = pScrn1->frameX0 + info->CurrentLayout.mode->HDisplay - 1; + pScrn1->frameY1 = pScrn1->frameY0 + info->CurrentLayout.mode->VDisplay - 1; +/* + RADEONDoAdjustFrame(pScrn1, info->CRT1frameX0, info->CRT1frameY0, FALSE); + RADEONDoAdjustFrame(pScrn1, pScrn2->frameX0, pScrn2->frameY0, TRUE); +*/ +} + +void +RADEONAdjustFrameMerged(int scrnIndex, int x, int y, int flags) +{ + ScrnInfoPtr pScrn1 = xf86Screens[scrnIndex]; + RADEONInfoPtr info = RADEONPTR(pScrn1); + ScrnInfoPtr pScrn2 = info->CRT2pScrn; + + RADEONAdjustFrameMergedHelper(scrnIndex, x, y, flags); + RADEONDoAdjustFrame(pScrn1, info->CRT1frameX0, info->CRT1frameY0, FALSE); + RADEONDoAdjustFrame(pScrn1, pScrn2->frameX0, pScrn2->frameY0, TRUE); +} + +void +RADEONMergedFBSetDpi(ScrnInfoPtr pScrn1, ScrnInfoPtr pScrn2, RADEONScrn2Rel srel) +{ + RADEONInfoPtr info = RADEONPTR(pScrn1); + MessageType from = X_DEFAULT; + xf86MonPtr DDC1 = (xf86MonPtr)(pScrn1->monitor->DDC); + xf86MonPtr DDC2 = (xf86MonPtr)(pScrn2->monitor->DDC); + int ddcWidthmm = 0, ddcHeightmm = 0; + const char *dsstr = "MergedFB: Display dimensions: (%d, %d) mm\n"; + + /* This sets the DPI for MergedFB mode. The problem is that + * this can never be exact, because the output devices may + * have different dimensions. This function tries to compromise + * through a few assumptions, and it just calculates an average DPI + * value for both monitors. + */ + + /* Given DisplaySize should regard BOTH monitors */ + pScrn1->widthmm = pScrn1->monitor->widthmm; + pScrn1->heightmm = pScrn1->monitor->heightmm; + + /* Get DDC display size; if only either CRT1 or CRT2 provided these, + * assume equal dimensions for both, otherwise add dimensions + */ + if( (DDC1 && (DDC1->features.hsize > 0 && DDC1->features.vsize > 0)) && + (DDC2 && (DDC2->features.hsize > 0 && DDC2->features.vsize > 0)) ) { + ddcWidthmm = max(DDC1->features.hsize, DDC2->features.hsize) * 10; + ddcHeightmm = max(DDC1->features.vsize, DDC2->features.vsize) * 10; + switch(srel) { + case radeonLeftOf: + case radeonRightOf: + ddcWidthmm = (DDC1->features.hsize + DDC2->features.hsize) * 10; + break; + case radeonAbove: + case radeonBelow: + ddcHeightmm = (DDC1->features.vsize + DDC2->features.vsize) * 10; + default: + break; + } + + } else if(DDC1 && (DDC1->features.hsize > 0 && DDC1->features.vsize > 0)) { + ddcWidthmm = DDC1->features.hsize * 10; + ddcHeightmm = DDC1->features.vsize * 10; + switch(srel) { + case radeonLeftOf: + case radeonRightOf: + ddcWidthmm *= 2; + break; + case radeonAbove: + case radeonBelow: + ddcHeightmm *= 2; + default: + break; + } + } else if(DDC2 && (DDC2->features.hsize > 0 && DDC2->features.vsize > 0) ) { + ddcWidthmm = DDC2->features.hsize * 10; + ddcHeightmm = DDC2->features.vsize * 10; + switch(srel) { + case radeonLeftOf: + case radeonRightOf: + ddcWidthmm *= 2; + break; + case radeonAbove: + case radeonBelow: + ddcHeightmm *= 2; + default: + break; + } + } + + if(monitorResolution > 0) { + + /* Set command line given values (overrules given options) */ + pScrn1->xDpi = monitorResolution; + pScrn1->yDpi = monitorResolution; + from = X_CMDLINE; + + } else if(info->MergedFBXDPI) { + + /* Set option-wise given values (overrule DisplaySize) */ + pScrn1->xDpi = info->MergedFBXDPI; + pScrn1->yDpi = info->MergedFBYDPI; + from = X_CONFIG; + + } else if(pScrn1->widthmm > 0 || pScrn1->heightmm > 0) { + + /* Set values calculated from given DisplaySize */ + from = X_CONFIG; + if(pScrn1->widthmm > 0) { + pScrn1->xDpi = (int)((double)pScrn1->virtualX * 25.4 / pScrn1->widthmm); + } + if(pScrn1->heightmm > 0) { + pScrn1->yDpi = (int)((double)pScrn1->virtualY * 25.4 / pScrn1->heightmm); + } + xf86DrvMsg(pScrn1->scrnIndex, from, dsstr, pScrn1->widthmm, pScrn1->heightmm); + + } else if(ddcWidthmm && ddcHeightmm) { + + /* Set values from DDC-provided display size */ + from = X_PROBED; + xf86DrvMsg(pScrn1->scrnIndex, from, dsstr, ddcWidthmm, ddcHeightmm ); + pScrn1->widthmm = ddcWidthmm; + pScrn1->heightmm = ddcHeightmm; + if(pScrn1->widthmm > 0) { + pScrn1->xDpi = (int)((double)pScrn1->virtualX * 25.4 / pScrn1->widthmm); + } + if(pScrn1->heightmm > 0) { + pScrn1->yDpi = (int)((double)pScrn1->virtualY * 25.4 / pScrn1->heightmm); + } + + } else { + + pScrn1->xDpi = pScrn1->yDpi = DEFAULT_DPI; + + } + + /* Sanity check */ + if(pScrn1->xDpi > 0 && pScrn1->yDpi <= 0) + pScrn1->yDpi = pScrn1->xDpi; + if(pScrn1->yDpi > 0 && pScrn1->xDpi <= 0) + pScrn1->xDpi = pScrn1->yDpi; + + pScrn2->xDpi = pScrn1->xDpi; + pScrn2->yDpi = pScrn1->yDpi; + + xf86DrvMsg(pScrn1->scrnIndex, from, "MergedFB: DPI set to (%d, %d)\n", + pScrn1->xDpi, pScrn1->yDpi); +} + +/* radeon cursor helpers */ +static void +RADEONChooseCursorCRTC(ScrnInfoPtr pScrn1, int x, int y) +{ + RADEONInfoPtr info = RADEONPTR(pScrn1); + unsigned char *RADEONMMIO = info->MMIO; + RADEONScrn2Rel srel = + ((RADEONMergedDisplayModePtr)info->CurrentLayout.mode->Private)->CRT2Position; + ScrnInfoPtr pScrn2 = info->CRT2pScrn; + + if (srel == radeonClone) { + /* show cursor 2 */ + OUTREGP(RADEON_CRTC2_GEN_CNTL, RADEON_CRTC2_CUR_EN, + ~RADEON_CRTC2_CUR_EN); + /* show cursor 1 */ + OUTREGP(RADEON_CRTC_GEN_CNTL, RADEON_CRTC_CUR_EN, + ~RADEON_CRTC_CUR_EN); + } + else { + if (((x >= pScrn1->frameX0) && (x <= pScrn1->frameX1)) && + ((y >= pScrn1->frameY0) && (y <= pScrn1->frameY1))) { + /* hide cursor 2 */ + OUTREGP(RADEON_CRTC2_GEN_CNTL, 0, ~RADEON_CRTC2_CUR_EN); + /* show cursor 1 */ + OUTREGP(RADEON_CRTC_GEN_CNTL, RADEON_CRTC_CUR_EN, + ~RADEON_CRTC_CUR_EN); + } + if (((x >= pScrn2->frameX0) && (x <= pScrn2->frameX1)) && + ((y >= pScrn2->frameY0) && (y <= pScrn2->frameY1))) { + /* hide cursor 1 */ + OUTREGP(RADEON_CRTC_GEN_CNTL, 0, ~RADEON_CRTC_CUR_EN); + /* show cursor 2 */ + OUTREGP(RADEON_CRTC2_GEN_CNTL, RADEON_CRTC2_CUR_EN, + ~RADEON_CRTC2_CUR_EN); + } + } +} + +void +RADEONSetCursorPositionMerged(ScrnInfoPtr pScrn, int x, int y) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + xf86CursorInfoPtr cursor = info->cursor; + int xorigin = 0; + int yorigin = 0; + int stride = 256; + ScrnInfoPtr pScrn2 = info->CRT2pScrn; + DisplayModePtr mode1 = CDMPTR->CRT1; + DisplayModePtr mode2 = CDMPTR->CRT2; + int x1, y1, x2, y2; + int total_y1 = pScrn->frameY1 - pScrn->frameY0; + int total_y2 = pScrn2->frameY1 - pScrn2->frameY0; + + if (x < 0) xorigin = -x+1; + if (y < 0) yorigin = -y+1; + /* if (y > total_y) y = total_y; */ + if (xorigin >= cursor->MaxWidth) xorigin = cursor->MaxWidth - 1; + if (yorigin >= cursor->MaxHeight) yorigin = cursor->MaxHeight - 1; + + x += pScrn->frameX0; + y += pScrn->frameY0; + + x1 = x - info->CRT1frameX0; + y1 = y - info->CRT1frameY0; + + x2 = x - pScrn2->frameX0; + y2 = y - pScrn2->frameY0; + + if (y1 > total_y1) + y1 = total_y1; + if (y2 > total_y2) + y2 = total_y2; + + if(mode1->Flags & V_INTERLACE) + y1 /= 2; + else if(mode1->Flags & V_DBLSCAN) + y1 *= 2; + + if(mode2->Flags & V_INTERLACE) + y2 /= 2; + else if(mode2->Flags & V_DBLSCAN) + y2 *= 2; + + if (x < 0) + x = 0; + if (y < 0) + y = 0; + + RADEONChooseCursorCRTC(pScrn, x, y); + + /* cursor1 */ + OUTREG(RADEON_CUR_HORZ_VERT_OFF, (RADEON_CUR_LOCK + | (xorigin << 16) + | yorigin)); + OUTREG(RADEON_CUR_HORZ_VERT_POSN, (RADEON_CUR_LOCK + | ((xorigin ? 0 : x1) << 16) + | (yorigin ? 0 : y1))); + OUTREG(RADEON_CUR_OFFSET, info->cursor_start + yorigin * stride); + /* cursor2 */ + OUTREG(RADEON_CUR2_HORZ_VERT_OFF, (RADEON_CUR2_LOCK + | (xorigin << 16) + | yorigin)); + OUTREG(RADEON_CUR2_HORZ_VERT_POSN, (RADEON_CUR2_LOCK + | ((xorigin ? 0 : x2) << 16) + | (yorigin ? 0 : y2))); + OUTREG(RADEON_CUR2_OFFSET, + info->cursor_start + yorigin * stride); + +} + +/* radeon Xv helpers */ + +/* choose the crtc for the overlay for mergedfb based on the location + of the output window and the orientation of the crtcs */ + +void +RADEONChooseOverlayCRTC( + ScrnInfoPtr pScrn, + BoxPtr dstBox +) { + RADEONInfoPtr info = RADEONPTR(pScrn); + RADEONScrn2Rel srel = + ((RADEONMergedDisplayModePtr)info->CurrentLayout.mode->Private)->CRT2Position; + + if (srel == radeonLeftOf) { + if (dstBox->x1 >= info->CRT2pScrn->frameX1) + info->OverlayOnCRTC2 = FALSE; + else + info->OverlayOnCRTC2 = TRUE; + } + if (srel == radeonRightOf) { + if (dstBox->x2 <= info->CRT2pScrn->frameX0) + info->OverlayOnCRTC2 = FALSE; + else + info->OverlayOnCRTC2 = TRUE; + } + if (srel == radeonAbove) { + if (dstBox->y1 >= info->CRT2pScrn->frameY1) + info->OverlayOnCRTC2 = FALSE; + else + info->OverlayOnCRTC2 = TRUE; + } + if (srel == radeonBelow) { + if (dstBox->y2 <= info->CRT2pScrn->frameY0) + info->OverlayOnCRTC2 = FALSE; + else + info->OverlayOnCRTC2 = TRUE; + } +} diff --git a/src/radeon_mergedfb.h b/src/radeon_mergedfb.h new file mode 100644 index 0000000..e51ce5c --- /dev/null +++ b/src/radeon_mergedfb.h @@ -0,0 +1,124 @@ +/* $XFree86$ */ +/* + * Copyright 2003 Alex Deucher. + * + * 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 on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, 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 ALEX DEUCHER, OR ANY OTHER + * CONTRIBUTORS 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: + * Alex Deucher <agd5f@yahoo.com> + * + */ + +#ifndef _RADEON_MERGEDFB_H_ +#define _RADEON_MERGEDFB_H_ + +#include "xf86.h" + +#include "radeon.h" + +#if 0 + /* Psuedo Xinerama support */ +#define NEED_REPLIES /* ? */ +#define EXTENSION_PROC_ARGS void * +#include "extnsionst.h" /* required */ +#include "panoramiXproto.h" /* required */ +#define RADEON_XINERAMA_MAJOR_VERSION 1 +#define RADEON_XINERAMA_MINOR_VERSION 1 + +/* needed for pseudo-xinerama by radeon_driver.c */ +Bool RADEONnoPanoramiXExtension = TRUE; + +/* Relative merge position */ +typedef enum { + radeonLeftOf, + radeonRightOf, + radeonAbove, + radeonBelow, + radeonClone +} RADEONScrn2Rel; +#endif + +#define SDMPTR(x) ((RADEONMergedDisplayModePtr)(x->currentMode->Private)) +#define CDMPTR ((RADEONMergedDisplayModePtr)(info->CurrentLayout.mode->Private)) + +#define BOUND(test,low,hi) { \ + if(test < low) test = low; \ + if(test > hi) test = hi; } + +#define REBOUND(low,hi,test) { \ + if(test < low) { \ + hi += test-low; \ + low = test; } \ + if(test > hi) { \ + low += test-hi; \ + hi = test; } } + +typedef struct _MergedDisplayModeRec { + DisplayModePtr CRT1; + DisplayModePtr CRT2; + RADEONScrn2Rel CRT2Position; +} RADEONMergedDisplayModeRec, *RADEONMergedDisplayModePtr; + +typedef struct _region { + int x0,x1,y0,y1; +} region; + +typedef struct _RADEONXineramaData { + int x; + int y; + int width; + int height; +} RADEONXineramaData; + +/* needed by radeon_driver.c */ +extern void +RADEONAdjustFrameMerged(int scrnIndex, int x, int y, int flags); +extern void +RADEONMergePointerMoved(int scrnIndex, int x, int y); +extern DisplayModePtr +RADEONGenerateModeList(ScrnInfoPtr pScrn, char* str, + DisplayModePtr i, DisplayModePtr j, + RADEONScrn2Rel srel); +extern int +RADEONStrToRanges(range *r, char *s, int max); +extern void +RADEONXineramaExtensionInit(ScrnInfoPtr pScrn); +extern void +RADEONUpdateXineramaScreenInfo(ScrnInfoPtr pScrn1); +extern void +RADEONMergedFBSetDpi(ScrnInfoPtr pScrn1, ScrnInfoPtr pScrn2, RADEONScrn2Rel srel); +extern void +RADEONRecalcDefaultVirtualSize(ScrnInfoPtr pScrn); + +/* needed by radeon_cursor.c */ +extern void +RADEONSetCursorPositionMerged(ScrnInfoPtr pScrn, int x, int y); + +/* needed by radeon_video.c */ +extern void +RADEONChooseOverlayCRTC(ScrnInfoPtr, BoxPtr); + +#endif /* _RADEON_MERGEDFB_H_ */ |