📄 savagetex.c
字号:
/* * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved. * Copyright 2001-2003 S3 Graphics, Inc. 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, sub license, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the * next paragraph) shall be included in all copies or substantial portions * of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL * VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS 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. */#include <stdlib.h>#include <stdio.h>#include <GL/gl.h>#include "mm.h"#include "savagecontext.h"#include "savagetex.h"#include "savagetris.h"#include "savageioctl.h"#include "simple_list.h"#include "enums.h"#include "savage_bci.h"#include "macros.h"#include "texformat.h"#include "texstore.h"#include "texobj.h"#include "convolve.h"#include "colormac.h"#include "swrast/swrast.h"#include "xmlpool.h"#define TILE_INDEX_DXT1 0#define TILE_INDEX_8 1#define TILE_INDEX_16 2#define TILE_INDEX_DXTn 3#define TILE_INDEX_32 4/* On Savage4 the texure LOD-bias needs an offset of ~ 0.3 to get * somewhere close to software rendering. */#define SAVAGE4_LOD_OFFSET 10/* Tile info for S3TC formats counts in 4x4 blocks instead of texels. * In DXT1 each block is encoded in 64 bits. In DXT3 and 5 each block is * encoded in 128 bits. *//* Size 1, 2 and 4 images are packed into the last subtile. Each image * is repeated to fill a 4x4 pixel area. The figure below shows the * layout of those 4x4 pixel areas in the 8x8 subtile. * * 4 2 * x 1 * * Yuck! 8-bit texture formats use 4x8 subtiles. See below. */static const savageTileInfo tileInfo_pro[5] = { {16, 16, 16, 8, 1, 2, {0x18, 0x10}}, /* DXT1 */ {64, 32, 16, 4, 4, 8, {0x30, 0x20}}, /* 8-bit */ {64, 16, 8, 2, 8, 8, {0x48, 0x08}}, /* 16-bit */ {16, 8, 16, 4, 1, 2, {0x30, 0x20}}, /* DXT3, DXT5 */ {32, 16, 4, 2, 8, 8, {0x90, 0x10}}, /* 32-bit */};/* Size 1, 2 and 4 images are packed into the last two subtiles. Each * image is repeated to fill a 4x4 pixel area. The figures below show * the layout of those 4x4 pixel areas in the two 4x8 subtiles. * * second last subtile: 4 last subtile: 2 * x 1 */static const savageTileInfo tileInfo_s3d_s4[5] = { {16, 16, 16, 8, 1, 2, {0x18, 0x10}}, /* DXT1 */ {64, 32, 16, 4, 4, 8, {0x30, 0x20}}, /* 8-bit */ {64, 16, 16, 2, 4, 8, {0x60, 0x40}}, /* 16-bit */ {16, 8, 16, 4, 1, 2, {0x30, 0x20}}, /* DXT3, DXT5 */ {32, 16, 8, 2, 4, 8, {0xc0, 0x80}}, /* 32-bit */};/** \brief Template for subtile uploads. * \param h height in pixels * \param w width in bytes */#define SUBTILE_FUNC(w,h) \static INLINE GLubyte *savageUploadSubtile_##w##x##h \(GLubyte *dest, GLubyte *src, GLuint srcStride) \{ \ GLuint y; \ for (y = 0; y < h; ++y) { \ memcpy (dest, src, w); \ src += srcStride; \ dest += w; \ } \ return dest; \}SUBTILE_FUNC(2, 8) /* 4 bits per pixel, 4 pixels wide */SUBTILE_FUNC(4, 8)SUBTILE_FUNC(8, 8)SUBTILE_FUNC(16, 8)SUBTILE_FUNC(32, 8) /* 4 bytes per pixel, 8 pixels wide */SUBTILE_FUNC(8, 2) /* DXT1 */SUBTILE_FUNC(16, 2) /* DXT3 and DXT5 *//** \brief Upload a complete tile from src (srcStride) to dest * * \param tileInfo Pointer to tiling information * \param wInSub Width of source/dest image in subtiles * \param hInSub Height of source/dest image in subtiles * \param bpp Bytes per pixel * \param src Pointer to source data * \param srcStride Byte stride of rows in the source data * \param dest Pointer to destination * * Writes linearly to the destination memory in order to exploit write * combining. * * For a complete tile wInSub and hInSub are set to the same values as * in tileInfo. If the source image is smaller than a whole tile in * one or both dimensions then they are set to the values of the * source image. This only works as long as the source image is bigger * than 8x8 pixels. */static void savageUploadTile (const savageTileInfo *tileInfo, GLuint wInSub, GLuint hInSub, GLuint bpp, GLubyte *src, GLuint srcStride, GLubyte *dest) { GLuint subStride = tileInfo->subWidth * bpp; GLubyte *srcSRow = src, *srcSTile = src; GLubyte *(*subtileFunc) (GLubyte *, GLubyte *, GLuint); GLuint sx, sy; switch (subStride) { case 2: subtileFunc = savageUploadSubtile_2x8; break; case 4: subtileFunc = savageUploadSubtile_4x8; break; case 8: subtileFunc = tileInfo->subHeight == 8 ? savageUploadSubtile_8x8 : savageUploadSubtile_8x2; break; case 16: subtileFunc = tileInfo->subHeight == 8 ? savageUploadSubtile_16x8 : savageUploadSubtile_16x2; break; case 32: subtileFunc = savageUploadSubtile_32x8; break; default: assert(0); } for (sy = 0; sy < hInSub; ++sy) { srcSTile = srcSRow; for (sx = 0; sx < wInSub; ++sx) { src = srcSTile; dest = subtileFunc (dest, src, srcStride); srcSTile += subStride; } srcSRow += srcStride * tileInfo->subHeight; }}/** \brief Upload a image that is smaller than 8 pixels in either dimension. * * \param tileInfo Pointer to tiling information * \param width Width of the image * \param height Height of the image * \param bpp Bytes per pixel * \param src Pointer to source data * \param dest Pointer to destination * * This function handles all the special cases that need to be taken * care off. The caller may need to call this function multiple times * with the destination offset in different ways since small texture * images must be repeated in order to fill a whole tile (or 4x4 for * the last 3 levels). * * FIXME: Repeating inside this function would be more efficient. */static void savageUploadTiny (const savageTileInfo *tileInfo, GLuint pixWidth, GLuint pixHeight, GLuint width, GLuint height, GLuint bpp, GLubyte *src, GLubyte *dest) { GLuint size = MAX2(pixWidth, pixHeight); if (width > tileInfo->subWidth) { /* assert: height <= subtile height */ GLuint wInSub = width / tileInfo->subWidth; GLuint srcStride = width * bpp; GLuint subStride = tileInfo->subWidth * bpp; GLuint subSkip = (tileInfo->subHeight - height) * subStride; GLubyte *srcSTile = src; GLuint sx, y; for (sx = 0; sx < wInSub; ++sx) { src = srcSTile; for (y = 0; y < height; ++y) { memcpy (dest, src, subStride); src += srcStride; dest += subStride; } dest += subSkip; srcSTile += subStride; } } else if (size > 4) { /* a tile or less wide, except the last 3 levels */ GLuint srcStride = width * bpp; GLuint subStride = tileInfo->subWidth * bpp; /* if the subtile width is 4 we have to skip every other subtile */ GLuint subSkip = tileInfo->subWidth <= 4 ? subStride * tileInfo->subHeight : 0; GLuint skipRemainder = tileInfo->subHeight - 1; GLuint y; for (y = 0; y < height; ++y) { memcpy (dest, src, srcStride); src += srcStride; dest += subStride; if ((y & skipRemainder) == skipRemainder) dest += subSkip; } } else { /* the last 3 mipmap levels */ GLuint offset = (size <= 2 ? tileInfo->tinyOffset[size-1] : 0); GLuint subStride = tileInfo->subWidth * bpp; GLuint y; dest += offset; for (y = 0; y < height; ++y) { memcpy (dest, src, bpp*width); src += width * bpp; dest += subStride; } }}/** \brief Upload an image from mesa's internal copy. */static void savageUploadTexLevel( savageTexObjPtr t, int level ){ const struct gl_texture_image *image = t->base.tObj->Image[0][level]; const savageTileInfo *tileInfo = t->tileInfo; GLuint pixWidth = image->Width2, pixHeight = image->Height2; GLuint bpp = t->texelBytes; GLuint width, height; /* FIXME: Need triangle (rather than pixel) fallbacks to simulate * this using normal textured triangles. * * DO THIS IN DRIVER STATE MANAGMENT, not hardware state. */ if(image->Border != 0) fprintf (stderr, "Not supported texture border %d.\n", (int) image->Border); if (t->hwFormat == TFT_S3TC4A4Bit || t->hwFormat == TFT_S3TC4CA4Bit || t->hwFormat == TFT_S3TC4Bit) { width = (pixWidth+3) / 4; height = (pixHeight+3) / 4; } else { width = pixWidth; height = pixHeight; } if (pixWidth >= 8 && pixHeight >= 8) { GLuint *dirtyPtr = t->image[level].dirtyTiles; GLuint dirtyMask = 1; if (width >= tileInfo->width && height >= tileInfo->height) { GLuint wInTiles = width / tileInfo->width; GLuint hInTiles = height / tileInfo->height; GLubyte *srcTRow = image->Data, *src; GLubyte *dest = (GLubyte *)(t->bufAddr + t->image[level].offset); GLuint x, y; for (y = 0; y < hInTiles; ++y) { src = srcTRow; for (x = 0; x < wInTiles; ++x) { if (*dirtyPtr & dirtyMask) { savageUploadTile (tileInfo, tileInfo->wInSub, tileInfo->hInSub, bpp, src, width * bpp, dest); } src += tileInfo->width * bpp; dest += 2048; /* tile size is always 2k */ if (dirtyMask == 1<<31) { dirtyMask = 1; dirtyPtr++; } else dirtyMask <<= 1; } srcTRow += width * tileInfo->height * bpp; } } else if (width >= tileInfo->width) { GLuint wInTiles = width / tileInfo->width; GLubyte *src = image->Data; GLubyte *dest = (GLubyte *)(t->bufAddr + t->image[level].offset); GLuint tileStride = tileInfo->width * bpp * height; savageContextPtr imesa = (savageContextPtr)t->base.heap->driverContext; GLuint x; /* Savage3D-based chips seem so use a constant tile stride * of 2048 for vertically incomplete tiles, but only if * the color depth is 32bpp. Nobody said this was supposed * to be logical! */ if (bpp == 4 && imesa->savageScreen->chipset < S3_SAVAGE4) tileStride = 2048; for (x = 0; x < wInTiles; ++x) { if (*dirtyPtr & dirtyMask) { savageUploadTile (tileInfo, tileInfo->wInSub, height / tileInfo->subHeight, bpp, src, width * bpp, dest); } src += tileInfo->width * bpp; dest += tileStride; if (dirtyMask == 1<<31) { dirtyMask = 1; dirtyPtr++; } else dirtyMask <<= 1; } } else { savageUploadTile (tileInfo, width / tileInfo->subWidth, height / tileInfo->subHeight, bpp, image->Data, width * bpp, (GLubyte *)(t->bufAddr+t->image[level].offset)); } } else { GLuint minHeight, minWidth, hRepeat, vRepeat, x, y; if (t->hwFormat == TFT_S3TC4A4Bit || t->hwFormat == TFT_S3TC4CA4Bit || t->hwFormat == TFT_S3TC4Bit) minWidth = minHeight = 1; else minWidth = minHeight = 4; if (width > minWidth || height > minHeight) { minWidth = tileInfo->subWidth; minHeight = tileInfo->subHeight; } hRepeat = width >= minWidth ? 1 : minWidth / width; vRepeat = height >= minHeight ? 1 : minHeight / height; for (y = 0; y < vRepeat; ++y) { GLuint offset = y * tileInfo->subWidth*height * bpp; for (x = 0; x < hRepeat; ++x) { savageUploadTiny (tileInfo, pixWidth, pixHeight, width, height, bpp, image->Data, (GLubyte *)(t->bufAddr + t->image[level].offset+offset)); offset += width * bpp; } } }}/** \brief Compute the destination size of a texture image */static GLuint savageTexImageSize (GLuint width, GLuint height, GLuint bpp) { /* full subtiles */ if (width >= 8 && height >= 8) return width * height * bpp; /* special case for the last three mipmap levels: the hardware computes * the offset internally */ else if (width <= 4 && height <= 4) return 0; /* partially filled sub tiles waste memory * on Savage3D and Savage4 with subtile width 4 every other subtile is * skipped if width < 8 so we can assume a uniform subtile width of 8 */ else if (width >= 8) return width * 8 * bpp; else if (height >= 8) return 8 * height * bpp; else return 64 * bpp;}/** \brief Compute the destination size of a compressed texture image */static GLuint savageCompressedTexImageSize (GLuint width, GLuint height, GLuint bpp) { width = (width+3) / 4; height = (height+3) / 4; /* full subtiles */ if (width >= 2 && height >= 2) return width * height * bpp; /* special case for the last three mipmap levels: the hardware computes * the offset internally */ else if (width <= 1 && height <= 1) return 0; /* partially filled sub tiles waste memory * on Savage3D and Savage4 with subtile width 4 every other subtile is * skipped if width < 8 so we can assume a uniform subtile width of 8 */ else if (width >= 2) return width * 2 * bpp; else if (height >= 2) return 2 * height * bpp; else return 4 * bpp;}/** \brief Compute the number of (partial) tiles of a texture image */static GLuint savageTexImageTiles (GLuint width, GLuint height, const savageTileInfo *tileInfo){ return (width + tileInfo->width - 1) / tileInfo->width * (height + tileInfo->height - 1) / tileInfo->height;}/** \brief Mark dirty tiles * * Some care must be taken because tileInfo may not be set or not * up-to-date. So we check if tileInfo is initialized and if the number * of tiles in the bit vector matches the number of tiles computed from
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -