/* * Mesa 3-D graphics library * Version: 5.1 * * Copyright (C) 1999-2003 Brian Paul 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 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 * BRIAN PAUL 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: * Keith Whitwell * Daniel Borca */ #include #include #include #include #include #include "driver.h" #include "drm.h" #include "imports.h" #include "dri_util.h" #include "tdfx_context.h" #include "tdfx_dri.h" #include "xf86drm.h" #define TILE_WIDTH 128 #define TILE_HEIGHT 32 #define CMDFIFO_PAGES 64 static int calcBufferStride (int xres, int tiled, int cpp) { int strideInTiles; if (tiled) { /* Calculate tile width stuff */ strideInTiles = (xres+TILE_WIDTH-1)/TILE_WIDTH; return strideInTiles*cpp*TILE_WIDTH; } else { return xres*cpp; } } /* calcBufferStride */ static int calcBufferHeightInTiles (int yres) { int heightInTiles; /* Height of buffer in tiles */ /* Calculate tile height stuff */ heightInTiles = yres >> 5; if (yres & (TILE_HEIGHT - 1)) heightInTiles++; return heightInTiles; } /* calcBufferHeightInTiles */ static int calcBufferSize (int xres, int yres, int tiled, int cpp) { int stride, height, bufSize; if (tiled) { stride = calcBufferStride(xres, tiled, cpp); height = TILE_HEIGHT * calcBufferHeightInTiles(yres); } else { stride = xres*cpp; height = yres; } bufSize = stride * height; return bufSize; } /* calcBufferSize */ static void allocateMemory (const DRIDriverContext *ctx, TDFXDRIPtr pTDFX) { int memRemaining, fifoSize, screenSizeInTiles; int fbSize; char *str; int pixmapCacheLinesMin; int cursorOffset, cursorSize; pTDFX->stride = calcBufferStride(pTDFX->width, !0, pTDFX->cpp); /* enough to do DVD */ pixmapCacheLinesMin = ((720*480*pTDFX->cpp) + pTDFX->stride - 1)/pTDFX->stride; if (pTDFX->deviceID > PCI_CHIP_VOODOO3) { if ((pixmapCacheLinesMin + pTDFX->height) > 4095) pixmapCacheLinesMin = 4095 - pTDFX->height; } else { if ((pixmapCacheLinesMin + pTDFX->height) > 2047) pixmapCacheLinesMin = 2047 - pTDFX->height; } if (pTDFX->cpp!=3) { screenSizeInTiles=calcBufferSize(pTDFX->width, pTDFX->height, !0, pTDFX->cpp); } else { /* cpp==3 needs to bump up to 4 */ screenSizeInTiles=calcBufferSize(pTDFX->width, pTDFX->height, !0, 4); } /* * Layout is: * cursor, fifo, fb, tex, bb, db */ fbSize = (pTDFX->height + pixmapCacheLinesMin) * pTDFX->stride; memRemaining=(pTDFX->mem - 1) &~ 0xFFF; /* Note that a page is 4096 bytes, and a */ /* tile is 32 x 128 = 4096 bytes. So, */ /* page and tile boundaries are the same */ /* Place the depth offset first, forcing */ /* it to be on an *odd* page boundary. */ pTDFX->depthOffset = (memRemaining - screenSizeInTiles) &~ 0xFFF; if ((pTDFX->depthOffset & (0x1 << 12)) == 0) { pTDFX->depthOffset -= (0x1 << 12); } /* Now, place the back buffer, forcing it */ /* to be on an *even* page boundary. */ pTDFX->backOffset = (pTDFX->depthOffset - screenSizeInTiles) &~ 0xFFF; if (pTDFX->backOffset & (0x1 << 12)) { pTDFX->backOffset -= (0x1 << 12); } /* Give the cmd fifo at least */ /* CMDFIFO_PAGES pages, but no more than */ /* 64. NOTE: Don't go higher than 64, as */ /* there is suspect code in Glide3 ! */ fifoSize = ((64 <= CMDFIFO_PAGES) ? 64 : CMDFIFO_PAGES) << 12; /* We give 4096 bytes to the cursor */ cursorSize = 0/*4096*/; cursorOffset = 0; pTDFX->fifoOffset = cursorOffset + cursorSize; pTDFX->fifoSize = fifoSize; /* Now, place the front buffer, forcing */ /* it to be on a page boundary too, just */ /* for giggles. */ pTDFX->fbOffset = pTDFX->fifoOffset + pTDFX->fifoSize; pTDFX->textureOffset = pTDFX->fbOffset + fbSize; if (pTDFX->depthOffset <= pTDFX->textureOffset || pTDFX->backOffset <= pTDFX->textureOffset) { /* * pTDFX->textureSize < 0 means that the DRI is disabled. pTDFX->backOffset * is used to calculate the maximum amount of memory available for * 2D offscreen use. With DRI disabled, set this to the top of memory. */ pTDFX->textureSize = -1; pTDFX->backOffset = pTDFX->mem; pTDFX->depthOffset = -1; fprintf(stderr, "Not enough video memory available for textures and depth buffer\n" "\tand/or back buffer. Disabling DRI. To use DRI try lower\n" "\tresolution modes and/or a smaller virtual screen size\n"); } else { pTDFX->textureSize = pTDFX->backOffset - pTDFX->textureOffset; } } static int createScreen (DRIDriverContext *ctx, TDFXDRIPtr pTDFX) { int err; { int width_bytes = (ctx->shared.virtualWidth * ctx->cpp); int maxy = ctx->shared.fbSize / width_bytes; if (maxy <= ctx->shared.virtualHeight * 3) { fprintf(stderr, "Static buffer allocation failed -- " "need at least %d kB video memory (have %d kB)\n", (ctx->shared.virtualWidth * ctx->shared.virtualHeight * ctx->cpp * 3 + 1023) / 1024, ctx->shared.fbSize / 1024); return 0; } } ctx->shared.SAREASize = SAREA_MAX; pTDFX->regsSize = ctx->MMIOSize; /* Note that drmOpen will try to load the kernel module, if needed. */ ctx->drmFD = drmOpen("tdfx", NULL ); if (ctx->drmFD < 0) { fprintf(stderr, "[drm] drmOpen failed\n"); return 0; } if ((err = drmSetBusid(ctx->drmFD, ctx->pciBusID)) < 0) { fprintf(stderr, "[drm] drmSetBusid failed (%d, %s), %s\n", ctx->drmFD, ctx->pciBusID, strerror(-err)); return 0; } if (drmAddMap( ctx->drmFD, 0, ctx->shared.SAREASize, DRM_SHM, DRM_CONTAINS_LOCK, &ctx->shared.hSAREA) < 0) { fprintf(stderr, "[drm] drmAddMap failed\n"); return 0; } fprintf(stderr, "[drm] added %d byte SAREA at 0x%08lx\n", ctx->shared.SAREASize, ctx->shared.hSAREA); if (drmMap( ctx->drmFD, ctx->shared.hSAREA, ctx->shared.SAREASize, (drmAddressPtr)(&ctx->pSAREA)) < 0) { fprintf(stderr, "[drm] drmMap failed\n"); return 0; } memset(ctx->pSAREA, 0, ctx->shared.SAREASize); fprintf(stderr, "[drm] mapped SAREA 0x%08lx to %p, size %d\n", ctx->shared.hSAREA, ctx->pSAREA, ctx->shared.SAREASize); /* Need to AddMap the framebuffer and mmio regions here: */ if (drmAddMap( ctx->drmFD, (drm_handle_t)ctx->FBStart, ctx->FBSize, DRM_FRAME_BUFFER, #ifndef _EMBEDDED 0, #else DRM_READ_ONLY, #endif &ctx->shared.hFrameBuffer) < 0) { fprintf(stderr, "[drm] drmAddMap framebuffer failed\n"); return 0; } fprintf(stderr, "[drm] framebuffer handle = 0x%08lx\n", ctx->shared.hFrameBuffer); if (drmAddMap(ctx->drmFD, ctx->MMIOStart, ctx->MMIOSize, DRM_REGISTERS, DRM_READ_ONLY, &pTDFX->regs) < 0) { fprintf(stderr, "[drm] drmAddMap mmio failed\n"); return 0; } fprintf(stderr, "[drm] register handle = 0x%08lx\n", pTDFX->regs); /* Create a 'server' context so we can grab the lock for * initialization ioctls. */ if ((err = drmCreateContext(ctx->drmFD, &ctx->serverContext)) != 0) { fprintf(stderr, "%s: drmCreateContext failed %d\n", __FUNCTION__, err); return 0; } DRM_LOCK(ctx->drmFD, ctx->pSAREA, ctx->serverContext, 0); /* Initialize the kernel data structures */ /* Initialize kernel gart memory manager */ allocateMemory(ctx, pTDFX); /* Initialize the SAREA private data structure */ /* Quick hack to clear the front & back buffers. Could also use * the clear ioctl to do this, but would need to setup hw state * first. */ /* This is the struct passed to tdfx_dri.so for its initialization */ ctx->driverClientMsg = malloc(sizeof(TDFXDRIRec)); ctx->driverClientMsgSize = sizeof(TDFXDRIRec); memcpy(ctx->driverClientMsg, pTDFX, ctx->driverClientMsgSize); pTDFX = (TDFXDRIPtr)ctx->driverClientMsg; /* Don't release the lock now - let the VT switch handler do it. */ return 1; } /** * \brief Validate the fbdev mode. * * \param ctx display handle. * * \return one on success, or zero on failure. * * Saves some registers and returns 1. * * \sa tdfxValidateMode(). */ static int tdfxValidateMode( const DRIDriverContext *ctx ) { return 1; } /** * \brief Examine mode returned by fbdev. * * \param ctx display handle. * * \return one on success, or zero on failure. * * Restores registers that fbdev has clobbered and returns 1. * * \sa tdfxValidateMode(). */ static int tdfxPostValidateMode( const DRIDriverContext *ctx ) { return 1; } /** * \brief Initialize the framebuffer device mode * * \param ctx display handle. * * \return one on success, or zero on failure. * * Before exiting clears the framebuffer memory accessing it directly. */ static int tdfxInitFBDev( DRIDriverContext *ctx ) { TDFXDRIPtr pTDFX = calloc(1, sizeof(TDFXDRIRec)); { int dummy = ctx->shared.virtualWidth; switch (ctx->bpp / 8) { case 1: dummy = (ctx->shared.virtualWidth + 127) & ~127; break; case 2: dummy = (ctx->shared.virtualWidth + 31) & ~31; break; case 3: case 4: dummy = (ctx->shared.virtualWidth + 15) & ~15; break; } ctx->shared.virtualWidth = dummy; } ctx->driverPrivate = (void *)pTDFX; pTDFX->deviceID = ctx->chipset; pTDFX->width = ctx->shared.virtualWidth; pTDFX->height = ctx->shared.virtualHeight; pTDFX->cpp = ctx->cpp; pTDFX->mem = ctx->FBSize; /* ->shared.fbSize? mem probe? */ pTDFX->sarea_priv_offset = sizeof(drm_sarea_t); if (!createScreen(ctx, pTDFX)) return 0; return 1; } /** * \brief The screen is being closed, so clean up any state and free any * resources used by the DRI. * * \param ctx display handle. * * Unmaps the SAREA, closes the DRM device file descriptor and frees the driver * private data. */ static void tdfxHaltFBDev( DRIDriverContext *ctx ) { drmUnmap( ctx->pSAREA, ctx->shared.SAREASize ); drmClose(ctx->drmFD); if (ctx->driverPrivate) { free(ctx->driverPrivate); ctx->driverPrivate = 0; } } /** * \brief Shutdown the drawing engine. * * \param ctx display handle * * Turns off the 3D engine & restores the graphics card * to a state that fbdev understands. */ static int tdfxEngineShutdown( const DRIDriverContext *ctx ) { fprintf(stderr, "%s: not implemented\n", __FUNCTION__); return 1; } /** * \brief Restore the drawing engine. * * \param ctx display handle * * Resets the graphics card and sets initial values for several registers of * the card's drawing engine. * * Turns on 3dfx */ static int tdfxEngineRestore( const DRIDriverContext *ctx ) { fprintf(stderr, "%s: not implemented\n", __FUNCTION__); return 1; } /** * \brief Exported driver interface for Mini GLX. * * \sa DRIDriverRec. */ struct DRIDriverRec __driDriver = { tdfxValidateMode, tdfxPostValidateMode, tdfxInitFBDev, tdfxHaltFBDev, tdfxEngineShutdown, tdfxEngineRestore, 0 };