diff options
Diffstat (limited to 'src/mesa/drivers/dri/savage/savagetex.c')
-rw-r--r-- | src/mesa/drivers/dri/savage/savagetex.c | 2135 |
1 files changed, 2135 insertions, 0 deletions
diff --git a/src/mesa/drivers/dri/savage/savagetex.c b/src/mesa/drivers/dri/savage/savagetex.c new file mode 100644 index 00000000000..b2802904bda --- /dev/null +++ b/src/mesa/drivers/dri/savage/savagetex.c @@ -0,0 +1,2135 @@ +/* + * 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 + * the current tileInfo. + */ +static void savageMarkDirtyTiles (savageTexObjPtr t, GLuint level, + GLuint totalWidth, GLuint totalHeight, + GLint xoffset, GLint yoffset, + GLsizei width, GLsizei height) +{ + GLuint wInTiles, hInTiles; + GLuint x0, y0, x1, y1; + GLuint x, y; + if (!t->tileInfo) + return; + wInTiles = (totalWidth + t->tileInfo->width - 1) / t->tileInfo->width; + hInTiles = (totalHeight + t->tileInfo->height - 1) / t->tileInfo->height; + if (wInTiles * hInTiles != t->image[level].nTiles) + return; + + x0 = xoffset / t->tileInfo->width; + y0 = yoffset / t->tileInfo->height; + x1 = (xoffset + width - 1) / t->tileInfo->width; + y1 = (yoffset + height - 1) / t->tileInfo->height; + + for (y = y0; y <= y1; ++y) { + GLuint *ptr = t->image[level].dirtyTiles + (y * wInTiles + x0) / 32; + GLuint mask = 1 << (y * wInTiles + x0) % 32; + for (x = x0; x <= x1; ++x) { + *ptr |= mask; + if (mask == (1<<31)) { + ptr++; + mask = 1; + } else { + mask <<= 1; + } + } + } +} + +/** \brief Mark all tiles as dirty + */ +static void savageMarkAllTiles (savageTexObjPtr t, GLuint level) +{ + GLuint words = (t->image[level].nTiles + 31) / 32; + if (words) + memset(t->image[level].dirtyTiles, ~0, words*sizeof(GLuint)); +} + + +static void savageSetTexWrapping(savageTexObjPtr tex, GLenum s, GLenum t) +{ + tex->setup.sWrapMode = s; + tex->setup.tWrapMode = t; +} + +static void savageSetTexFilter(savageTexObjPtr t, GLenum minf, GLenum magf) +{ + t->setup.minFilter = minf; + t->setup.magFilter = magf; +} + + +/* Need a fallback ? + */ +static void savageSetTexBorderColor(savageTexObjPtr t, GLubyte color[4]) +{ +/* t->Setup[SAVAGE_TEXREG_TEXBORDERCOL] = */ + /*t->setup.borderColor = SAVAGEPACKCOLOR8888(color[0],color[1],color[2],color[3]); */ +} + + + +static savageTexObjPtr +savageAllocTexObj( struct gl_texture_object *texObj ) +{ + savageTexObjPtr t; + + t = (savageTexObjPtr) calloc(1,sizeof(*t)); + texObj->DriverData = t; + if ( t != NULL ) { + GLuint i; + + /* Initialize non-image-dependent parts of the state: + */ + t->base.tObj = texObj; + t->base.dirty_images[0] = 0; + t->dirtySubImages = 0; + t->tileInfo = NULL; + + /* Initialize dirty tiles bit vectors + */ + for (i = 0; i < SAVAGE_TEX_MAXLEVELS; ++i) + t->image[i].nTiles = 0; + + /* FIXME Something here to set initial values for other parts of + * FIXME t->setup? + */ + + make_empty_list( &t->base ); + + savageSetTexWrapping(t,texObj->WrapS,texObj->WrapT); + savageSetTexFilter(t,texObj->MinFilter,texObj->MagFilter); + savageSetTexBorderColor(t,texObj->_BorderChan); + } + + return t; +} + +/* Mesa texture formats for alpha-images on Savage3D/IX/MX + * + * Promoting texture images to ARGB888 or ARGB4444 doesn't work + * because we can't tell the hardware to ignore the color components + * and only use the alpha component. So we define our own texture + * formats that promote to ARGB8888 or ARGB4444 and set the color + * components to white. This way we get the correct result. */ +static GLboolean +_savage_texstore_a1114444 (GLcontext *ctx, GLuint dims, + GLenum baseInternalFormat, + const struct gl_texture_format *dstFormat, + GLvoid *dstAddr, + GLint dstXoffset, GLint dstYoffset, GLint dstZoffset, + GLint dstRowStride, GLint dstImageStride, + GLint srcWidth, GLint srcHeight, GLint srcDepth, + GLenum srcFormat, GLenum srcType, + const GLvoid *srcAddr, + const struct gl_pixelstore_attrib *srcPacking); +static GLboolean +_savage_texstore_a1118888 (GLcontext *ctx, GLuint dims, + GLenum baseInternalFormat, + const struct gl_texture_format *dstFormat, + GLvoid *dstAddr, + GLint dstXoffset, GLint dstYoffset, GLint dstZoffset, + GLint dstRowStride, GLint dstImageStride, + GLint srcWidth, GLint srcHeight, GLint srcDepth, + GLenum srcFormat, GLenum srcType, + const GLvoid *srcAddr, + const struct gl_pixelstore_attrib *srcPacking); + +static struct gl_texture_format _savage_texformat_a1114444 = { + MESA_FORMAT_ARGB4444, /* MesaFormat */ + GL_RGBA, /* BaseFormat */ + GL_UNSIGNED_NORMALIZED_ARB, /* DataType */ + 4, /* RedBits */ + 4, /* GreenBits */ + 4, /* BlueBits */ + 4, /* AlphaBits */ + 0, /* LuminanceBits */ + 0, /* IntensityBits */ + 0, /* IndexBits */ + 0, /* DepthBits */ + 0, /* StencilBits */ + 2, /* TexelBytes */ + _savage_texstore_a1114444, /* StoreTexImageFunc */ + NULL, NULL, NULL, NULL, NULL, NULL /* FetchTexel* filled in by + * savageDDInitTextureFuncs */ +}; +static struct gl_texture_format _savage_texformat_a1118888 = { + MESA_FORMAT_ARGB8888, /* MesaFormat */ + GL_RGBA, /* BaseFormat */ + GL_UNSIGNED_NORMALIZED_ARB, /* DataType */ + 8, /* RedBits */ + 8, /* GreenBits */ + 8, /* BlueBits */ + 8, /* AlphaBits */ + 0, /* LuminanceBits */ + 0, /* IntensityBits */ + 0, /* IndexBits */ + 0, /* DepthBits */ + 0, /* StencilBits */ + 4, /* TexelBytes */ + _savage_texstore_a1118888, /* StoreTexImageFunc */ + NULL, NULL, NULL, NULL, NULL, NULL /* FetchTexel* filled in by + * savageDDInitTextureFuncs */ +}; + +static GLboolean +_savage_texstore_a1114444 (GLcontext *ctx, GLuint dims, + GLenum baseInternalFormat, + const struct gl_texture_format *dstFormat, + GLvoid *dstAddr, + GLint dstXoffset, GLint dstYoffset, GLint dstZoffset, + GLint dstRowStride, GLint dstImageStride, + GLint srcWidth, GLint srcHeight, GLint srcDepth, + GLenum srcFormat, GLenum srcType, + const GLvoid *srcAddr, + const struct gl_pixelstore_attrib *srcPacking) +{ + /* general path */ + const GLchan *tempImage = _mesa_make_temp_chan_image(ctx, dims, + baseInternalFormat, + baseInternalFormat, + srcWidth, srcHeight, srcDepth, + srcFormat, srcType, srcAddr, + srcPacking); + const GLchan *src = tempImage; + GLubyte *dstImage = (GLubyte *) dstAddr + + dstZoffset * dstImageStride + + dstYoffset * dstRowStride + + dstXoffset * dstFormat->TexelBytes; + GLint img, row, col; + + ASSERT(dstFormat == &_savage_texformat_a1114444); + ASSERT(baseInternalFormat == GL_ALPHA); + + if (!tempImage) + return GL_FALSE; + _mesa_adjust_image_for_convolution(ctx, dims, &srcWidth, &srcHeight); + for (img = 0; img < srcDepth; img++) { + GLubyte *dstRow = dstImage; + for (row = 0; row < srcHeight; row++) { + GLushort *dstUI = (GLushort *) dstRow; + for (col = 0; col < srcWidth; col++) { + dstUI[col] = PACK_COLOR_4444( CHAN_TO_UBYTE(src[0]), + 255, 255, 255 ); + src += 1; + } + dstRow += dstRowStride; + } + dstImage += dstImageStride; + } + _mesa_free((void *) tempImage); + + return GL_TRUE; +} +static GLboolean +_savage_texstore_a1118888 (GLcontext *ctx, GLuint dims, + GLenum baseInternalFormat, + const struct gl_texture_format *dstFormat, + GLvoid *dstAddr, + GLint dstXoffset, GLint dstYoffset, GLint dstZoffset, + GLint dstRowStride, GLint dstImageStride, + GLint srcWidth, GLint srcHeight, GLint srcDepth, + GLenum srcFormat, GLenum srcType, + const GLvoid *srcAddr, + const struct gl_pixelstore_attrib *srcPacking) +{ + /* general path */ + const GLchan *tempImage = _mesa_make_temp_chan_image(ctx, dims, + baseInternalFormat, + baseInternalFormat, + srcWidth, srcHeight, srcDepth, + srcFormat, srcType, srcAddr, + srcPacking); + const GLchan *src = tempImage; + GLubyte *dstImage = (GLubyte *) dstAddr + + dstZoffset * dstImageStride + + dstYoffset * dstRowStride + + dstXoffset * dstFormat->TexelBytes; + GLint img, row, col; + + ASSERT(dstFormat == &_savage_texformat_a1118888); + ASSERT(baseInternalFormat == GL_ALPHA); + + if (!tempImage) + return GL_FALSE; + _mesa_adjust_image_for_convolution(ctx, dims, &srcWidth, &srcHeight); + for (img = 0; img < srcDepth; img++) { + GLubyte *dstRow = dstImage; + for (row = 0; row < srcHeight; row++) { + GLuint *dstUI = (GLuint *) dstRow; + for (col = 0; col < srcWidth; col++) { + dstUI[col] = PACK_COLOR_8888( CHAN_TO_UBYTE(src[0]), + 255, 255, 255 ); + src += 1; + } + dstRow += dstRowStride; + } + dstImage += dstImageStride; + } + _mesa_free((void *) tempImage); + + return GL_TRUE; +} + +/* Called by the _mesa_store_teximage[123]d() functions. */ +static const struct gl_texture_format * +savageChooseTextureFormat( GLcontext *ctx, GLint internalFormat, + GLenum format, GLenum type ) +{ + savageContextPtr imesa = SAVAGE_CONTEXT(ctx); + const GLboolean do32bpt = + ( imesa->texture_depth == DRI_CONF_TEXTURE_DEPTH_32 ); + const GLboolean force16bpt = + ( imesa->texture_depth == DRI_CONF_TEXTURE_DEPTH_FORCE_16 ); + const GLboolean isSavage4 = (imesa->savageScreen->chipset >= S3_SAVAGE4); + (void) format; + + switch ( internalFormat ) { + case 4: + case GL_RGBA: + case GL_COMPRESSED_RGBA: + switch ( type ) { + case GL_UNSIGNED_INT_10_10_10_2: + case GL_UNSIGNED_INT_2_10_10_10_REV: + return do32bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_argb1555; + case GL_UNSIGNED_SHORT_4_4_4_4: + case GL_UNSIGNED_SHORT_4_4_4_4_REV: + return &_mesa_texformat_argb4444; + case GL_UNSIGNED_SHORT_5_5_5_1: + case GL_UNSIGNED_SHORT_1_5_5_5_REV: + return &_mesa_texformat_argb1555; + default: + return do32bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_argb4444; + } + + case 3: + case GL_RGB: + case GL_COMPRESSED_RGB: + switch ( type ) { + case GL_UNSIGNED_SHORT_4_4_4_4: + case GL_UNSIGNED_SHORT_4_4_4_4_REV: + return &_mesa_texformat_argb4444; + case GL_UNSIGNED_SHORT_5_5_5_1: + case GL_UNSIGNED_SHORT_1_5_5_5_REV: + return &_mesa_texformat_argb1555; + case GL_UNSIGNED_SHORT_5_6_5: + case GL_UNSIGNED_SHORT_5_6_5_REV: + return &_mesa_texformat_rgb565; + default: + return do32bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_rgb565; + } + + case GL_RGBA8: + case GL_RGBA12: + case GL_RGBA16: + return !force16bpt ? + &_mesa_texformat_argb8888 : &_mesa_texformat_argb4444; + + case GL_RGB10_A2: + return !force16bpt ? + &_mesa_texformat_argb8888 : &_mesa_texformat_argb1555; + + case GL_RGBA4: + case GL_RGBA2: + return &_mesa_texformat_argb4444; + + case GL_RGB5_A1: + return &_mesa_texformat_argb1555; + + case GL_RGB8: + case GL_RGB10: + case GL_RGB12: + case GL_RGB16: + return !force16bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_rgb565; + + case GL_RGB5: + case GL_RGB4: + case GL_R3_G3_B2: + return &_mesa_texformat_rgb565; + + case GL_ALPHA: + case GL_COMPRESSED_ALPHA: + return isSavage4 ? &_mesa_texformat_a8 : ( + do32bpt ? &_savage_texformat_a1118888 : &_savage_texformat_a1114444); + case GL_ALPHA4: + return isSavage4 ? &_mesa_texformat_a8 : &_savage_texformat_a1114444; + case GL_ALPHA8: + case GL_ALPHA12: + case GL_ALPHA16: + return isSavage4 ? &_mesa_texformat_a8 : ( + !force16bpt ? &_savage_texformat_a1118888 : &_savage_texformat_a1114444); + + case 1: + case GL_LUMINANCE: + case GL_COMPRESSED_LUMINANCE: + /* no alpha, but use argb1555 in 16bit case to get pure grey values */ + return isSavage4 ? &_mesa_texformat_l8 : ( + do32bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_argb1555); + case GL_LUMINANCE4: + return isSavage4 ? &_mesa_texformat_l8 : &_mesa_texformat_argb1555; + case GL_LUMINANCE8: + case GL_LUMINANCE12: + case GL_LUMINANCE16: + return isSavage4 ? &_mesa_texformat_l8 : ( + !force16bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_argb1555); + + case 2: + case GL_LUMINANCE_ALPHA: + case GL_COMPRESSED_LUMINANCE_ALPHA: + /* Savage4 has a al44 texture format. But it's not supported by Mesa. */ + return do32bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_argb4444; + case GL_LUMINANCE4_ALPHA4: + case GL_LUMINANCE6_ALPHA2: + return &_mesa_texformat_argb4444; + case GL_LUMINANCE8_ALPHA8: + case GL_LUMINANCE12_ALPHA4: + case GL_LUMINANCE12_ALPHA12: + case GL_LUMINANCE16_ALPHA16: + return !force16bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_argb4444; +#if 0 + /* TFT_I8 produces garbage on ProSavageDDR and subsequent texture + * disable keeps rendering garbage. Disabled for now. */ + case GL_INTENSITY: + case GL_COMPRESSED_INTENSITY: + return isSavage4 ? &_mesa_texformat_i8 : ( + do32bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_argb4444); + case GL_INTENSITY4: + return isSavage4 ? &_mesa_texformat_i8 : &_mesa_texformat_argb4444; + case GL_INTENSITY8: + case GL_INTENSITY12: + case GL_INTENSITY16: + return isSavage4 ? &_mesa_texformat_i8 : ( + !force16bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_argb4444); +#else + case GL_INTENSITY: + case GL_COMPRESSED_INTENSITY: + return do32bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_argb4444; + case GL_INTENSITY4: + return &_mesa_texformat_argb4444; + case GL_INTENSITY8: + case GL_INTENSITY12: + case GL_INTENSITY16: + return !force16bpt ? &_mesa_texformat_argb8888 : + &_mesa_texformat_argb4444; +#endif + + case GL_RGB_S3TC: + case GL_RGB4_S3TC: + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: + return &_mesa_texformat_rgb_dxt1; + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: + return &_mesa_texformat_rgba_dxt1; + + case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: + return &_mesa_texformat_rgba_dxt3; + + case GL_RGBA_S3TC: + case GL_RGBA4_S3TC: + if (!isSavage4) + /* Not the best choice but Savage3D/MX/IX don't support DXT3 or DXT5. */ + return &_mesa_texformat_rgba_dxt1; + /* fall through */ + case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: + return &_mesa_texformat_rgba_dxt5; + +/* + case GL_COLOR_INDEX: + case GL_COLOR_INDEX1_EXT: + case GL_COLOR_INDEX2_EXT: + case GL_COLOR_INDEX4_EXT: + case GL_COLOR_INDEX8_EXT: + case GL_COLOR_INDEX12_EXT: + case GL_COLOR_INDEX16_EXT: + return &_mesa_texformat_ci8; +*/ + default: + _mesa_problem(ctx, "unexpected texture format in %s", __FUNCTION__); + return NULL; + } +} + +static void savageSetTexImages( savageContextPtr imesa, + const struct gl_texture_object *tObj ) +{ + savageTexObjPtr t = (savageTexObjPtr) tObj->DriverData; + struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel]; + GLuint offset, i, textureFormat, tileIndex, size; + GLint firstLevel, lastLevel; + + assert(t); + assert(image); + + switch (image->TexFormat->MesaFormat) { + case MESA_FORMAT_ARGB8888: + textureFormat = TFT_ARGB8888; + t->texelBytes = tileIndex = 4; + break; + case MESA_FORMAT_ARGB1555: + textureFormat = TFT_ARGB1555; + t->texelBytes = tileIndex = 2; + break; + case MESA_FORMAT_ARGB4444: + textureFormat = TFT_ARGB4444; + t->texelBytes = tileIndex = 2; + break; + case MESA_FORMAT_RGB565: + textureFormat = TFT_RGB565; + t->texelBytes = tileIndex = 2; + break; + case MESA_FORMAT_L8: + textureFormat = TFT_L8; + t->texelBytes = tileIndex = 1; + break; + case MESA_FORMAT_I8: + textureFormat = TFT_I8; + t->texelBytes = tileIndex = 1; + break; + case MESA_FORMAT_A8: + textureFormat = TFT_A8; + t->texelBytes = tileIndex = 1; + break; + case MESA_FORMAT_RGB_DXT1: + textureFormat = TFT_S3TC4Bit; + tileIndex = TILE_INDEX_DXT1; + t->texelBytes = 8; + break; + case MESA_FORMAT_RGBA_DXT1: + textureFormat = TFT_S3TC4Bit; + tileIndex = TILE_INDEX_DXT1; + t->texelBytes = 8; + break; + case MESA_FORMAT_RGBA_DXT3: + textureFormat = TFT_S3TC4A4Bit; + tileIndex = TILE_INDEX_DXTn; + t->texelBytes = 16; + break; + case MESA_FORMAT_RGBA_DXT5: + textureFormat = TFT_S3TC4CA4Bit; + tileIndex = TILE_INDEX_DXTn; + t->texelBytes = 16; + break; + default: + _mesa_problem(imesa->glCtx, "Bad texture format in %s", __FUNCTION__); + return; + } + t->hwFormat = textureFormat; + + /* Select tiling format depending on the chipset and texture format */ + if (imesa->savageScreen->chipset <= S3_SAVAGE4) + t->tileInfo = &tileInfo_s3d_s4[tileIndex]; + else + t->tileInfo = &tileInfo_pro[tileIndex]; + + /* Compute which mipmap levels we really want to send to the hardware. + */ + driCalculateTextureFirstLastLevel( &t->base ); + firstLevel = t->base.firstLevel; + lastLevel = t->base.lastLevel; + + /* Figure out the size now (and count the levels). Upload won't be + * done until later. If the number of tiles changes, it means that + * this function is called for the first time on this tex object or + * the image or the destination color format changed. So all tiles + * are marked as dirty. + */ + offset = 0; + size = 1; + for ( i = firstLevel ; i <= lastLevel && tObj->Image[0][i] ; i++ ) { + GLuint nTiles; + nTiles = savageTexImageTiles (image->Width2, image->Height2, t->tileInfo); + if (t->image[i].nTiles != nTiles) { + GLuint words = (nTiles + 31) / 32; + if (t->image[i].nTiles != 0) { + free(t->image[i].dirtyTiles); + } + t->image[i].dirtyTiles = malloc(words*sizeof(GLuint)); + memset(t->image[i].dirtyTiles, ~0, words*sizeof(GLuint)); + } + t->image[i].nTiles = nTiles; + + t->image[i].offset = offset; + + image = tObj->Image[0][i]; + if (t->texelBytes >= 8) + size = savageCompressedTexImageSize (image->Width2, image->Height2, + t->texelBytes); + else + size = savageTexImageSize (image->Width2, image->Height2, + t->texelBytes); + offset += size; + } + + t->base.lastLevel = i-1; + t->base.totalSize = offset; + /* the last three mipmap levels don't add to the offset. They are packed + * into 64 pixels. */ + if (size == 0) + t->base.totalSize += (t->texelBytes >= 8 ? 4 : 64) * t->texelBytes; + /* 2k-aligned (really needed?) */ + t->base.totalSize = (t->base.totalSize + 2047UL) & ~2047UL; +} + +void savageDestroyTexObj(savageContextPtr imesa, savageTexObjPtr t) +{ + GLuint i; + + /* Free dirty tiles bit vectors */ + for (i = 0; i < SAVAGE_TEX_MAXLEVELS; ++i) { + if (t->image[i].nTiles) + free (t->image[i].dirtyTiles); + } + + /* See if it was the driver's current object. + */ + if ( imesa != NULL ) + { + for ( i = 0 ; i < imesa->glCtx->Const.MaxTextureUnits ; i++ ) + { + if ( &t->base == imesa->CurrentTexObj[ i ] ) { + assert( t->base.bound & (1 << i) ); + imesa->CurrentTexObj[ i ] = NULL; + } + } + } +} + +/* Upload a texture's images to one of the texture heaps. May have to + * eject our own and/or other client's texture objects to make room + * for the upload. + */ +static void savageUploadTexImages( savageContextPtr imesa, savageTexObjPtr t ) +{ + const GLint numLevels = t->base.lastLevel - t->base.firstLevel + 1; + GLuint i; + + assert(t); + + LOCK_HARDWARE(imesa); + + /* Do we need to eject LRU texture objects? + */ + if (!t->base.memBlock) { + GLint heap; + GLuint ofs; + + heap = driAllocateTexture(imesa->textureHeaps, imesa->lastTexHeap, + (driTextureObject *)t); + if (heap == -1) { + UNLOCK_HARDWARE(imesa); + return; + } + + ofs = t->base.memBlock->ofs; + t->setup.physAddr = imesa->savageScreen->textureOffset[heap] + ofs; + t->bufAddr = (GLubyte *)imesa->savageScreen->texVirtual[heap] + ofs; + imesa->dirty |= SAVAGE_UPLOAD_GLOBAL; /* FIXME: really needed? */ + } + + /* Let the world know we've used this memory recently. + */ + driUpdateTextureLRU( &t->base ); + UNLOCK_HARDWARE(imesa); + + if (t->base.dirty_images[0] || t->dirtySubImages) { + if (SAVAGE_DEBUG & DEBUG_VERBOSE_TEX) + fprintf(stderr, "Texture upload: |"); + + /* Heap timestamps are only reliable with Savage DRM 2.3.x or + * later. Earlier versions had only 16 bit time stamps which + * would wrap too frequently. */ + if (imesa->savageScreen->driScrnPriv->drmMinor >= 3) { + unsigned int heap = t->base.heap->heapId; + LOCK_HARDWARE(imesa); + savageWaitEvent (imesa, imesa->textureHeaps[heap]->timestamp); + } else { + savageFlushVertices (imesa); + LOCK_HARDWARE(imesa); + savageFlushCmdBufLocked (imesa, GL_FALSE); + WAIT_IDLE_EMPTY_LOCKED(imesa); + } + + for (i = 0 ; i < numLevels ; i++) { + const GLint j = t->base.firstLevel + i; /* the texObj's level */ + if (t->base.dirty_images[0] & (1 << j)) { + savageMarkAllTiles(t, j); + if (SAVAGE_DEBUG & DEBUG_VERBOSE_TEX) + fprintf (stderr, "*"); + } else if (SAVAGE_DEBUG & DEBUG_VERBOSE_TEX) { + if (t->dirtySubImages & (1 << j)) + fprintf (stderr, "."); + else + fprintf (stderr, " "); + } + if ((t->base.dirty_images[0] | t->dirtySubImages) & (1 << j)) + savageUploadTexLevel( t, j ); + } + + UNLOCK_HARDWARE(imesa); + t->base.dirty_images[0] = 0; + t->dirtySubImages = 0; + + if (SAVAGE_DEBUG & DEBUG_VERBOSE_TEX) + fprintf(stderr, "|\n"); + } +} + + +static void +savage4_set_wrap_mode( savageContextPtr imesa, unsigned unit, + GLenum s_mode, GLenum t_mode ) +{ + switch( s_mode ) { + case GL_REPEAT: + imesa->regs.s4.texCtrl[ unit ].ni.uMode = TAM_Wrap; + break; + case GL_CLAMP: + case GL_CLAMP_TO_EDGE: + imesa->regs.s4.texCtrl[ unit ].ni.uMode = TAM_Clamp; + break; + case GL_MIRRORED_REPEAT: + imesa->regs.s4.texCtrl[ unit ].ni.uMode = TAM_Mirror; + break; + } + + switch( t_mode ) { + case GL_REPEAT: + imesa->regs.s4.texCtrl[ unit ].ni.vMode = TAM_Wrap; + break; + case GL_CLAMP: + case GL_CLAMP_TO_EDGE: + imesa->regs.s4.texCtrl[ unit ].ni.vMode = TAM_Clamp; + break; + case GL_MIRRORED_REPEAT: + imesa->regs.s4.texCtrl[ unit ].ni.vMode = TAM_Mirror; + break; + } +} + + +/** + * Sets the hardware bits for the specified GL texture filter modes. + * + * \todo + * Does the Savage4 have the ability to select the magnification filter? + */ +static void +savage4_set_filter_mode( savageContextPtr imesa, unsigned unit, + GLenum minFilter, GLenum magFilter ) +{ + (void) magFilter; + + switch (minFilter) { + case GL_NEAREST: + imesa->regs.s4.texCtrl[ unit ].ni.filterMode = TFM_Point; + imesa->regs.s4.texCtrl[ unit ].ni.mipmapEnable = GL_FALSE; + break; + + case GL_LINEAR: + imesa->regs.s4.texCtrl[ unit ].ni.filterMode = TFM_Bilin; + imesa->regs.s4.texCtrl[ unit ].ni.mipmapEnable = GL_FALSE; + break; + + case GL_NEAREST_MIPMAP_NEAREST: + imesa->regs.s4.texCtrl[ unit ].ni.filterMode = TFM_Point; + imesa->regs.s4.texCtrl[ unit ].ni.mipmapEnable = GL_TRUE; + break; + + case GL_LINEAR_MIPMAP_NEAREST: + imesa->regs.s4.texCtrl[ unit ].ni.filterMode = TFM_Bilin; + imesa->regs.s4.texCtrl[ unit ].ni.mipmapEnable = GL_TRUE; + break; + + case GL_NEAREST_MIPMAP_LINEAR: + case GL_LINEAR_MIPMAP_LINEAR: + imesa->regs.s4.texCtrl[ unit ].ni.filterMode = TFM_Trilin; + imesa->regs.s4.texCtrl[ unit ].ni.mipmapEnable = GL_TRUE; + break; + } +} + + +static void savageUpdateTex0State_s4( GLcontext *ctx ) +{ + savageContextPtr imesa = SAVAGE_CONTEXT(ctx); + struct gl_texture_object *tObj; + struct gl_texture_image *image; + savageTexObjPtr t; + GLuint format; + + /* disable */ + imesa->regs.s4.texDescr.ni.tex0En = GL_FALSE; + imesa->regs.s4.texBlendCtrl[0].ui = TBC_NoTexMap; + imesa->regs.s4.texCtrl[0].ui = 0x20f040; + if (ctx->Texture.Unit[0]._ReallyEnabled == 0) + return; + + tObj = ctx->Texture.Unit[0]._Current; + if ((ctx->Texture.Unit[0]._ReallyEnabled & ~(TEXTURE_1D_BIT|TEXTURE_2D_BIT)) + || tObj->Image[0][tObj->BaseLevel]->Border > 0) { + /* 3D texturing enabled, or texture border - fallback */ + FALLBACK (ctx, SAVAGE_FALLBACK_TEXTURE, GL_TRUE); + return; + } + + /* Do 2D texture setup */ + + t = tObj->DriverData; + if (!t) { + t = savageAllocTexObj( tObj ); + if (!t) + return; + } + + imesa->CurrentTexObj[0] = &t->base; + t->base.bound |= 1; + + if (t->base.dirty_images[0] || t->dirtySubImages) { + savageSetTexImages(imesa, tObj); + savageUploadTexImages(imesa, t); + } + + driUpdateTextureLRU( &t->base ); + + format = tObj->Image[0][tObj->BaseLevel]->_BaseFormat; + + switch (ctx->Texture.Unit[0].EnvMode) { + case GL_REPLACE: + imesa->regs.s4.texCtrl[0].ni.clrArg1Invert = GL_FALSE; + switch(format) + { + case GL_LUMINANCE: + case GL_RGB: + imesa->regs.s4.texBlendCtrl[0].ui = TBC_Decal; + break; + + case GL_LUMINANCE_ALPHA: + case GL_RGBA: + case GL_INTENSITY: + imesa->regs.s4.texBlendCtrl[0].ui = TBC_Copy; + break; + + case GL_ALPHA: + imesa->regs.s4.texBlendCtrl[0].ui = TBC_CopyAlpha; + break; + } + __HWEnvCombineSingleUnitScale(imesa, 0, 0, + &imesa->regs.s4.texBlendCtrl[0]); + break; + + case GL_DECAL: + imesa->regs.s4.texCtrl[0].ni.clrArg1Invert = GL_FALSE; + switch (format) + { + case GL_RGB: + case GL_LUMINANCE: + imesa->regs.s4.texBlendCtrl[0].ui = TBC_Decal; + break; + + case GL_RGBA: + case GL_INTENSITY: + case GL_LUMINANCE_ALPHA: + imesa->regs.s4.texBlendCtrl[0].ui = TBC_DecalAlpha; + break; + + /* + GL_LUMINANCE, GL_LUMINANCE_ALPHA, GL_ALPHA, GL_INTENSITY + are undefined with GL_DECAL + */ + + case GL_ALPHA: + imesa->regs.s4.texBlendCtrl[0].ui = TBC_CopyAlpha; + break; + } + __HWEnvCombineSingleUnitScale(imesa, 0, 0, + &imesa->regs.s4.texBlendCtrl[0]); + break; + + case GL_MODULATE: + imesa->regs.s4.texCtrl[0].ni.clrArg1Invert = GL_FALSE; + imesa->regs.s4.texBlendCtrl[0].ui = TBC_ModulAlpha; + __HWEnvCombineSingleUnitScale(imesa, 0, 0, + &imesa->regs.s4.texBlendCtrl[0]); + break; + + case GL_BLEND: + imesa->regs.s4.texBlendColor.ui = imesa->texEnvColor; + + switch (format) + { + case GL_ALPHA: + imesa->regs.s4.texBlendCtrl[0].ui = TBC_ModulAlpha; + imesa->regs.s4.texCtrl[0].ni.clrArg1Invert = GL_FALSE; + break; + + case GL_LUMINANCE: + case GL_RGB: + imesa->regs.s4.texBlendCtrl[0].ui = TBC_Blend0; + imesa->regs.s4.texDescr.ni.tex1En = GL_TRUE; + imesa->regs.s4.texDescr.ni.texBLoopEn = GL_TRUE; + imesa->regs.s4.texDescr.ni.tex1Width = + imesa->regs.s4.texDescr.ni.tex0Width; + imesa->regs.s4.texDescr.ni.tex1Height = + imesa->regs.s4.texDescr.ni.tex0Height; + imesa->regs.s4.texDescr.ni.tex1Fmt = + imesa->regs.s4.texDescr.ni.tex0Fmt; + + imesa->regs.s4.texAddr[1].ui = imesa->regs.s4.texAddr[0].ui; + imesa->regs.s4.texBlendCtrl[1].ui = TBC_Blend1; + + imesa->regs.s4.texCtrl[0].ni.clrArg1Invert = GL_TRUE; + imesa->bTexEn1 = GL_TRUE; + break; + + case GL_LUMINANCE_ALPHA: + case GL_RGBA: + imesa->regs.s4.texBlendCtrl[0].ui = TBC_BlendAlpha0; + imesa->regs.s4.texDescr.ni.tex1En = GL_TRUE; + imesa->regs.s4.texDescr.ni.texBLoopEn = GL_TRUE; + imesa->regs.s4.texDescr.ni.tex1Width = + imesa->regs.s4.texDescr.ni.tex0Width; + imesa->regs.s4.texDescr.ni.tex1Height = + imesa->regs.s4.texDescr.ni.tex0Height; + imesa->regs.s4.texDescr.ni.tex1Fmt = + imesa->regs.s4.texDescr.ni.tex0Fmt; + + imesa->regs.s4.texAddr[1].ui = imesa->regs.s4.texAddr[0].ui; + imesa->regs.s4.texBlendCtrl[1].ui = TBC_BlendAlpha1; + + imesa->regs.s4.texCtrl[0].ni.clrArg1Invert = GL_TRUE; + imesa->bTexEn1 = GL_TRUE; + break; + + case GL_INTENSITY: + imesa->regs.s4.texBlendCtrl[0].ui = TBC_BlendInt0; + imesa->regs.s4.texDescr.ni.tex1En = GL_TRUE; + imesa->regs.s4.texDescr.ni.texBLoopEn = GL_TRUE; + imesa->regs.s4.texDescr.ni.tex1Width = + imesa->regs.s4.texDescr.ni.tex0Width; + imesa->regs.s4.texDescr.ni.tex1Height = + imesa->regs.s4.texDescr.ni.tex0Height; + imesa->regs.s4.texDescr.ni.tex1Fmt = + imesa->regs.s4.texDescr.ni.tex0Fmt; + + imesa->regs.s4.texAddr[1].ui = imesa->regs.s4.texAddr[0].ui; + imesa->regs.s4.texBlendCtrl[1].ui = TBC_BlendInt1; + + imesa->regs.s4.texCtrl[0].ni.clrArg1Invert = GL_TRUE; + imesa->regs.s4.texCtrl[0].ni.alphaArg1Invert = GL_TRUE; + imesa->bTexEn1 = GL_TRUE; + break; + } + __HWEnvCombineSingleUnitScale(imesa, 0, 0, + &imesa->regs.s4.texBlendCtrl[0]); + break; + + case GL_ADD: + imesa->regs.s4.texCtrl[0].ni.clrArg1Invert = GL_FALSE; + switch (format) + { + case GL_ALPHA: + imesa->regs.s4.texBlendCtrl[0].ui = TBC_ModulAlpha; + break; + + case GL_LUMINANCE: + case GL_RGB: + imesa->regs.s4.texBlendCtrl[0].ui = TBC_Add; + break; + + case GL_LUMINANCE_ALPHA: + case GL_RGBA: + imesa->regs.s4.texBlendCtrl[0].ui = TBC_Add; + break; + + case GL_INTENSITY: + imesa->regs.s4.texBlendCtrl[0].ui = TBC_AddAlpha; + break; + } + __HWEnvCombineSingleUnitScale(imesa, 0, 0, + &imesa->regs.s4.texBlendCtrl[0]); + break; + +#if GL_ARB_texture_env_combine + case GL_COMBINE_ARB: + __HWParseTexEnvCombine(imesa, 0, &imesa->regs.s4.texCtrl[0], + &imesa->regs.s4.texBlendCtrl[0]); + break; +#endif + + default: + fprintf(stderr, "unknown tex env mode"); + exit(1); + break; + } + + savage4_set_wrap_mode( imesa, 0, t->setup.sWrapMode, t->setup.tWrapMode ); + savage4_set_filter_mode( imesa, 0, t->setup.minFilter, t->setup.magFilter ); + + if((ctx->Texture.Unit[0].LodBias !=0.0F) || + (imesa->regs.s4.texCtrl[0].ni.dBias != 0)) + { + int bias = (int)(ctx->Texture.Unit[0].LodBias * 32.0) + + SAVAGE4_LOD_OFFSET; + if (bias < -256) + bias = -256; + else if (bias > 255) + bias = 255; + imesa->regs.s4.texCtrl[0].ni.dBias = bias & 0x1ff; + } + + image = tObj->Image[0][tObj->BaseLevel]; + imesa->regs.s4.texDescr.ni.tex0En = GL_TRUE; + imesa->regs.s4.texDescr.ni.tex0Width = image->WidthLog2; + imesa->regs.s4.texDescr.ni.tex0Height = image->HeightLog2; + imesa->regs.s4.texDescr.ni.tex0Fmt = t->hwFormat; + imesa->regs.s4.texCtrl[0].ni.dMax = t->base.lastLevel - t->base.firstLevel; + + if (imesa->regs.s4.texDescr.ni.tex1En) + imesa->regs.s4.texDescr.ni.texBLoopEn = GL_TRUE; + + imesa->regs.s4.texAddr[0].ui = (u_int32_t) t->setup.physAddr | 0x2; + if(t->base.heap->heapId == SAVAGE_AGP_HEAP) + imesa->regs.s4.texAddr[0].ui |= 0x1; + + return; +} +static void savageUpdateTex1State_s4( GLcontext *ctx ) +{ + savageContextPtr imesa = SAVAGE_CONTEXT(ctx); + struct gl_texture_object *tObj; + struct gl_texture_image *image; + savageTexObjPtr t; + GLuint format; + + /* disable */ + if(imesa->bTexEn1) + { + imesa->bTexEn1 = GL_FALSE; + return; + } + + imesa->regs.s4.texDescr.ni.tex1En = GL_FALSE; + imesa->regs.s4.texBlendCtrl[1].ui = TBC_NoTexMap1; + imesa->regs.s4.texCtrl[1].ui = 0x20f040; + imesa->regs.s4.texDescr.ni.texBLoopEn = GL_FALSE; + if (ctx->Texture.Unit[1]._ReallyEnabled == 0) + return; + + tObj = ctx->Texture.Unit[1]._Current; + + if ((ctx->Texture.Unit[1]._ReallyEnabled & ~(TEXTURE_1D_BIT|TEXTURE_2D_BIT)) + || tObj->Image[0][tObj->BaseLevel]->Border > 0) { + /* 3D texturing enabled, or texture border - fallback */ + FALLBACK (ctx, SAVAGE_FALLBACK_TEXTURE, GL_TRUE); + return; + } + + /* Do 2D texture setup */ + + t = tObj->DriverData; + if (!t) { + t = savageAllocTexObj( tObj ); + if (!t) + return; + } + + imesa->CurrentTexObj[1] = &t->base; + + t->base.bound |= 2; + + if (t->base.dirty_images[0] || t->dirtySubImages) { + savageSetTexImages(imesa, tObj); + savageUploadTexImages(imesa, t); + } + + driUpdateTextureLRU( &t->base ); + + format = tObj->Image[0][tObj->BaseLevel]->_BaseFormat; + + switch (ctx->Texture.Unit[1].EnvMode) { + case GL_REPLACE: + imesa->regs.s4.texCtrl[1].ni.clrArg1Invert = GL_FALSE; + switch (format) + { + case GL_LUMINANCE: + case GL_RGB: + imesa->regs.s4.texBlendCtrl[1].ui = TBC_Decal; + break; + + case GL_LUMINANCE_ALPHA: + case GL_INTENSITY: + case GL_RGBA: + imesa->regs.s4.texBlendCtrl[1].ui = TBC_Copy; + break; + + case GL_ALPHA: + imesa->regs.s4.texBlendCtrl[1].ui = TBC_CopyAlpha1; + break; + } + __HWEnvCombineSingleUnitScale(imesa, 0, 1, &imesa->regs.s4.texBlendCtrl); + break; + case GL_MODULATE: + imesa->regs.s4.texCtrl[1].ni.clrArg1Invert = GL_FALSE; + imesa->regs.s4.texBlendCtrl[1].ui = TBC_ModulAlpha1; + __HWEnvCombineSingleUnitScale(imesa, 0, 1, &imesa->regs.s4.texBlendCtrl); + break; + + case GL_ADD: + imesa->regs.s4.texCtrl[1].ni.clrArg1Invert = GL_FALSE; + switch (format) + { + case GL_ALPHA: + imesa->regs.s4.texBlendCtrl[1].ui = TBC_ModulAlpha1; + break; + + case GL_LUMINANCE: + case GL_RGB: + imesa->regs.s4.texBlendCtrl[1].ui = TBC_Add1; + break; + + case GL_LUMINANCE_ALPHA: + case GL_RGBA: + imesa->regs.s4.texBlendCtrl[1].ui = TBC_Add1; + break; + + case GL_INTENSITY: + imesa->regs.s4.texBlendCtrl[1].ui = TBC_AddAlpha1; + break; + } + __HWEnvCombineSingleUnitScale(imesa, 0, 1, &imesa->regs.s4.texBlendCtrl); + break; + +#if GL_ARB_texture_env_combine + case GL_COMBINE_ARB: + __HWParseTexEnvCombine(imesa, 1, &texCtrl, &imesa->regs.s4.texBlendCtrl); + break; +#endif + + case GL_DECAL: + imesa->regs.s4.texCtrl[1].ni.clrArg1Invert = GL_FALSE; + + switch (format) + { + case GL_LUMINANCE: + case GL_RGB: + imesa->regs.s4.texBlendCtrl[1].ui = TBC_Decal1; + break; + case GL_LUMINANCE_ALPHA: + case GL_INTENSITY: + case GL_RGBA: + imesa->regs.s4.texBlendCtrl[1].ui = TBC_DecalAlpha1; + break; + + /* + // GL_LUMINANCE, GL_LUMINANCE_ALPHA, GL_ALPHA, GL_INTENSITY + // are undefined with GL_DECAL + */ + case GL_ALPHA: + imesa->regs.s4.texBlendCtrl[1].ui = TBC_CopyAlpha1; + break; + } + __HWEnvCombineSingleUnitScale(imesa, 0, 1, &imesa->regs.s4.texBlendCtrl); + break; + + case GL_BLEND: + if (format == GL_LUMINANCE) + { + /* + // This is a hack for GLQuake, invert. + */ + imesa->regs.s4.texCtrl[1].ni.clrArg1Invert = GL_TRUE; + imesa->regs.s4.texBlendCtrl[1].ui = 0; + } + __HWEnvCombineSingleUnitScale(imesa, 0, 1, &imesa->regs.s4.texBlendCtrl); + break; + + default: + fprintf(stderr, "unknown tex 1 env mode\n"); + exit(1); + break; + } + + savage4_set_wrap_mode( imesa, 1, t->setup.sWrapMode, t->setup.tWrapMode ); + savage4_set_filter_mode( imesa, 1, t->setup.minFilter, t->setup.magFilter ); + + if((ctx->Texture.Unit[1].LodBias !=0.0F) || + (imesa->regs.s4.texCtrl[1].ni.dBias != 0)) + { + int bias = (int)(ctx->Texture.Unit[1].LodBias * 32.0) + + SAVAGE4_LOD_OFFSET; + if (bias < -256) + bias = -256; + else if (bias > 255) + bias = 255; + imesa->regs.s4.texCtrl[1].ni.dBias = bias & 0x1ff; + } + + image = tObj->Image[0][tObj->BaseLevel]; + imesa->regs.s4.texDescr.ni.tex1En = GL_TRUE; + imesa->regs.s4.texDescr.ni.tex1Width = image->WidthLog2; + imesa->regs.s4.texDescr.ni.tex1Height = image->HeightLog2; + imesa->regs.s4.texDescr.ni.tex1Fmt = t->hwFormat; + imesa->regs.s4.texCtrl[1].ni.dMax = t->base.lastLevel - t->base.firstLevel; + imesa->regs.s4.texDescr.ni.texBLoopEn = GL_TRUE; + + imesa->regs.s4.texAddr[1].ui = (u_int32_t) t->setup.physAddr | 2; + if(t->base.heap->heapId == SAVAGE_AGP_HEAP) + imesa->regs.s4.texAddr[1].ui |= 0x1; +} +static void savageUpdateTexState_s3d( GLcontext *ctx ) +{ + savageContextPtr imesa = SAVAGE_CONTEXT(ctx); + struct gl_texture_object *tObj; + struct gl_texture_image *image; + savageTexObjPtr t; + GLuint format; + + /* disable */ + imesa->regs.s3d.texCtrl.ui = 0; + imesa->regs.s3d.texCtrl.ni.texEn = GL_FALSE; + imesa->regs.s3d.texCtrl.ni.dBias = 0x08; + imesa->regs.s3d.texCtrl.ni.texXprEn = GL_TRUE; + if (ctx->Texture.Unit[0]._ReallyEnabled == 0) + return; + + tObj = ctx->Texture.Unit[0]._Current; + if ((ctx->Texture.Unit[0]._ReallyEnabled & ~(TEXTURE_1D_BIT|TEXTURE_2D_BIT)) + || tObj->Image[0][tObj->BaseLevel]->Border > 0) { + /* 3D texturing enabled, or texture border - fallback */ + FALLBACK (ctx, SAVAGE_FALLBACK_TEXTURE, GL_TRUE); + return; + } + + /* Do 2D texture setup */ + t = tObj->DriverData; + if (!t) { + t = savageAllocTexObj( tObj ); + if (!t) + return; + } + + imesa->CurrentTexObj[0] = &t->base; + t->base.bound |= 1; + + if (t->base.dirty_images[0] || t->dirtySubImages) { + savageSetTexImages(imesa, tObj); + savageUploadTexImages(imesa, t); + } + + driUpdateTextureLRU( &t->base ); + + format = tObj->Image[0][tObj->BaseLevel]->_BaseFormat; + + /* FIXME: copied from utah-glx, probably needs some tuning */ + switch (ctx->Texture.Unit[0].EnvMode) { + case GL_DECAL: + imesa->regs.s3d.drawCtrl.ni.texBlendCtrl = SAVAGETBC_DECALALPHA_S3D; + break; + case GL_REPLACE: + switch (format) { + case GL_ALPHA: /* FIXME */ + imesa->regs.s3d.drawCtrl.ni.texBlendCtrl = 1; + break; + case GL_LUMINANCE_ALPHA: + case GL_RGBA: + imesa->regs.s3d.drawCtrl.ni.texBlendCtrl = 4; + break; + case GL_RGB: + case GL_LUMINANCE: + imesa->regs.s3d.drawCtrl.ni.texBlendCtrl = SAVAGETBC_DECAL_S3D; + break; + case GL_INTENSITY: + imesa->regs.s3d.drawCtrl.ni.texBlendCtrl = SAVAGETBC_COPY_S3D; + } + break; + case GL_BLEND: /* hardware can't do GL_BLEND */ + FALLBACK (ctx, SAVAGE_FALLBACK_TEXTURE, GL_TRUE); + return; + case GL_MODULATE: + imesa->regs.s3d.drawCtrl.ni.texBlendCtrl = SAVAGETBC_MODULATEALPHA_S3D; + break; + default: + fprintf(stderr, "unknown tex env mode\n"); + /*exit(1);*/ + break; + } + + /* The Savage3D can't handle different wrapping modes in s and t. + * If they are not the same, fall back to software. */ + if (t->setup.sWrapMode != t->setup.tWrapMode) { + FALLBACK (ctx, SAVAGE_FALLBACK_TEXTURE, GL_TRUE); + return; + } + imesa->regs.s3d.texCtrl.ni.uWrapEn = 0; + imesa->regs.s3d.texCtrl.ni.vWrapEn = 0; + imesa->regs.s3d.texCtrl.ni.wrapMode = + (t->setup.sWrapMode == GL_REPEAT) ? TAM_Wrap : TAM_Clamp; + + switch (t->setup.minFilter) { + case GL_NEAREST: + imesa->regs.s3d.texCtrl.ni.filterMode = TFM_Point; + imesa->regs.s3d.texCtrl.ni.mipmapDisable = GL_TRUE; + break; + + case GL_LINEAR: + imesa->regs.s3d.texCtrl.ni.filterMode = TFM_Bilin; + imesa->regs.s3d.texCtrl.ni.mipmapDisable = GL_TRUE; + break; + + case GL_NEAREST_MIPMAP_NEAREST: + imesa->regs.s3d.texCtrl.ni.filterMode = TFM_Point; + imesa->regs.s3d.texCtrl.ni.mipmapDisable = GL_FALSE; + break; + + case GL_LINEAR_MIPMAP_NEAREST: + imesa->regs.s3d.texCtrl.ni.filterMode = TFM_Bilin; + imesa->regs.s3d.texCtrl.ni.mipmapDisable = GL_FALSE; + break; + + case GL_NEAREST_MIPMAP_LINEAR: + case GL_LINEAR_MIPMAP_LINEAR: + imesa->regs.s3d.texCtrl.ni.filterMode = TFM_Trilin; + imesa->regs.s3d.texCtrl.ni.mipmapDisable = GL_FALSE; + break; + } + + /* There is no way to specify a maximum mipmap level. We may have to + disable mipmapping completely. */ + /* + if (t->max_level < t->image[0].image->WidthLog2 || + t->max_level < t->image[0].image->HeightLog2) { + texCtrl.ni.mipmapEnable = GL_TRUE; + if (texCtrl.ni.filterMode == TFM_Trilin) + texCtrl.ni.filterMode = TFM_Bilin; + texCtrl.ni.filterMode = TFM_Point; + } + */ + + if((ctx->Texture.Unit[0].LodBias !=0.0F) || + (imesa->regs.s3d.texCtrl.ni.dBias != 0)) + { + int bias = (int)(ctx->Texture.Unit[0].LodBias * 16.0); + if (bias < -256) + bias = -256; + else if (bias > 255) + bias = 255; + imesa->regs.s3d.texCtrl.ni.dBias = bias & 0x1ff; + } + + image = tObj->Image[0][tObj->BaseLevel]; + imesa->regs.s3d.texCtrl.ni.texEn = GL_TRUE; + imesa->regs.s3d.texDescr.ni.texWidth = image->WidthLog2; + imesa->regs.s3d.texDescr.ni.texHeight = image->HeightLog2; + assert (t->hwFormat <= 7); + imesa->regs.s3d.texDescr.ni.texFmt = t->hwFormat; + + imesa->regs.s3d.texAddr.ui = (u_int32_t) t->setup.physAddr | 2; + if(t->base.heap->heapId == SAVAGE_AGP_HEAP) + imesa->regs.s3d.texAddr.ui |= 0x1; +} + + +static void savageTimestampTextures( savageContextPtr imesa ) +{ + /* Timestamp current texture objects for texture heap aging. + * Only useful with long-lived 32-bit event tags available + * with Savage DRM 2.3.x or later. */ + if ((imesa->CurrentTexObj[0] || imesa->CurrentTexObj[1]) && + imesa->savageScreen->driScrnPriv->drmMinor >= 3) { + unsigned int e; + FLUSH_BATCH(imesa); + e = savageEmitEvent(imesa, SAVAGE_WAIT_3D); + if (imesa->CurrentTexObj[0]) + imesa->CurrentTexObj[0]->timestamp = e; + if (imesa->CurrentTexObj[1]) + imesa->CurrentTexObj[1]->timestamp = e; + } +} + + +static void savageUpdateTextureState_s4( GLcontext *ctx ) +{ + savageContextPtr imesa = SAVAGE_CONTEXT(ctx); + + /* When a texture is about to change or be disabled, timestamp the + * old texture(s). We'll have to wait for this time stamp before + * uploading anything to the same texture heap. + */ + if ((imesa->CurrentTexObj[0] && ctx->Texture.Unit[0]._ReallyEnabled && + ctx->Texture.Unit[0]._Current->DriverData != imesa->CurrentTexObj[0]) || + (imesa->CurrentTexObj[1] && ctx->Texture.Unit[1]._ReallyEnabled && + ctx->Texture.Unit[1]._Current->DriverData != imesa->CurrentTexObj[1]) || + (imesa->CurrentTexObj[0] && !ctx->Texture.Unit[0]._ReallyEnabled) || + (imesa->CurrentTexObj[1] && !ctx->Texture.Unit[1]._ReallyEnabled)) + savageTimestampTextures(imesa); + + if (imesa->CurrentTexObj[0]) imesa->CurrentTexObj[0]->bound &= ~1; + if (imesa->CurrentTexObj[1]) imesa->CurrentTexObj[1]->bound &= ~2; + imesa->CurrentTexObj[0] = 0; + imesa->CurrentTexObj[1] = 0; + savageUpdateTex0State_s4( ctx ); + savageUpdateTex1State_s4( ctx ); + imesa->dirty |= (SAVAGE_UPLOAD_TEX0 | + SAVAGE_UPLOAD_TEX1); +} +static void savageUpdateTextureState_s3d( GLcontext *ctx ) +{ + savageContextPtr imesa = SAVAGE_CONTEXT(ctx); + + /* When a texture is about to change or be disabled, timestamp the + * old texture(s). We'll have to wait for this time stamp before + * uploading anything to the same texture heap. + */ + if ((imesa->CurrentTexObj[0] && ctx->Texture.Unit[0]._ReallyEnabled && + ctx->Texture.Unit[0]._Current->DriverData != imesa->CurrentTexObj[0]) || + (imesa->CurrentTexObj[0] && !ctx->Texture.Unit[0]._ReallyEnabled)) + savageTimestampTextures(imesa); + + if (imesa->CurrentTexObj[0]) imesa->CurrentTexObj[0]->bound &= ~1; + imesa->CurrentTexObj[0] = 0; + savageUpdateTexState_s3d( ctx ); + imesa->dirty |= (SAVAGE_UPLOAD_TEX0); +} +void savageUpdateTextureState( GLcontext *ctx) +{ + savageContextPtr imesa = SAVAGE_CONTEXT( ctx ); + FALLBACK (ctx, SAVAGE_FALLBACK_TEXTURE, GL_FALSE); + FALLBACK(ctx, SAVAGE_FALLBACK_PROJ_TEXTURE, GL_FALSE); + if (imesa->savageScreen->chipset >= S3_SAVAGE4) + savageUpdateTextureState_s4 (ctx); + else + savageUpdateTextureState_s3d (ctx); +} + + + +/***************************************** + * DRIVER functions + *****************************************/ + +static void savageTexEnv( GLcontext *ctx, GLenum target, + GLenum pname, const GLfloat *param ) +{ + savageContextPtr imesa = SAVAGE_CONTEXT( ctx ); + + if (pname == GL_TEXTURE_ENV_MODE) { + + imesa->new_state |= SAVAGE_NEW_TEXTURE; + + } else if (pname == GL_TEXTURE_ENV_COLOR) { + + struct gl_texture_unit *texUnit = + &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; + const GLfloat *fc = texUnit->EnvColor; + GLuint r, g, b, a; + CLAMPED_FLOAT_TO_UBYTE(r, fc[0]); + CLAMPED_FLOAT_TO_UBYTE(g, fc[1]); + CLAMPED_FLOAT_TO_UBYTE(b, fc[2]); + CLAMPED_FLOAT_TO_UBYTE(a, fc[3]); + + imesa->texEnvColor = ((a << 24) | (r << 16) | + (g << 8) | (b << 0)); + + + } +} + +/* Update the heap's time stamp, so the new image is not uploaded + * while the old one is still in use. If the texture that is going to + * be changed is currently bound, we need to timestamp the texture + * first. */ +static void savageTexImageChanged (savageTexObjPtr t) { + if (t->base.heap) { + if (t->base.bound) + savageTimestampTextures( + (savageContextPtr)t->base.heap->driverContext); + if (t->base.timestamp > t->base.heap->timestamp) + t->base.heap->timestamp = t->base.timestamp; + } +} + +static void savageTexImage1D( GLcontext *ctx, GLenum target, GLint level, + GLint internalFormat, + GLint width, GLint border, + GLenum format, GLenum type, const GLvoid *pixels, + const struct gl_pixelstore_attrib *packing, + struct gl_texture_object *texObj, + struct gl_texture_image *texImage ) +{ + savageTexObjPtr t = (savageTexObjPtr) texObj->DriverData; + if (t) { + savageTexImageChanged (t); + } else { + t = savageAllocTexObj(texObj); + if (!t) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage1D"); + return; + } + } + _mesa_store_teximage1d( ctx, target, level, internalFormat, + width, border, format, type, + pixels, packing, texObj, texImage ); + t->base.dirty_images[0] |= (1 << level); + SAVAGE_CONTEXT(ctx)->new_state |= SAVAGE_NEW_TEXTURE; +} + +static void savageTexSubImage1D( GLcontext *ctx, + GLenum target, + GLint level, + GLint xoffset, + GLsizei width, + GLenum format, GLenum type, + const GLvoid *pixels, + const struct gl_pixelstore_attrib *packing, + struct gl_texture_object *texObj, + struct gl_texture_image *texImage ) +{ + savageTexObjPtr t = (savageTexObjPtr) texObj->DriverData; + assert( t ); /* this _should_ be true */ + if (t) { + savageTexImageChanged (t); + savageMarkDirtyTiles(t, level, texImage->Width2, 1, + xoffset, 0, width, 1); + } else { + t = savageAllocTexObj(texObj); + if (!t) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexSubImage1D"); + return; + } + t->base.dirty_images[0] |= (1 << level); + } + _mesa_store_texsubimage1d(ctx, target, level, xoffset, width, + format, type, pixels, packing, texObj, + texImage); + t->dirtySubImages |= (1 << level); + SAVAGE_CONTEXT(ctx)->new_state |= SAVAGE_NEW_TEXTURE; +} + +static void savageTexImage2D( GLcontext *ctx, GLenum target, GLint level, + GLint internalFormat, + GLint width, GLint height, GLint border, + GLenum format, GLenum type, const GLvoid *pixels, + const struct gl_pixelstore_attrib *packing, + struct gl_texture_object *texObj, + struct gl_texture_image *texImage ) +{ + savageTexObjPtr t = (savageTexObjPtr) texObj->DriverData; + if (t) { + savageTexImageChanged (t); + } else { + t = savageAllocTexObj(texObj); + if (!t) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage2D"); + return; + } + } + _mesa_store_teximage2d( ctx, target, level, internalFormat, + width, height, border, format, type, + pixels, packing, texObj, texImage ); + t->base.dirty_images[0] |= (1 << level); + SAVAGE_CONTEXT(ctx)->new_state |= SAVAGE_NEW_TEXTURE; +} + +static void savageTexSubImage2D( GLcontext *ctx, + GLenum target, + GLint level, + GLint xoffset, GLint yoffset, + GLsizei width, GLsizei height, + GLenum format, GLenum type, + const GLvoid *pixels, + const struct gl_pixelstore_attrib *packing, + struct gl_texture_object *texObj, + struct gl_texture_image *texImage ) +{ + savageTexObjPtr t = (savageTexObjPtr) texObj->DriverData; + assert( t ); /* this _should_ be true */ + if (t) { + savageTexImageChanged (t); + savageMarkDirtyTiles(t, level, texImage->Width2, texImage->Height2, + xoffset, yoffset, width, height); + } else { + t = savageAllocTexObj(texObj); + if (!t) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexSubImage2D"); + return; + } + t->base.dirty_images[0] |= (1 << level); + } + _mesa_store_texsubimage2d(ctx, target, level, xoffset, yoffset, width, + height, format, type, pixels, packing, texObj, + texImage); + t->dirtySubImages |= (1 << level); + SAVAGE_CONTEXT(ctx)->new_state |= SAVAGE_NEW_TEXTURE; +} + +static void +savageCompressedTexImage2D( GLcontext *ctx, GLenum target, GLint level, + GLint internalFormat, + GLint width, GLint height, GLint border, + GLsizei imageSize, const GLvoid *data, + struct gl_texture_object *texObj, + struct gl_texture_image *texImage ) +{ + savageTexObjPtr t = (savageTexObjPtr) texObj->DriverData; + if (t) { + savageTexImageChanged (t); + } else { + t = savageAllocTexObj(texObj); + if (!t) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCompressedTexImage2D"); + return; + } + } + _mesa_store_compressed_teximage2d( ctx, target, level, internalFormat, + width, height, border, imageSize, + data, texObj, texImage ); + t->base.dirty_images[0] |= (1 << level); + SAVAGE_CONTEXT(ctx)->new_state |= SAVAGE_NEW_TEXTURE; +} + +static void +savageCompressedTexSubImage2D( GLcontext *ctx, + GLenum target, + GLint level, + GLint xoffset, GLint yoffset, + GLsizei width, GLsizei height, + GLenum format, GLsizei imageSize, + const GLvoid *data, + struct gl_texture_object *texObj, + struct gl_texture_image *texImage ) +{ + savageTexObjPtr t = (savageTexObjPtr) texObj->DriverData; + assert( t ); /* this _should_ be true */ + if (t) { + savageTexImageChanged (t); + savageMarkDirtyTiles(t, level, texImage->Width2, texImage->Height2, + xoffset, yoffset, width, height); + } else { + t = savageAllocTexObj(texObj); + if (!t) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexSubImage2D"); + return; + } + t->base.dirty_images[0] |= (1 << level); + } + _mesa_store_compressed_texsubimage2d(ctx, target, level, xoffset, yoffset, + width, height, format, imageSize, + data, texObj, texImage); + t->dirtySubImages |= (1 << level); + SAVAGE_CONTEXT(ctx)->new_state |= SAVAGE_NEW_TEXTURE; +} + +static void savageTexParameter( GLcontext *ctx, GLenum target, + struct gl_texture_object *tObj, + GLenum pname, const GLfloat *params ) +{ + savageTexObjPtr t = (savageTexObjPtr) tObj->DriverData; + savageContextPtr imesa = SAVAGE_CONTEXT( ctx ); + + if (!t || (target != GL_TEXTURE_1D && target != GL_TEXTURE_2D)) + return; + + switch (pname) { + case GL_TEXTURE_MIN_FILTER: + case GL_TEXTURE_MAG_FILTER: + savageSetTexFilter(t,tObj->MinFilter,tObj->MagFilter); + break; + + case GL_TEXTURE_WRAP_S: + case GL_TEXTURE_WRAP_T: + savageSetTexWrapping(t,tObj->WrapS,tObj->WrapT); + break; + + case GL_TEXTURE_BORDER_COLOR: + savageSetTexBorderColor(t,tObj->_BorderChan); + break; + + default: + return; + } + + imesa->new_state |= SAVAGE_NEW_TEXTURE; +} + +static void savageBindTexture( GLcontext *ctx, GLenum target, + struct gl_texture_object *tObj ) +{ + savageContextPtr imesa = SAVAGE_CONTEXT( ctx ); + + assert( (target != GL_TEXTURE_1D && target != GL_TEXTURE_2D) || + (tObj->DriverData != NULL) ); + + imesa->new_state |= SAVAGE_NEW_TEXTURE; +} + +static void savageDeleteTexture( GLcontext *ctx, struct gl_texture_object *tObj ) +{ + driTextureObject *t = (driTextureObject *)tObj->DriverData; + savageContextPtr imesa = SAVAGE_CONTEXT( ctx ); + + if (t) { + if (t->bound) + savageTimestampTextures(imesa); + + driDestroyTextureObject(t); + } + /* Free mipmap images and the texture object itself */ + _mesa_delete_texture_object(ctx, tObj); +} + + +static struct gl_texture_object * +savageNewTextureObject( GLcontext *ctx, GLuint name, GLenum target ) +{ + struct gl_texture_object *obj; + obj = _mesa_new_texture_object(ctx, name, target); + savageAllocTexObj( obj ); + + return obj; +} + +void savageDDInitTextureFuncs( struct dd_function_table *functions ) +{ + functions->TexEnv = savageTexEnv; + functions->ChooseTextureFormat = savageChooseTextureFormat; + functions->TexImage1D = savageTexImage1D; + functions->TexSubImage1D = savageTexSubImage1D; + functions->TexImage2D = savageTexImage2D; + functions->TexSubImage2D = savageTexSubImage2D; + functions->CompressedTexImage2D = savageCompressedTexImage2D; + functions->CompressedTexSubImage2D = savageCompressedTexSubImage2D; + functions->BindTexture = savageBindTexture; + functions->NewTextureObject = savageNewTextureObject; + functions->DeleteTexture = savageDeleteTexture; + functions->IsTextureResident = driIsTextureResident; + functions->TexParameter = savageTexParameter; + + /* Texel fetching with our custom texture formats works just like + * the standard argb formats. */ + _savage_texformat_a1114444.FetchTexel1D = _mesa_texformat_argb4444.FetchTexel1D; + _savage_texformat_a1114444.FetchTexel2D = _mesa_texformat_argb4444.FetchTexel2D; + _savage_texformat_a1114444.FetchTexel3D = _mesa_texformat_argb4444.FetchTexel3D; + _savage_texformat_a1114444.FetchTexel1Df= _mesa_texformat_argb4444.FetchTexel1Df; + _savage_texformat_a1114444.FetchTexel2Df= _mesa_texformat_argb4444.FetchTexel2Df; + _savage_texformat_a1114444.FetchTexel3Df= _mesa_texformat_argb4444.FetchTexel3Df; + + _savage_texformat_a1118888.FetchTexel1D = _mesa_texformat_argb8888.FetchTexel1D; + _savage_texformat_a1118888.FetchTexel2D = _mesa_texformat_argb8888.FetchTexel2D; + _savage_texformat_a1118888.FetchTexel3D = _mesa_texformat_argb8888.FetchTexel3D; + _savage_texformat_a1118888.FetchTexel1Df= _mesa_texformat_argb8888.FetchTexel1Df; + _savage_texformat_a1118888.FetchTexel2Df= _mesa_texformat_argb8888.FetchTexel2Df; + _savage_texformat_a1118888.FetchTexel3Df= _mesa_texformat_argb8888.FetchTexel3Df; +} |