summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/atidri.c1508
-rw-r--r--src/atidri.h47
-rw-r--r--src/atidripriv.h59
-rw-r--r--src/mach64_common.h131
-rw-r--r--src/mach64_dri.h126
-rw-r--r--src/mach64_sarea.h163
-rw-r--r--src/radeon_mergedfb.c1560
-rw-r--r--src/radeon_mergedfb.h124
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_ */