summaryrefslogtreecommitdiff
path: root/src/atidri.c
diff options
context:
space:
mode:
authorEric Anholt <anholt@freebsd.org>2004-06-16 09:25:58 +0000
committerEric Anholt <anholt@freebsd.org>2004-06-16 09:25:58 +0000
commit7b588cda922992a8ee2d04853ba1533cf43592a3 (patch)
tree87dc5ed102aec08e80dc2e15f9051358319ef383 /src/atidri.c
parent6cbb5bbff43d65a762d432659793333868837f0b (diff)
Initial revision
Diffstat (limited to 'src/atidri.c')
-rw-r--r--src/atidri.c1508
1 files changed, 1508 insertions, 0 deletions
diff --git a/src/atidri.c b/src/atidri.c
new file mode 100644
index 00000000..d5e1c898
--- /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;
+ }
+}