blob: 9b81756eb942b0b777b7e07da3a072663e50bd2c [file] [log] [blame]
/*
* 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(TEXSTORE_PARAMS);
static GLboolean
_savage_texstore_a1118888(TEXSTORE_PARAMS);
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(TEXSTORE_PARAMS)
{
const GLchan *tempImage = _mesa_make_temp_chan_image(ctx, dims,
baseInternalFormat,
baseInternalFormat,
srcWidth, srcHeight, srcDepth,
srcFormat, srcType, srcAddr,
srcPacking);
const GLchan *src = tempImage;
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 = (GLubyte *) dstAddr
+ dstImageOffsets[dstZoffset + img] * dstFormat->TexelBytes
+ dstYoffset * dstRowStride
+ dstXoffset * dstFormat->TexelBytes;
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;
}
}
_mesa_free((void *) tempImage);
return GL_TRUE;
}
static GLboolean
_savage_texstore_a1118888(TEXSTORE_PARAMS)
{
const GLchan *tempImage = _mesa_make_temp_chan_image(ctx, dims,
baseInternalFormat,
baseInternalFormat,
srcWidth, srcHeight, srcDepth,
srcFormat, srcType, srcAddr,
srcPacking);
const GLchan *src = tempImage;
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 = (GLubyte *) dstAddr
+ dstImageOffsets[dstZoffset + img] * dstFormat->TexelBytes
+ dstYoffset * dstRowStride
+ dstXoffset * dstFormat->TexelBytes;
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;
}
}
_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->drm_version.minor >= 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->drm_version.minor >= 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;
}