| /* |
| * 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 <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <errno.h> |
| #include <unistd.h> |
| |
| #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 |
| }; |