diff options
Diffstat (limited to 'src/i810_dri.c')
-rw-r--r-- | src/i810_dri.c | 1220 |
1 files changed, 1220 insertions, 0 deletions
diff --git a/src/i810_dri.c b/src/i810_dri.c new file mode 100644 index 00000000..11ecacf0 --- /dev/null +++ b/src/i810_dri.c @@ -0,0 +1,1220 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/i810/i810_dri.c,v 1.33 2002/12/10 01:27:04 dawes Exp $ */ +/* + * Reformatted with GNU indent (2.2.8), using the following options: + * + * -bad -bap -c41 -cd0 -ncdb -ci6 -cli0 -cp0 -ncs -d0 -di3 -i3 -ip3 -l78 + * -lp -npcs -psl -sob -ss -br -ce -sc -hnl + * + * This provides a good match with the original i810 code and preferred + * XFree86 formatting conventions. + * + * When editing this driver, please follow the existing formatting, and edit + * with <TAB> characters expanded at 8-column intervals. + */ + +#include "xf86.h" +#include "xf86_OSproc.h" +#include "xf86_ansic.h" +#include "xf86Priv.h" + +#include "xf86PciInfo.h" +#include "xf86Pci.h" + +#include "windowstr.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, + drmContext hwContext, void *pVisualConfigPriv, + DRIContextType contextStore); +static void I810DestroyContext(ScreenPtr pScreen, drmContext 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); + +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 +}; + +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.func = I810_INIT_DMA; + + 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; + + 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 = 0; + I810ConfigPrivPtr pI810Configs = 0; + I810ConfigPrivPtr *pI810ConfigPtrs = 0; + int accum, stencil, db, depth; + int i; + + switch (pScrn->bitsPerPixel) { + case 8: + case 24: + case 32: + break; + case 16: + numConfigs = 8; + + pConfigs = + (__GLXvisualConfig *) xcalloc(sizeof(__GLXvisualConfig), + numConfigs); + if (!pConfigs) + return FALSE; + + pI810Configs = + (I810ConfigPrivPtr) xcalloc(sizeof(I810ConfigPrivRec), + numConfigs); + if (!pI810Configs) { + xfree(pConfigs); + return FALSE; + } + + pI810ConfigPtrs = + (I810ConfigPrivPtr *) xcalloc(sizeof(I810ConfigPrivPtr), + numConfigs); + if (!pI810ConfigPtrs) { + xfree(pConfigs); + xfree(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].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 = 16; + } 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_VISUAL_EXT; + else + pConfigs[i].visualRating = GLX_NONE_EXT; + pConfigs[i].transparentPixel = 0; + 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; + unsigned long agpHandle; + unsigned long dcacheHandle; + int sysmem_size = 0; + int back_size = 0; + 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("DRIScreenInit")) + 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; + } + + /* Check the DRI version */ + { + int major, minor, patch; + + DRIQueryVersion(&major, &minor, &patch); + if (major != 4 || minor < 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[dri] I810DRIScreenInit failed because of a version mismatch.\n" + "[dri] libDRI version is %d.%d.%d bug version 4.0.x is needed.\n" + "[dri] Disabling DRI.\n", major, minor, patch); + 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; + pDRIInfo->busIdString = xalloc(64); + + sprintf(pDRIInfo->busIdString, "PCI:%d:%d:%d", + ((pciConfigPtr) pI810->PciInfo->thisCard)->busnum, + ((pciConfigPtr) pI810->PciInfo->thisCard)->devnum, + ((pciConfigPtr) pI810->PciInfo->thisCard)->funcnum); + pDRIInfo->ddxDriverMajorVersion = I810_MAJOR_VERSION; + pDRIInfo->ddxDriverMinorVersion = I810_MINOR_VERSION; + pDRIInfo->ddxDriverPatchVersion = I810_PATCHLEVEL; + pDRIInfo->frameBufferPhysicalAddress = 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) xcalloc(sizeof(I810DRIRec), 1))) { + DRIDestroyInfoRec(pI810->pDRIInfo); + pI810->pDRIInfo = 0; + 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->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"); + xfree(pDRIInfo->devPrivate); + pDRIInfo->devPrivate = 0; + DRIDestroyInfoRec(pI810->pDRIInfo); + pI810->pDRIInfo = 0; + 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) { + 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; + } + drmFreeVersion(version); + } + } + + pI810DRI->regsSize = I810_REG_SIZE; + if (drmAddMap(pI810->drmSubFD, (drmHandle) pI810->MMIOAddr, + pI810DRI->regsSize, DRM_REGISTERS, 0, &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%08lx\n", + pI810DRI->regs); + + pI810->backHandle = 0; + pI810->zHandle = 0; + pI810->cursorHandle = 0; + pI810->xvmcHandle = 0; + pI810->sysmemHandle = 0; + pI810->agpAcquired = FALSE; + pI810->dcacheHandle = 0; + + /* 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; + + /* Dcache - half the speed of normal ram, but has use as a Z buffer + * under the DRI. + */ + + drmAgpAlloc(pI810->drmSubFD, 4096 * 1024, 1, NULL, &dcacheHandle); + pI810->dcacheHandle = dcacheHandle; + xf86DrvMsg(pScreen->myNum, X_INFO, "[agp] dcacheHandle : %p\n", + dcacheHandle); + +#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 { + back_size = i810_pitches[pitch_idx] * (pScrn->virtualY + 4); + back_size = ((back_size + 4096 - 1) / 4096) * 4096; + } + + sysmem_size = pScrn->videoRam * 1024; + if (dcacheHandle != 0) { + 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 = 0; + } 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 */ + + pI810->SysMem.Start = 0; + pI810->SysMem.Size = sysmem_size; + pI810->SysMem.End = sysmem_size; + tom = sysmem_size; + + pI810->SavedSysMem = pI810->SysMem; + + if (dcacheHandle != 0) { + 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 = 0; + } + } else { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "[agp] GART: no dcache memory found\n"); + } + + drmAgpAlloc(pI810->drmSubFD, back_size, 0, NULL, &agpHandle); + pI810->backHandle = agpHandle; + + if (agpHandle != 0) { + 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 == 0) { + drmAgpAlloc(pI810->drmSubFD, back_size, 0, NULL, &agpHandle); + pI810->zHandle = agpHandle; + + if (agpHandle != 0) { + 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, &agpHandle); + if (agpHandle == 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, "[agp] drmAgpAlloc failed\n"); + DRICloseScreen(pScreen); + return FALSE; + } + pI810->sysmemHandle = agpHandle; + + if (drmAgpBind(pI810->drmSubFD, agpHandle, 0) != 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, "[agp] drmAgpBind failed\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, &agpHandle); + pI810->xvmcHandle = agpHandle; + + if (agpHandle != 0) { + 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, &agpHandle); + pI810->cursorHandle = agpHandle; + + if (agpHandle != 0) { + 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; + } + + /* 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, (drmHandle) pI810->BackBuffer.Start, + pI810->BackBuffer.Size, DRM_AGP, 0, + &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, (drmHandle) pI810->DepthBuffer.Start, + pI810->DepthBuffer.Size, DRM_AGP, 0, + &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, (drmHandle) pI810->BufferMem.Start, + pI810->BufferMem.Size, DRM_AGP, 0, &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, (drmHandle) pI810->LpRing.mem.Start, + pI810->LpRing.mem.Size, DRM_AGP, 0, &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, (drmHandle) pI810->TexMem.Start, + pI810->TexMem.Size, DRM_AGP, 0, &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, + ((pciConfigPtr) pI810-> + PciInfo->thisCard)->busnum, + ((pciConfigPtr) pI810-> + PciInfo->thisCard)->devnum, + ((pciConfigPtr) pI810-> + PciInfo->thisCard)->funcnum); + 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 = pI810->PciInfo->chipType; + 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); + + I810CleanupDma(pScrn); + + if (pI810->dcacheHandle) + drmAgpFree(pI810->drmSubFD, pI810->dcacheHandle); + if (pI810->backHandle) + drmAgpFree(pI810->drmSubFD, pI810->backHandle); + if (pI810->zHandle) + drmAgpFree(pI810->drmSubFD, pI810->zHandle); + if (pI810->cursorHandle) + drmAgpFree(pI810->drmSubFD, pI810->cursorHandle); + if (pI810->xvmcHandle) + drmAgpFree(pI810->drmSubFD, pI810->xvmcHandle); + if (pI810->sysmemHandle) + drmAgpFree(pI810->drmSubFD, pI810->sysmemHandle); + + if (pI810->agpAcquired == TRUE) + drmAgpRelease(pI810->drmSubFD); + + pI810->backHandle = 0; + pI810->zHandle = 0; + pI810->cursorHandle = 0; + pI810->xvmcHandle = 0; + pI810->sysmemHandle = 0; + pI810->agpAcquired = FALSE; + pI810->dcacheHandle = 0; + + DRICloseScreen(pScreen); + + if (pI810->pDRIInfo) { + if (pI810->pDRIInfo->devPrivate) { + xfree(pI810->pDRIInfo->devPrivate); + pI810->pDRIInfo->devPrivate = 0; + } + DRIDestroyInfoRec(pI810->pDRIInfo); + pI810->pDRIInfo = 0; + } + if (pI810->pVisualConfigs) + xfree(pI810->pVisualConfigs); + if (pI810->pVisualConfigsPriv) + xfree(pI810->pVisualConfigsPriv); +} + +static Bool +I810CreateContext(ScreenPtr pScreen, VisualPtr visual, + drmContext hwContext, void *pVisualConfigPriv, + DRIContextType contextStore) +{ + return TRUE; +} + +static void +I810DestroyContext(ScreenPtr pScreen, drmContext hwContext, + DRIContextType contextStore) +{ +} + +Bool +I810DRIFinishScreenInit(ScreenPtr pScreen) +{ + I810SAREARec *sPriv = (I810SAREARec *) DRIGetSAREAPrivate(pScreen); + + memset(sPriv, 0, sizeof(sPriv)); + 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); + 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; + int xdir, ydir; + + int screenwidth = pScrn->virtualX; + int screenheight = pScrn->virtualY; + + BoxPtr pbox = REGION_RECTS(prgnSrc); + int nbox = REGION_NUM_RECTS(prgnSrc); + + BoxPtr pboxNew1 = 0; + BoxPtr pboxNew2 = 0; + DDXPointPtr pptNew1 = 0; + 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) 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 orderof rects in each band */ + pboxNew2 = (BoxPtr) ALLOCATE_LOCAL(sizeof(BoxRec) * nbox); + pptNew2 = (DDXPointPtr) ALLOCATE_LOCAL(sizeof(DDXPointRec) * nbox); + if (!pboxNew2 || !pptNew2) { + if (pptNew2) + DEALLOCATE_LOCAL(pptNew2); + if (pboxNew2) + DEALLOCATE_LOCAL(pboxNew2); + if (pboxNew1) { + 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; + } + + /* 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) { + DEALLOCATE_LOCAL(pptNew2); + DEALLOCATE_LOCAL(pboxNew2); + } + if (pboxNew1) { + DEALLOCATE_LOCAL(pptNew1); + DEALLOCATE_LOCAL(pboxNew1); + } + + pI810->AccelInfoRec->NeedToSync = TRUE; +} |