diff options
Diffstat (limited to 'src/legacy/i810/i810_dri.c')
-rw-r--r-- | src/legacy/i810/i810_dri.c | 1544 |
1 files changed, 1544 insertions, 0 deletions
diff --git a/src/legacy/i810/i810_dri.c b/src/legacy/i810/i810_dri.c new file mode 100644 index 00000000..ecb94af1 --- /dev/null +++ b/src/legacy/i810/i810_dri.c @@ -0,0 +1,1544 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <errno.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> + +#include "xf86.h" +#include "xf86_OSproc.h" +#include "xf86Priv.h" + +#include "xf86PciInfo.h" +#include "xf86Pci.h" + +#include "windowstr.h" +#include "shadow.h" +#include "shadowfb.h" + +#include "GL/glxtokens.h" + +#include "i810.h" +#include "i810_dri.h" + +static char I810KernelDriverName[] = "i810"; +static char I810ClientDriverName[] = "i810"; + +static Bool I810InitVisualConfigs(ScreenPtr pScreen); +static Bool I810CreateContext(ScreenPtr pScreen, VisualPtr visual, + drm_context_t hwContext, void *pVisualConfigPriv, + DRIContextType contextStore); +static void I810DestroyContext(ScreenPtr pScreen, drm_context_t hwContext, + DRIContextType contextStore); +static void I810DRISwapContext(ScreenPtr pScreen, DRISyncType syncType, + DRIContextType readContextType, + void *readContextStore, + DRIContextType writeContextType, + void *writeContextStore); +static void I810DRIInitBuffers(WindowPtr pWin, RegionPtr prgn, CARD32 index); +static void I810DRIMoveBuffers(WindowPtr pParent, DDXPointRec ptOldOrg, + RegionPtr prgnSrc, CARD32 index); + + +static void I810EnablePageFlip(ScreenPtr pScreen); +static void I810DisablePageFlip(ScreenPtr pScreen); +static void I810DRITransitionSingleToMulti3d(ScreenPtr pScreen); +static void I810DRITransitionMultiToSingle3d(ScreenPtr pScreen); +static void I810DRITransitionTo3d(ScreenPtr pScreen); +static void I810DRITransitionTo2d(ScreenPtr pScreen); + +static void I810DRIRefreshArea(ScrnInfoPtr pScrn, int num, BoxPtr pbox); + +extern void GlxSetVisualConfigs(int nconfigs, + __GLXvisualConfig * configs, + void **configprivs); + +static int i810_pitches[] = { + 512, + 1024, + 2048, + 4096, + 0 +}; + +static int i810_pitch_flags[] = { + 0x0, + 0x1, + 0x2, + 0x3, + 0 +}; + +static unsigned int i810_drm_version = 0; + +Bool +I810CleanupDma(ScrnInfoPtr pScrn) +{ + I810Ptr pI810 = I810PTR(pScrn); + drmI810Init info; + + memset(&info, 0, sizeof(drmI810Init)); + info.func = I810_CLEANUP_DMA; + + if (drmCommandWrite(pI810->drmSubFD, DRM_I810_INIT, + &info, sizeof(drmI810Init))) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "[dri] I810 Dma Cleanup Failed\n"); + return FALSE; + } + + return TRUE; +} + +Bool +I810InitDma(ScrnInfoPtr pScrn) +{ + I810Ptr pI810 = I810PTR(pScrn); + I810RingBuffer *ring = pI810->LpRing; + I810DRIPtr pI810DRI = (I810DRIPtr) pI810->pDRIInfo->devPrivate; + drmI810Init info; + + memset(&info, 0, sizeof(drmI810Init)); + + info.ring_start = ring->mem.Start; + info.ring_end = ring->mem.End; + info.ring_size = ring->mem.Size; + info.mmio_offset = (unsigned int)pI810DRI->regs; + info.buffers_offset = (unsigned int)pI810->buffer_map; + info.sarea_priv_offset = sizeof(XF86DRISAREARec); + + info.front_offset = 0; + info.back_offset = pI810->BackBuffer.Start; + info.depth_offset = pI810->DepthBuffer.Start; + info.overlay_offset = pI810->OverlayStart; + info.overlay_physical = pI810->OverlayPhysical; + info.w = pScrn->virtualX; + info.h = pScrn->virtualY; + info.pitch = pI810->auxPitch; + info.pitch_bits = pI810->auxPitchBits; + + /* We require DRM v1.2 or greater. Since DRM v1.2 broke compatibility + * we created a new v1.4 that supports a new init function. Eventually the + * old init function will go away. If you change the drm interface, make a + * new init type too so that we can detect the new client. + */ + switch(i810_drm_version) { + case ((1<<16) | 0): + case ((1<<16) | 1): + case ((1<<16) | 2): + case ((1<<16) | 3): + /* Use OLD drm < 1.4 init */ + info.func = I810_INIT_DMA; + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "[drm] Init PRE v1.4 interface.\n"); + break; + default: + case ((1<<16) | 4): + /* DRM version 1.3 or greater init */ + info.func = I810_INIT_DMA_1_4; + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "[drm] Init v1.4 interface.\n"); + break; + } + + if (drmCommandWrite(pI810->drmSubFD, DRM_I810_INIT, + &info, sizeof(drmI810Init))) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "[drm] I810 Dma Initialization failed.\n"); + return FALSE; + } + + return TRUE; +} + +static Bool +I810InitVisualConfigs(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + I810Ptr pI810 = I810PTR(pScrn); + int numConfigs = 0; + __GLXvisualConfig *pConfigs = NULL; + I810ConfigPrivPtr pI810Configs = NULL; + I810ConfigPrivPtr *pI810ConfigPtrs = NULL; + int accum, stencil, db, depth; + int i; + + switch (pScrn->bitsPerPixel) { + case 8: + case 24: + case 32: + break; + case 16: + numConfigs = 8; + + pConfigs = + (__GLXvisualConfig *) calloc(sizeof(__GLXvisualConfig), + numConfigs); + if (!pConfigs) + return FALSE; + + pI810Configs = + (I810ConfigPrivPtr) calloc(sizeof(I810ConfigPrivRec), + numConfigs); + if (!pI810Configs) { + free(pConfigs); + return FALSE; + } + + pI810ConfigPtrs = + (I810ConfigPrivPtr *) calloc(sizeof(I810ConfigPrivPtr), + numConfigs); + if (!pI810ConfigPtrs) { + free(pConfigs); + free(pI810Configs); + return FALSE; + } + + for (i = 0; i < numConfigs; i++) + pI810ConfigPtrs[i] = &pI810Configs[i]; + + i = 0; + depth = 1; + for (accum = 0; accum <= 1; accum++) { + for (stencil = 0; stencil <= 1; stencil++) { + for (db = 1; db >= 0; db--) { + 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 = 0; + if (accum) { + 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; + if (depth) + pConfigs[i].depthSize = 16; + else + pConfigs[i].depthSize = 0; + if (stencil) + pConfigs[i].stencilSize = 8; + else + pConfigs[i].stencilSize = 0; + pConfigs[i].auxBuffers = 0; + pConfigs[i].level = 0; + if (stencil || accum) + 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++; + } + } + } + assert(i == numConfigs); + break; + } + pI810->numVisualConfigs = numConfigs; + pI810->pVisualConfigs = pConfigs; + pI810->pVisualConfigsPriv = pI810Configs; + GlxSetVisualConfigs(numConfigs, pConfigs, (void **)pI810ConfigPtrs); + return TRUE; +} + +static unsigned int +mylog2(unsigned int n) +{ + unsigned int log2 = 1; + + while (n > 1) + n >>= 1, log2++; + return log2; +} + +Bool +I810DRIScreenInit(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + I810Ptr pI810 = I810PTR(pScrn); + DRIInfoPtr pDRIInfo; + I810DRIPtr pI810DRI; + unsigned long tom; + drm_handle_t agpHandle; + drm_handle_t dcacheHandle; + int sysmem_size = 0; + int back_size = 0; + unsigned int pitch_idx = 0; + int bufs; + int width = pScrn->displayWidth * pI810->cpp; + int i; + + /* Hardware 3D rendering only implemented for 16bpp */ + /* And it only works for 5:6:5 (Mark) */ + if (pScrn->depth != 16) + return FALSE; + + /* 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("drmAvailable")) + return FALSE; + if (!xf86LoaderCheckSymbol("DRIQueryVersion")) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[dri] I810DRIScreenInit failed (libdri.a too old)\n"); + return FALSE; + } + + /* adjust width first */ +#define Elements(x) sizeof(x)/sizeof(*x) + for (pitch_idx = 0; pitch_idx < Elements(i810_pitches); pitch_idx++) + if (width <= i810_pitches[pitch_idx]) + break; + + if (pitch_idx == Elements(i810_pitches)) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "[dri] Couldn't find depth/back buffer pitch"); + DRICloseScreen(pScreen); + return FALSE; + } else { + /* for tiled memory to work, the buffer needs to have the + * number of lines as a multiple of 16 (the tile size), + * - airlied */ + int lines = (pScrn->virtualY + 15) / 16 * 16; + back_size = i810_pitches[pitch_idx] * lines; + back_size = ((back_size + 4096 - 1) / 4096) * 4096; + } + + pScrn->displayWidth = i810_pitches[pitch_idx] / pI810->cpp; + + /* Check the DRI version */ + { + int major, minor, patch; + + DRIQueryVersion(&major, &minor, &patch); + if (major != DRIINFO_MAJOR_VERSION || minor < DRIINFO_MINOR_VERSION) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[dri] I810DRIScreenInit failed because of a version mismatch.\n" + "[dri] libdri version is %d.%d.%d bug version %d.%d.x is needed.\n" + "[dri] Disabling DRI.\n", major, minor, patch, + DRIINFO_MAJOR_VERSION, DRIINFO_MINOR_VERSION); + return FALSE; + } + } + + pDRIInfo = DRICreateInfoRec(); + if (!pDRIInfo) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[dri] DRICreateInfoRec failed. Disabling DRI.\n"); + return FALSE; + } + +/* pDRIInfo->wrap.ValidateTree = 0; */ +/* pDRIInfo->wrap.PostValidateTree = 0; */ + + pI810->pDRIInfo = pDRIInfo; + pI810->LockHeld = 0; + + pDRIInfo->drmDriverName = I810KernelDriverName; + pDRIInfo->clientDriverName = I810ClientDriverName; + if (xf86LoaderCheckSymbol("DRICreatePCIBusID")) { + pDRIInfo->busIdString = DRICreatePCIBusID(pI810->PciInfo); + } else { + pDRIInfo->busIdString = malloc(64); + sprintf(pDRIInfo->busIdString, "PCI:%d:%d:%d", + ((pI810->PciInfo->domain << 8) | pI810->PciInfo->bus), + pI810->PciInfo->dev, pI810->PciInfo->func + ); + } + pDRIInfo->ddxDriverMajorVersion = I810_MAJOR_VERSION; + pDRIInfo->ddxDriverMinorVersion = I810_MINOR_VERSION; + pDRIInfo->ddxDriverPatchVersion = I810_PATCHLEVEL; + pDRIInfo->frameBufferPhysicalAddress = (pointer) pI810->LinearAddr; + pDRIInfo->frameBufferSize = (((pScrn->displayWidth * + pScrn->virtualY * pI810->cpp) + + 4096 - 1) / 4096) * 4096; + + pDRIInfo->frameBufferStride = pScrn->displayWidth * pI810->cpp; + pDRIInfo->ddxDrawableTableEntry = I810_MAX_DRAWABLES; + + if (SAREA_MAX_DRAWABLES < I810_MAX_DRAWABLES) + pDRIInfo->maxDrawableTableEntry = SAREA_MAX_DRAWABLES; + else + pDRIInfo->maxDrawableTableEntry = I810_MAX_DRAWABLES; + + /* For now the mapping works by using a fixed size defined + * in the SAREA header + */ + if (sizeof(XF86DRISAREARec) + sizeof(I810SAREARec) > SAREA_MAX) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[dri] Data does not fit in SAREA\n"); + return FALSE; + } + pDRIInfo->SAREASize = SAREA_MAX; + + if (!(pI810DRI = (I810DRIPtr) calloc(sizeof(I810DRIRec), 1))) { + DRIDestroyInfoRec(pI810->pDRIInfo); + pI810->pDRIInfo = NULL; + return FALSE; + } + pDRIInfo->devPrivate = pI810DRI; + pDRIInfo->devPrivateSize = sizeof(I810DRIRec); + pDRIInfo->contextSize = sizeof(I810DRIContextRec); + + pDRIInfo->CreateContext = I810CreateContext; + pDRIInfo->DestroyContext = I810DestroyContext; + pDRIInfo->SwapContext = I810DRISwapContext; + pDRIInfo->InitBuffers = I810DRIInitBuffers; + pDRIInfo->MoveBuffers = I810DRIMoveBuffers; + pDRIInfo->bufferRequests = DRI_ALL_WINDOWS; + pDRIInfo->TransitionTo2d = I810DRITransitionTo2d; + pDRIInfo->TransitionTo3d = I810DRITransitionTo3d; + pDRIInfo->TransitionSingleToMulti3D = I810DRITransitionSingleToMulti3d; + pDRIInfo->TransitionMultiToSingle3D = I810DRITransitionMultiToSingle3d; + + pDRIInfo->createDummyCtx = TRUE; + pDRIInfo->createDummyCtxPriv = FALSE; + + /* This adds the framebuffer as a drm map *before* we have asked agp + * to allocate it. Scary stuff, hold on... + */ + if (!DRIScreenInit(pScreen, pDRIInfo, &pI810->drmSubFD)) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[dri] DRIScreenInit failed. Disabling DRI.\n"); + free(pDRIInfo->devPrivate); + pDRIInfo->devPrivate = NULL; + DRIDestroyInfoRec(pI810->pDRIInfo); + pI810->pDRIInfo = NULL; + return FALSE; + } + + /* Check the i810 DRM versioning */ + { + drmVersionPtr version; + + /* 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(pI810->drmSubFD); + } 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(pI810->drmSubFD); + version->version_major = 1; + version->version_minor = 0; + version->version_patchlevel = 0; + } + +#define REQ_MAJ 1 +#define REQ_MIN 1 + if (version) { + if (version->version_major != REQ_MAJ || + version->version_minor < REQ_MIN) { + /* incompatible drm library version */ + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[dri] I810DRIScreenInit failed because of a version mismatch.\n" + "[dri] libdrm.a module version is %d.%d.%d but version %d.%d.x is needed.\n" + "[dri] Disabling DRI.\n", + version->version_major, + version->version_minor, version->version_patchlevel, + REQ_MAJ, REQ_MIN); + drmFreeVersion(version); + I810DRICloseScreen(pScreen); + return FALSE; + } + drmFreeVersion(version); + } + + /* Check the i810 DRM version */ + version = drmGetVersion(pI810->drmSubFD); + if (version) { + i810_drm_version = (version->version_major<<16) | + version->version_minor; + if (version->version_major != 1 || version->version_minor < 2) { + /* incompatible drm version */ + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[dri] I810DRIScreenInit failed because of a version mismatch.\n" + "[dri] i810.o kernel module version is %d.%d.%d but version 1.2.0 or greater is needed.\n" + "[dri] Disabling DRI.\n", + version->version_major, + version->version_minor, version->version_patchlevel); + I810DRICloseScreen(pScreen); + drmFreeVersion(version); + return FALSE; + } + pI810->drmMinor = version->version_minor; + drmFreeVersion(version); + } + } + + pI810DRI->regsSize = I810_REG_SIZE; + if (drmAddMap(pI810->drmSubFD, (drm_handle_t) pI810->MMIOAddr, + pI810DRI->regsSize, DRM_REGISTERS, 0, + (drmAddress) &pI810DRI->regs) < 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, "[drm] drmAddMap(regs) failed\n"); + DRICloseScreen(pScreen); + return FALSE; + } + xf86DrvMsg(pScreen->myNum, X_INFO, "[drm] Registers = 0x%08x\n", + (int)pI810DRI->regs); + + pI810->backHandle = DRM_AGP_NO_HANDLE; + pI810->zHandle = DRM_AGP_NO_HANDLE; + pI810->cursorHandle = DRM_AGP_NO_HANDLE; + pI810->xvmcHandle = DRM_AGP_NO_HANDLE; + pI810->sysmemHandle = DRM_AGP_NO_HANDLE; + pI810->agpAcquired = FALSE; + pI810->dcacheHandle = DRM_AGP_NO_HANDLE; + + /* Agp Support - Need this just to get the framebuffer. + */ + if (drmAgpAcquire(pI810->drmSubFD) < 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, "[agp] drmAgpAquire failed\n"); + DRICloseScreen(pScreen); + return FALSE; + } + pI810->agpAcquired = TRUE; + + if (drmAgpEnable(pI810->drmSubFD, 0) < 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, "[agp] drmAgpEnable failed\n"); + DRICloseScreen(pScreen); + return FALSE; + } + + memset(&pI810->DcacheMem, 0, sizeof(I810MemRange)); + memset(&pI810->BackBuffer, 0, sizeof(I810MemRange)); + memset(&pI810->DepthBuffer, 0, sizeof(I810MemRange)); + pI810->CursorPhysical = 0; + pI810->CursorARGBPhysical = 0; + + /* Dcache - half the speed of normal ram, but has use as a Z buffer + * under the DRI. + */ + + drmAgpAlloc(pI810->drmSubFD, 4096 * 1024, 1, NULL, + (drmAddress) &dcacheHandle); + pI810->dcacheHandle = dcacheHandle; + + xf86DrvMsg(pScreen->myNum, X_INFO, "[agp] dcacheHandle : 0x%x\n", + (int)dcacheHandle); + + sysmem_size = pScrn->videoRam * 1024; + if (dcacheHandle != DRM_AGP_NO_HANDLE) { + if (back_size > 4 * 1024 * 1024) { + xf86DrvMsg(pScreen->myNum, X_INFO, + "[dri] Backsize is larger then 4 meg\n"); + sysmem_size = sysmem_size - 2 * back_size; + drmAgpFree(pI810->drmSubFD, dcacheHandle); + pI810->dcacheHandle = dcacheHandle = DRM_AGP_NO_HANDLE; + } else { + sysmem_size = sysmem_size - back_size; + } + } else { + sysmem_size = sysmem_size - 2 * back_size; + } + + /* Max size is 48 without XvMC, 41 with 6 surfaces, 40 with 7 surfaces */ + if (pI810->numSurfaces && (pI810->numSurfaces == 6)) { + if (sysmem_size > (pI810->FbMapSize - 7 * 1024 * 1024)) { + sysmem_size = (pI810->FbMapSize - 7 * 1024 * 1024); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "User requested more memory then fits in the agp aperture\n" + "Truncating to %d bytes of memory\n", sysmem_size); + } + } + if (pI810->numSurfaces && (pI810->numSurfaces == 7)) { + if (sysmem_size > (pI810->FbMapSize - 8 * 1024 * 1024)) { + sysmem_size = (pI810->FbMapSize - 8 * 1024 * 1024); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "User requested more memory then fits in the agp aperture\n" + "Truncating to %d bytes of memory\n", sysmem_size); + } + } + + if (sysmem_size > pI810->FbMapSize) { + sysmem_size = pI810->FbMapSize; + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "[dri] User requested more memory then fits in the agp" + " aperture\n\tTruncating to %d bytes of memory\n", + sysmem_size); + } + + sysmem_size -= 4096; /* remove 4k for the hw cursor */ + sysmem_size -= 16384; /* remove 16k for the ARGB hw cursor */ + + pI810->SysMem.Start = 0; + pI810->SysMem.Size = sysmem_size; + pI810->SysMem.End = sysmem_size; + tom = sysmem_size; + + pI810->SavedSysMem = pI810->SysMem; + + if (dcacheHandle != DRM_AGP_NO_HANDLE) { + if (drmAgpBind(pI810->drmSubFD, dcacheHandle, pI810->DepthOffset) == 0) { + memset(&pI810->DcacheMem, 0, sizeof(I810MemRange)); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "[agp] GART: Found 4096K Z buffer memory\n"); + pI810->DcacheMem.Start = pI810->DepthOffset; + pI810->DcacheMem.Size = 1024 * 4096; + pI810->DcacheMem.End = + pI810->DcacheMem.Start + pI810->DcacheMem.Size; + if (!I810AllocLow + (&(pI810->DepthBuffer), &(pI810->DcacheMem), back_size)) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "[agp] Depth buffer allocation failed\n"); + DRICloseScreen(pScreen); + return FALSE; + } + } else { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "[agp] GART: dcache bind failed\n"); + drmAgpFree(pI810->drmSubFD, dcacheHandle); + pI810->dcacheHandle = dcacheHandle = DRM_AGP_NO_HANDLE; + } + } else { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "[agp] GART: no dcache memory found\n"); + } + + drmAgpAlloc(pI810->drmSubFD, back_size, 0, NULL, + (drmAddress) &agpHandle); + pI810->backHandle = agpHandle; + + if (agpHandle != DRM_AGP_NO_HANDLE) { + if (drmAgpBind(pI810->drmSubFD, agpHandle, pI810->BackOffset) == 0) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "[agp] Bound backbuffer memory\n"); + + pI810->BackBuffer.Start = pI810->BackOffset; + pI810->BackBuffer.Size = back_size; + pI810->BackBuffer.End = (pI810->BackBuffer.Start + + pI810->BackBuffer.Size); + } else { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "[agp] Unable to bind backbuffer. Disabling DRI.\n"); + DRICloseScreen(pScreen); + return FALSE; + } + } else { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "[dri] Unable to allocate backbuffer memory. Disabling DRI.\n"); + DRICloseScreen(pScreen); + return FALSE; + } + + if (dcacheHandle == DRM_AGP_NO_HANDLE) { + drmAgpAlloc(pI810->drmSubFD, back_size, 0, NULL, + (drmAddress) &agpHandle); + + pI810->zHandle = agpHandle; + + if (agpHandle != DRM_AGP_NO_HANDLE) { + if (drmAgpBind(pI810->drmSubFD, agpHandle, pI810->DepthOffset) == 0) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "[agp] Bound depthbuffer memory\n"); + pI810->DepthBuffer.Start = pI810->DepthOffset; + pI810->DepthBuffer.Size = back_size; + pI810->DepthBuffer.End = (pI810->DepthBuffer.Start + + pI810->DepthBuffer.Size); + } else { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "[agp] Unable to bind depthbuffer. Disabling DRI.\n"); + DRICloseScreen(pScreen); + return FALSE; + } + } else { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "[agp] Unable to allocate depthbuffer memory. Disabling DRI.\n"); + DRICloseScreen(pScreen); + return FALSE; + } + } + + /* Now allocate and bind the agp space. This memory will include the + * regular framebuffer as well as texture memory. + */ + drmAgpAlloc(pI810->drmSubFD, sysmem_size, 0, NULL, + (drmAddress)&agpHandle); + pI810->sysmemHandle = agpHandle; + + if (agpHandle != DRM_AGP_NO_HANDLE) { + if (drmAgpBind(pI810->drmSubFD, agpHandle, 0) == 0) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "[agp] Bound System Texture Memory\n"); + } else { + xf86DrvMsg(pScreen->myNum, X_ERROR, "[agp] Unable to bind system texture memory. Disabling DRI.\n"); + DRICloseScreen(pScreen); + return FALSE; + } + } else { + xf86DrvMsg(pScreen->myNum, X_ERROR, "[agp] Unable to allocate system texture memory. Disabling DRI.\n"); + DRICloseScreen(pScreen); + return FALSE; + } + +/* Allocate 7 or 8MB for XvMC this is setup as follows to best use tiled + regions and required surface pitches. (Numbers are adjusted if the + AGP region is only 32MB + For numSurfaces == 6 + 44 - 48MB = 4MB Fence, 8 Tiles wide + 43 - 44MB = 1MB Fence, 8 Tiles wide + 42 - 43MB = 1MB Fence, 4 Tiles wide + 41 - 42MB = 1MB Fence, 4 Tiles wide + For numSurfaces == 7 + 44 - 48MB = 4MB Fence, 8 Tiles wide + 43 - 44MB = 1MB Fence, 8 Tiles wide + 42.5 - 43MB = 0.5MB Fence, 8 Tiles wide + 42 - 42.5MB = 0.5MB Fence, 4 Tiles wide + 40 - 42MB = 2MB Fence, 4 Tiles wide + */ + if (pI810->numSurfaces) { + if (pI810->numSurfaces == 6) { + pI810->MC.Size = 7 * 1024 * 1024; + pI810->MC.Start = pI810->FbMapSize - 7 * 1024 * 1024; + + } + if (pI810->numSurfaces == 7) { + pI810->MC.Size = 8 * 1024 * 1024; + pI810->MC.Start = pI810->FbMapSize - 8 * 1024 * 1024; + } + drmAgpAlloc(pI810->drmSubFD, pI810->MC.Size, 0, NULL, + (drmAddress) &agpHandle); + + pI810->xvmcHandle = agpHandle; + + if (agpHandle != DRM_AGP_NO_HANDLE) { + if (drmAgpBind(pI810->drmSubFD, agpHandle, pI810->MC.Start) == 0) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "GART: Allocated 7MB for HWMC\n"); + pI810->MC.End = pI810->MC.Start + pI810->MC.Size; + } else { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "GART: HWMC bind failed\n"); + pI810->MC.Start = 0; + pI810->MC.Size = 0; + pI810->MC.End = 0; + } + } else { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "GART: HWMC alloc failed\n"); + pI810->MC.Start = 0; + pI810->MC.Size = 0; + pI810->MC.End = 0; + } + pI810->xvmcContext = 0; + } + + drmAgpAlloc(pI810->drmSubFD, 4096, 2, + (unsigned long *)&pI810->CursorPhysical, + (drmAddress) &agpHandle); + + pI810->cursorHandle = agpHandle; + + if (agpHandle != DRM_AGP_NO_HANDLE) { + tom = sysmem_size; + + if (drmAgpBind(pI810->drmSubFD, agpHandle, tom) == 0) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "[agp] GART: Allocated 4K for mouse cursor image\n"); + pI810->CursorStart = tom; + tom += 4096; + } else { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "[agp] GART: cursor bind failed\n"); + pI810->CursorPhysical = 0; + } + } else { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "[agp] GART: cursor alloc failed\n"); + pI810->CursorPhysical = 0; + } + + drmAgpAlloc(pI810->drmSubFD, 16384, 2, + (unsigned long *)&pI810->CursorARGBPhysical, + (drmAddress) &agpHandle); + + pI810->cursorARGBHandle = agpHandle; + + if (agpHandle != DRM_AGP_NO_HANDLE) { + int r; + + if ((r = drmAgpBind(pI810->drmSubFD, agpHandle, tom)) == 0) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "[agp] GART: Allocated 16K for ARGB mouse cursor image\n"); + pI810->CursorARGBStart = tom; + tom += 16384; + } else { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "[agp] GART: ARGB cursor bind failed\n"); + pI810->CursorARGBPhysical = 0; + } + } else { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "[agp] GART: ARGB cursor alloc failed\n"); + pI810->CursorARGBPhysical = 0; + } + + /* Steal some of the excess cursor space for the overlay regs. + */ + pI810->OverlayPhysical = pI810->CursorPhysical + 1024; + pI810->OverlayStart = pI810->CursorStart + 1024; + + I810SetTiledMemory(pScrn, 1, + pI810->DepthBuffer.Start, + i810_pitches[pitch_idx], 8 * 1024 * 1024); + + I810SetTiledMemory(pScrn, 2, + pI810->BackBuffer.Start, + i810_pitches[pitch_idx], 8 * 1024 * 1024); + + /* These are for HWMC surfaces */ + if (pI810->numSurfaces == 6) { + I810SetTiledMemory(pScrn, 3, pI810->MC.Start, 512, 1024 * 1024); + + I810SetTiledMemory(pScrn, 4, + pI810->MC.Start + 1024 * 1024, 512, 1024 * 1024); + + I810SetTiledMemory(pScrn, 5, + pI810->MC.Start + 1024 * 1024 * 2, + 1024, 1024 * 1024); + + I810SetTiledMemory(pScrn, 6, + pI810->MC.Start + 1024 * 1024 * 3, + 1024, 4 * 1024 * 1024); + } + if (pI810->numSurfaces == 7) { + I810SetTiledMemory(pScrn, 3, pI810->MC.Start, 512, 2 * 1024 * 1024); + + I810SetTiledMemory(pScrn, 4, + pI810->MC.Start + 2 * 1024 * 1024, 512, 512 * 1024); + + I810SetTiledMemory(pScrn, 5, + pI810->MC.Start + 2 * 1024 * 1024 + 512 * 1024, + 1024, 512 * 1024); + + I810SetTiledMemory(pScrn, 6, + pI810->MC.Start + 3 * 1024 * 1024, + 1024, 1 * 1024 * 1024); + + I810SetTiledMemory(pScrn, 7, + pI810->MC.Start + 4 * 1024 * 1024, + 1024, 4 * 1024 * 1024); + + } + + pI810->auxPitch = i810_pitches[pitch_idx]; + pI810->auxPitchBits = i810_pitch_flags[pitch_idx]; + pI810->SavedDcacheMem = pI810->DcacheMem; + pI810DRI->backbufferSize = pI810->BackBuffer.Size; + + if (drmAddMap(pI810->drmSubFD, (drm_handle_t) pI810->BackBuffer.Start, + pI810->BackBuffer.Size, DRM_AGP, 0, + (drmAddress) &pI810DRI->backbuffer) < 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[drm] drmAddMap(backbuffer) failed. Disabling DRI\n"); + DRICloseScreen(pScreen); + return FALSE; + } + + pI810DRI->depthbufferSize = pI810->DepthBuffer.Size; + if (drmAddMap(pI810->drmSubFD, (drm_handle_t) pI810->DepthBuffer.Start, + pI810->DepthBuffer.Size, DRM_AGP, 0, + (drmAddress) &pI810DRI->depthbuffer) < 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[drm] drmAddMap(depthbuffer) failed. Disabling DRI.\n"); + DRICloseScreen(pScreen); + return FALSE; + } + + /* Allocate FrontBuffer etc. */ + if (!I810AllocateFront(pScrn)) { + DRICloseScreen(pScreen); + return FALSE; + } + + /* Allocate buffer memory */ + I810AllocHigh(&(pI810->BufferMem), &(pI810->SysMem), + I810_DMA_BUF_NR * I810_DMA_BUF_SZ); + + xf86DrvMsg(pScreen->myNum, X_INFO, "[dri] Buffer map : %lx\n", + pI810->BufferMem.Start); + + if (pI810->BufferMem.Start == 0 || + pI810->BufferMem.End - pI810->BufferMem.Start > + I810_DMA_BUF_NR * I810_DMA_BUF_SZ) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[dri] Not enough memory for dma buffers. Disabling DRI.\n"); + DRICloseScreen(pScreen); + return FALSE; + } + if (drmAddMap(pI810->drmSubFD, (drm_handle_t) pI810->BufferMem.Start, + pI810->BufferMem.Size, DRM_AGP, 0, + (drmAddress) &pI810->buffer_map) < 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[drm] drmAddMap(buffer_map) failed. Disabling DRI.\n"); + DRICloseScreen(pScreen); + return FALSE; + } + + pI810DRI->agp_buffers = pI810->buffer_map; + pI810DRI->agp_buf_size = pI810->BufferMem.Size; + + if (drmAddMap(pI810->drmSubFD, (drm_handle_t) pI810->LpRing->mem.Start, + pI810->LpRing->mem.Size, DRM_AGP, 0, + (drmAddress) &pI810->ring_map) < 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[drm] drmAddMap(ring_map) failed. Disabling DRI.\n"); + DRICloseScreen(pScreen); + return FALSE; + } + + /* Use the rest of memory for textures. */ + pI810DRI->textureSize = pI810->SysMem.Size; + + i = mylog2(pI810DRI->textureSize / I810_NR_TEX_REGIONS); + + if (i < I810_LOG_MIN_TEX_REGION_SIZE) + i = I810_LOG_MIN_TEX_REGION_SIZE; + + pI810DRI->logTextureGranularity = i; + pI810DRI->textureSize = (pI810DRI->textureSize >> i) << i; /* truncate */ + + if (pI810DRI->textureSize < 512 * 1024) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[drm] Less then 512k memory left for textures. Disabling DRI.\n"); + DRICloseScreen(pScreen); + return FALSE; + } + + I810AllocLow(&(pI810->TexMem), &(pI810->SysMem), pI810DRI->textureSize); + + if (drmAddMap(pI810->drmSubFD, (drm_handle_t) pI810->TexMem.Start, + pI810->TexMem.Size, DRM_AGP, 0, + (drmAddress) &pI810DRI->textures) < 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[drm] drmAddMap(textures) failed. Disabling DRI.\n"); + DRICloseScreen(pScreen); + return FALSE; + } + + if ((bufs = drmAddBufs(pI810->drmSubFD, + I810_DMA_BUF_NR, + I810_DMA_BUF_SZ, + DRM_AGP_BUFFER, pI810->BufferMem.Start)) <= 0) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "[drm] failure adding %d %d byte DMA buffers. Disabling DRI.\n", + I810_DMA_BUF_NR, I810_DMA_BUF_SZ); + DRICloseScreen(pScreen); + return FALSE; + } + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "[drm] added %d %d byte DMA buffers\n", bufs, I810_DMA_BUF_SZ); + + I810InitDma(pScrn); + + /* Okay now initialize the dma engine */ + + if (!pI810DRI->irq) { + pI810DRI->irq = drmGetInterruptFromBusID(pI810->drmSubFD, + ((pI810->PciInfo->domain << 8) | + pI810->PciInfo->bus), + pI810->PciInfo->dev, + pI810->PciInfo->func + ); + if ((drmCtlInstHandler(pI810->drmSubFD, pI810DRI->irq)) != 0) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "[drm] failure adding irq handler, there is a device " + "already using that irq\n Consider rearranging your " + "PCI cards. Disabling DRI.\n"); + DRICloseScreen(pScreen); + return FALSE; + } + } + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "[drm] dma control initialized, using IRQ %d\n", pI810DRI->irq); + + pI810DRI->deviceID = DEVICE_ID(pI810->PciInfo); + pI810DRI->width = pScrn->virtualX; + pI810DRI->height = pScrn->virtualY; + pI810DRI->mem = pScrn->videoRam * 1024; + pI810DRI->cpp = pI810->cpp; + + pI810DRI->fbOffset = pI810->FrontBuffer.Start; + pI810DRI->fbStride = pI810->auxPitch; + + pI810DRI->bitsPerPixel = pScrn->bitsPerPixel; + + pI810DRI->textureOffset = pI810->TexMem.Start; + + pI810DRI->backOffset = pI810->BackBuffer.Start; + pI810DRI->depthOffset = pI810->DepthBuffer.Start; + + pI810DRI->ringOffset = pI810->LpRing->mem.Start; + pI810DRI->ringSize = pI810->LpRing->mem.Size; + + pI810DRI->auxPitch = pI810->auxPitch; + pI810DRI->auxPitchBits = pI810->auxPitchBits; + pI810DRI->sarea_priv_offset = sizeof(XF86DRISAREARec); + + if (!(I810InitVisualConfigs(pScreen))) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[dri] I810InitVisualConfigs failed. Disabling DRI.\n"); + DRICloseScreen(pScreen); + return FALSE; + } + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "[dri] visual configs initialized.\n"); + pI810->pDRIInfo->driverSwapMethod = DRI_HIDE_X_CONTEXT; + + return TRUE; +} + +void +I810DRICloseScreen(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + I810Ptr pI810 = I810PTR(pScrn); + I810DRIPtr pI810DRI = (I810DRIPtr) pI810->pDRIInfo->devPrivate; + + if (pI810DRI->irq) { + drmCtlUninstHandler(pI810->drmSubFD); + pI810DRI->irq = 0; + } + + I810CleanupDma(pScrn); + + if (pI810->dcacheHandle!=DRM_AGP_NO_HANDLE) + drmAgpFree(pI810->drmSubFD, pI810->dcacheHandle); + if (pI810->backHandle!=DRM_AGP_NO_HANDLE) + drmAgpFree(pI810->drmSubFD, pI810->backHandle); + if (pI810->zHandle!=DRM_AGP_NO_HANDLE) + drmAgpFree(pI810->drmSubFD, pI810->zHandle); + if (pI810->cursorHandle!=DRM_AGP_NO_HANDLE) + drmAgpFree(pI810->drmSubFD, pI810->cursorHandle); + if (pI810->xvmcHandle!=DRM_AGP_NO_HANDLE) + drmAgpFree(pI810->drmSubFD, pI810->xvmcHandle); + if (pI810->sysmemHandle!=DRM_AGP_NO_HANDLE) + drmAgpFree(pI810->drmSubFD, pI810->sysmemHandle); + + if (pI810->agpAcquired == TRUE) + drmAgpRelease(pI810->drmSubFD); + + pI810->backHandle = DRM_AGP_NO_HANDLE; + pI810->zHandle = DRM_AGP_NO_HANDLE; + pI810->cursorHandle = DRM_AGP_NO_HANDLE; + pI810->xvmcHandle = DRM_AGP_NO_HANDLE; + pI810->sysmemHandle = DRM_AGP_NO_HANDLE; + pI810->agpAcquired = FALSE; + pI810->dcacheHandle = DRM_AGP_NO_HANDLE; + + DRICloseScreen(pScreen); + + if (pI810->pDRIInfo) { + if (pI810->pDRIInfo->devPrivate) { + free(pI810->pDRIInfo->devPrivate); + pI810->pDRIInfo->devPrivate = NULL; + } + DRIDestroyInfoRec(pI810->pDRIInfo); + pI810->pDRIInfo = NULL; + } + if (pI810->pVisualConfigs) + free(pI810->pVisualConfigs); + if (pI810->pVisualConfigsPriv) + free(pI810->pVisualConfigsPriv); +} + +static Bool +I810CreateContext(ScreenPtr pScreen, VisualPtr visual, + drm_context_t hwContext, void *pVisualConfigPriv, + DRIContextType contextStore) +{ + return TRUE; +} + +static void +I810DestroyContext(ScreenPtr pScreen, drm_context_t hwContext, + DRIContextType contextStore) +{ +} + +Bool +I810DRIFinishScreenInit(ScreenPtr pScreen) +{ + I810SAREARec *sPriv = (I810SAREARec *) DRIGetSAREAPrivate(pScreen); + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + I810Ptr info = I810PTR(pScrn); + + memset(sPriv, 0, sizeof(sPriv)); + + /* Have shadow run only while there is 3d active. + */ + if (info->allowPageFlip && info->drmMinor >= 3) { + ShadowFBInit( pScreen, I810DRIRefreshArea ); + } + else + info->allowPageFlip = 0; + return DRIFinishScreenInit(pScreen); +} + +void +I810DRISwapContext(ScreenPtr pScreen, DRISyncType syncType, + DRIContextType oldContextType, void *oldContext, + DRIContextType newContextType, void *newContext) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + I810Ptr pI810 = I810PTR(pScrn); + + if (syncType == DRI_3D_SYNC && + oldContextType == DRI_2D_CONTEXT && newContextType == DRI_2D_CONTEXT) { + if (I810_DEBUG & DEBUG_VERBOSE_DRI) + ErrorF("I810DRISwapContext (in)\n"); + + if (!pScrn->vtSema) + return; + pI810->LockHeld = 1; + I810RefreshRing(pScrn); + } else if (syncType == DRI_2D_SYNC && + oldContextType == DRI_NO_CONTEXT && + newContextType == DRI_2D_CONTEXT) { + pI810->LockHeld = 0; + if (I810_DEBUG & DEBUG_VERBOSE_DRI) + ErrorF("I810DRISwapContext (out)\n"); + } else if (I810_DEBUG & DEBUG_VERBOSE_DRI) + ErrorF("I810DRISwapContext (other)\n"); +} + +static void +I810DRIInitBuffers(WindowPtr pWin, RegionPtr prgn, CARD32 index) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + I810Ptr pI810 = I810PTR(pScrn); + BoxPtr pbox = REGION_RECTS(prgn); + int nbox = REGION_NUM_RECTS(prgn); + + if (I810_DEBUG & DEBUG_VERBOSE_DRI) + ErrorF("I810DRIInitBuffers\n"); + + I810SetupForSolidFill(pScrn, 0, GXcopy, -1); + while (nbox--) { + I810SelectBuffer(pScrn, I810_SELECT_BACK); + I810SubsequentSolidFillRect(pScrn, pbox->x1, pbox->y1, + pbox->x2 - pbox->x1, pbox->y2 - pbox->y1); + pbox++; + } + + /* Clear the depth buffer - uses 0xffff rather than 0. + */ + pbox = REGION_RECTS(prgn); + nbox = REGION_NUM_RECTS(prgn); + I810SelectBuffer(pScrn, I810_SELECT_DEPTH); + I810SetupForSolidFill(pScrn, 0xffff, GXcopy, -1); + while (nbox--) { + I810SubsequentSolidFillRect(pScrn, pbox->x1, pbox->y1, + pbox->x2 - pbox->x1, pbox->y2 - pbox->y1); + pbox++; + } + I810SelectBuffer(pScrn, I810_SELECT_FRONT); + + if (pI810->AccelInfoRec) + pI810->AccelInfoRec->NeedToSync = TRUE; +} + +/* 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. + * + * KW: can you believe that this is called even when a 2d window moves? + */ +static void +I810DRIMoveBuffers(WindowPtr pParent, DDXPointRec ptOldOrg, + RegionPtr prgnSrc, CARD32 index) +{ + ScreenPtr pScreen = pParent->drawable.pScreen; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + I810Ptr pI810 = I810PTR(pScrn); + BoxPtr pboxTmp, pboxNext, pboxBase; + DDXPointPtr pptTmp, pptNew2 = NULL; + int xdir, ydir; + + int screenwidth = pScrn->virtualX; + int screenheight = pScrn->virtualY; + + BoxPtr pbox = REGION_RECTS(prgnSrc); + int nbox = REGION_NUM_RECTS(prgnSrc); + + BoxPtr pboxNew1 = NULL; + BoxPtr pboxNew2 = NULL; + DDXPointPtr pptNew1 = NULL; + DDXPointPtr pptSrc = &ptOldOrg; + + int dx = pParent->drawable.x - ptOldOrg.x; + int dy = pParent->drawable.y - ptOldOrg.y; + + /* 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) malloc(sizeof(BoxRec) * nbox); + if (!pboxNew1) + return; + pptNew1 = (DDXPointPtr) malloc(sizeof(DDXPointRec) * nbox); + if (!pptNew1) { + free(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 orderof rects in each band */ + pboxNew2 = (BoxPtr) malloc(sizeof(BoxRec) * nbox); + pptNew2 = (DDXPointPtr) malloc(sizeof(DDXPointRec) * nbox); + if (!pboxNew2 || !pptNew2) { + if (pptNew2) + free(pptNew2); + if (pboxNew2) + free(pboxNew2); + if (pboxNew1) { + free(pptNew1); + free(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; + } + + /* SelectBuffer isn't really a good concept for the i810. + */ + I810EmitFlush(pScrn); + I810SetupForScreenToScreenCopy(pScrn, xdir, ydir, GXcopy, -1, -1); + for (; nbox--; pbox++) { + + int x1 = pbox->x1; + int y1 = pbox->y1; + int destx = x1 + dx; + int desty = y1 + dy; + int w = pbox->x2 - x1 + 1; + int h = pbox->y2 - y1 + 1; + + if (destx < 0) + x1 -= destx, w += destx, destx = 0; + if (desty < 0) + y1 -= 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; + + if (I810_DEBUG & DEBUG_VERBOSE_DRI) + ErrorF("MoveBuffers %d,%d %dx%d dx: %d dy: %d\n", + x1, y1, w, h, dx, dy); + + I810SelectBuffer(pScrn, I810_SELECT_BACK); + I810SubsequentScreenToScreenCopy(pScrn, x1, y1, destx, desty, w, h); + I810SelectBuffer(pScrn, I810_SELECT_DEPTH); + I810SubsequentScreenToScreenCopy(pScrn, x1, y1, destx, desty, w, h); + } + I810SelectBuffer(pScrn, I810_SELECT_FRONT); + I810EmitFlush(pScrn); + + if (pboxNew2) { + free(pptNew2); + free(pboxNew2); + } + if (pboxNew1) { + free(pptNew1); + free(pboxNew1); + } + + if (pI810->AccelInfoRec) + pI810->AccelInfoRec->NeedToSync = TRUE; +} + + +/* Use the miext/shadow module to maintain a list of dirty rectangles. + * These are blitted to the back buffer to keep both buffers clean + * during page-flipping when the 3d application isn't fullscreen. + * + * Unlike most use of the shadow code, both buffers are in video memory. + * + * An alternative to this would be to organize for all on-screen drawing + * operations to be duplicated for the two buffers. That might be + * faster, but seems like a lot more work... + */ + + +/* This should be done *before* XAA syncs or fires its buffer. + * Otherwise will have to fire it again??? + */ +static void I810DRIRefreshArea(ScrnInfoPtr pScrn, int num, BoxPtr pbox) +{ + I810Ptr pI810 = I810PTR(pScrn); + int i; + I810SAREAPtr pSAREAPriv = DRIGetSAREAPrivate(pScrn->pScreen); + unsigned int br13; + int cpp=2; + + + /* Don't want to do this when no 3d is active and pages are + * right-way-round + */ + if (!pSAREAPriv->pf_active && pSAREAPriv->pf_current_page == 0) + return; + + br13 = (pI810->auxPitch) | (0xcc << 16); + + for (i = 0 ; i < num ; i++, pbox++) { + unsigned int w = min(pbox->y2, pScrn->virtualY-1) - max(pbox->y1, 0) + 1; + unsigned int h = min(pbox->x2, pScrn->virtualX-1) - max(pbox->x1, 0) + 1; + unsigned int dst = max(pbox->x1, 0)*cpp + (max(pbox->y1, 0)*pI810->auxPitch); + + BEGIN_LP_RING(6); + + OUT_RING(BR00_BITBLT_CLIENT | BR00_OP_SRC_COPY_BLT | 0x4); + OUT_RING(br13); + OUT_RING( (h<<16) | (w*cpp) ); + OUT_RING(pI810->BackBuffer.Start + dst); + OUT_RING(br13 & 0xffff); + OUT_RING(dst); + + ADVANCE_LP_RING(); + } + +} + +static void I810EnablePageFlip(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + I810Ptr pI810 = I810PTR(pScrn); + I810SAREAPtr pSAREAPriv = DRIGetSAREAPrivate(pScreen); + int cpp=2; + pSAREAPriv->pf_enabled = pI810->allowPageFlip; + pSAREAPriv->pf_active = 0; + + if (pI810->allowPageFlip) { + unsigned int br13 = pI810->auxPitch | (0xcc << 16); + + BEGIN_LP_RING(6); + + OUT_RING(BR00_BITBLT_CLIENT | BR00_OP_SRC_COPY_BLT | 0x4); + OUT_RING(br13); + OUT_RING((pScrn->virtualY << 16) | (pScrn->virtualX*cpp)); + OUT_RING(pI810->BackBuffer.Start); + OUT_RING(br13 & 0xFFFF); + OUT_RING(0); + ADVANCE_LP_RING(); + + pSAREAPriv->pf_active = 1; + } + +} + +static void I810DisablePageFlip(ScreenPtr pScreen) +{ + I810SAREAPtr pSAREAPriv = DRIGetSAREAPrivate(pScreen); + + pSAREAPriv->pf_active=0; +} + +static void I810DRITransitionSingleToMulti3d(ScreenPtr pScreen) +{ + /* Tell the clients not to pageflip. How? + * -- Field in sarea, plus bumping the window counters. + * -- DRM needs to cope with Front-to-Back swapbuffers. + */ + I810DisablePageFlip(pScreen); +} + +static void I810DRITransitionMultiToSingle3d(ScreenPtr pScreen) +{ + /* Let the remaining 3d app start page flipping again */ + I810EnablePageFlip(pScreen); +} + +static void I810DRITransitionTo3d(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + I810Ptr pI810 = I810PTR(pScrn); + + I810EnablePageFlip(pScreen); + pI810->have3DWindows = 1; +} + +static void I810DRITransitionTo2d(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + I810Ptr pI810 = I810PTR(pScrn); + I810SAREAPtr pSAREAPriv = DRIGetSAREAPrivate(pScreen); + + /* Try flipping back to the front page if necessary */ + if (pSAREAPriv->pf_current_page == 1) + drmCommandNone(pI810->drmSubFD, DRM_I810_FLIP); + + /* Shut down shadowing if we've made it back to the front page */ + if (pSAREAPriv->pf_current_page == 0) { + I810DisablePageFlip(pScreen); + } + pI810->have3DWindows = 0; +} + +Bool +I810DRILeave(ScrnInfoPtr pScrn) +{ + I810Ptr pI810 = I810PTR(pScrn); + + if (pI810->directRenderingEnabled) { + if (pI810->dcacheHandle != 0) + if (drmAgpUnbind(pI810->drmSubFD, pI810->dcacheHandle) != 0) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR,"%s\n",strerror(errno)); + return FALSE; + } + if (pI810->backHandle != 0) + if (drmAgpUnbind(pI810->drmSubFD, pI810->backHandle) != 0) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR,"%s\n",strerror(errno)); + return FALSE; + } + if (pI810->zHandle != 0) + if (drmAgpUnbind(pI810->drmSubFD, pI810->zHandle) != 0) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR,"%s\n",strerror(errno)); + return FALSE; + } + if (pI810->sysmemHandle != 0) + if (drmAgpUnbind(pI810->drmSubFD, pI810->sysmemHandle) != 0) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR,"%s\n",strerror(errno)); + return FALSE; + } + if (pI810->xvmcHandle != 0) + if (drmAgpUnbind(pI810->drmSubFD, pI810->xvmcHandle) != 0) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR,"%s\n",strerror(errno)); + return FALSE; + } + if (pI810->cursorHandle != 0) + if (drmAgpUnbind(pI810->drmSubFD, pI810->cursorHandle) != 0) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR,"%s\n",strerror(errno)); + return FALSE; + } + if (pI810->cursorARGBHandle != 0) + if (drmAgpUnbind(pI810->drmSubFD, pI810->cursorARGBHandle) != 0) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR,"%s\n",strerror(errno)); + return FALSE; + } + if (pI810->agpAcquired == TRUE) + drmAgpRelease(pI810->drmSubFD); + pI810->agpAcquired = FALSE; + } + return TRUE; +} + +Bool +I810DRIEnter(ScrnInfoPtr pScrn) +{ + I810Ptr pI810 = I810PTR(pScrn); + + if (pI810->directRenderingEnabled) { + + if (pI810->agpAcquired == FALSE) + drmAgpAcquire(pI810->drmSubFD); + pI810->agpAcquired = TRUE; + if (pI810->dcacheHandle != 0) + if (drmAgpBind(pI810->drmSubFD, pI810->dcacheHandle, + pI810->DepthOffset) != 0) + return FALSE; + if (pI810->backHandle != 0) + if (drmAgpBind(pI810->drmSubFD, pI810->backHandle, + pI810->BackOffset) != 0) + return FALSE; + if (pI810->zHandle != 0) + if (drmAgpBind(pI810->drmSubFD, pI810->zHandle, + pI810->DepthOffset) != 0) + return FALSE; + if (pI810->sysmemHandle != 0) + if (drmAgpBind(pI810->drmSubFD, pI810->sysmemHandle, 0) != 0) + return FALSE; + if (pI810->xvmcHandle != 0) + if (drmAgpBind(pI810->drmSubFD, pI810->xvmcHandle, + pI810->MC.Start) != 0) + return FALSE; + if (pI810->cursorHandle != 0) + if (drmAgpBind(pI810->drmSubFD, pI810->cursorHandle, + pI810->CursorStart) != 0) + return FALSE; + if (pI810->cursorARGBHandle != 0) + if (drmAgpBind(pI810->drmSubFD, pI810->cursorARGBHandle, + pI810->CursorARGBStart) != 0) + return FALSE; + } + return TRUE; +} |