mesa: replace gl_texture_format with gl_format
[mesa.git] / src / mesa / drivers / dri / savage / savagetex.c
index 934b6e2b3c58c80f4e34d87c463e5b3c1cb36ff1..796da4fc0d7d568c04779cd77f2dc229948b296f 100644 (file)
 
 #include <GL/gl.h>
 
-#include "mm.h"
+#include "main/mm.h"
 #include "savagecontext.h"
 #include "savagetex.h"
 #include "savagetris.h"
 #include "savageioctl.h"
-#include "simple_list.h"
-#include "enums.h"
+#include "main/simple_list.h"
+#include "main/enums.h"
 #include "savage_bci.h"
 
-#include "macros.h"
-#include "texformat.h"
-#include "texstore.h"
-#include "texobj.h"
+#include "main/macros.h"
+#include "main/texformat.h"
+#include "main/texstore.h"
+#include "main/texobj.h"
+#include "main/convolve.h"
+#include "main/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.
  * Yuck! 8-bit texture formats use 4x8 subtiles. See below.
  */
 static const savageTileInfo tileInfo_pro[5] = {
-    {64, 64,  8, 8, 8, 8, {0x12, 0x02}}, /* 4-bit */
+    {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 */
-    { 0,  0,  0, 0, 0, 0, {0x00, 0x00}}, /* 24-bit */
+    {16,  8, 16, 4, 1, 2, {0x30, 0x20}}, /* DXT3, DXT5 */
     {32, 16,  4, 2, 8, 8, {0x90, 0x10}}, /* 32-bit */
 };
 
@@ -76,10 +88,10 @@ static const savageTileInfo tileInfo_pro[5] = {
  *                      x                 1
  */
 static const savageTileInfo tileInfo_s3d_s4[5] = {
-    {64, 64, 16, 8, 4, 8, {0x18, 0x10}}, /* 4-bit */
+    {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 */
-    { 0,  0,  0, 0, 0, 0, {0x00, 0x00}}, /* 24-bit */
+    {16,  8, 16, 4, 1, 2, {0x30, 0x20}}, /* DXT3, DXT5 */
     {32, 16,  8, 2, 4, 8, {0xc0, 0x80}}, /* 32-bit */
 };
 
@@ -88,7 +100,7 @@ static const savageTileInfo tileInfo_s3d_s4[5] = {
  * \param w   width in bytes
  */
 #define SUBTILE_FUNC(w,h)                                      \
-static __inline GLubyte *savageUploadSubtile_##w##x##h         \
+static INLINE GLubyte *savageUploadSubtile_##w##x##h           \
 (GLubyte *dest, GLubyte *src, GLuint srcStride)                        \
 {                                                              \
     GLuint y;                                                  \
@@ -106,6 +118,9 @@ 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
@@ -135,8 +150,10 @@ static void savageUploadTile (const savageTileInfo *tileInfo,
     switch (subStride) {
     case  2: subtileFunc = savageUploadSubtile_2x8; break;
     case  4: subtileFunc = savageUploadSubtile_4x8; break;
-    case  8: subtileFunc = savageUploadSubtile_8x8; break;
-    case 16: subtileFunc = savageUploadSubtile_16x8; 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);
     }
@@ -169,9 +186,10 @@ static void savageUploadTile (const savageTileInfo *tileInfo,
  * 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(width, height);
+    GLuint size = MAX2(pixWidth, pixHeight);
 
     if (width > tileInfo->subWidth) { /* assert: height <= subtile height */
        GLuint wInSub = width / tileInfo->subWidth;
@@ -194,14 +212,15 @@ static void savageUploadTiny (const savageTileInfo *tileInfo,
        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 ?
+       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 & 7) == 7)
+           if ((y & skipRemainder) == skipRemainder)
                dest += subSkip;
        }
     } else { /* the last 3 mipmap levels */
@@ -223,8 +242,9 @@ 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 width = image->Width2, height = image->Height2;
+    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.
@@ -235,7 +255,16 @@ static void savageUploadTexLevel( savageTexObjPtr t, int level )
        fprintf (stderr, "Not supported texture border %d.\n",
                 (int) image->Border);
 
-    if (width >= 8 && height >= tileInfo->subHeight) {
+    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;
 
@@ -300,19 +329,22 @@ static void savageUploadTexLevel( savageTexObjPtr t, int level )
        }
     } else {
        GLuint minHeight, minWidth, hRepeat, vRepeat, x, y;
-       if (width > 4 || height > 4) {
+       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;
-       } else {
-           minWidth = 4;
-           minHeight = 4;
        }
        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, width, height, bpp, image->Data,
+               savageUploadTiny (tileInfo, pixWidth, pixHeight,
+                                 width, height, bpp, image->Data,
                                  (GLubyte *)(t->bufAddr +
                                              t->image[level].offset+offset));
                offset += width * bpp;
@@ -342,6 +374,30 @@ static GLuint savageTexImageSize (GLuint width, GLuint height, GLuint bpp) {
        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,
@@ -418,7 +474,7 @@ static void savageSetTexFilter(savageTexObjPtr t, GLenum minf, GLenum magf)
 
 /* Need a fallback ?
  */
-static void savageSetTexBorderColor(savageTexObjPtr t, GLubyte color[4])
+static void savageSetTexBorderColor(savageTexObjPtr t, const GLfloat color[4])
 {
 /*    t->Setup[SAVAGE_TEXREG_TEXBORDERCOL] =  */
     /*t->setup.borderColor = SAVAGEPACKCOLOR8888(color[0],color[1],color[2],color[3]); */
@@ -456,14 +512,153 @@ savageAllocTexObj( struct gl_texture_object *texObj )
 
       savageSetTexWrapping(t,texObj->WrapS,texObj->WrapT);
       savageSetTexFilter(t,texObj->MinFilter,texObj->MagFilter);
-      savageSetTexBorderColor(t,texObj->_BorderChan);
+      savageSetTexBorderColor(t,texObj->BorderColor);
    }
 
    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.
+ */
+
+#if 0
+/* Using MESA_FORMAT_RGBA8888 to store alpha-only textures should
+ * work but is space inefficient.
+ */
+
+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++) {
+        GLuint texelBytes = _mesa_get_format_bytes(dstFormat);
+        GLubyte *dstRow = (GLubyte *) dstAddr
+           + dstImageOffsets[dstZoffset + img] * texelBytes
+           + dstYoffset * dstRowStride
+           + dstXoffset * 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++) {
+        GLuint texelBytes = _mesa_get_format_bytes(dstFormat);
+        GLubyte *dstRow = (GLubyte *) dstAddr
+           + dstImageOffsets[dstZoffset + img] * texelBytes
+           + dstYoffset * dstRowStride
+           + dstXoffset * 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;
+}
+#endif
+
+
 /* Called by the _mesa_store_teximage[123]d() functions. */
-static const struct gl_texture_format *
+static gl_format
 savageChooseTextureFormat( GLcontext *ctx, GLint internalFormat,
                           GLenum format, GLenum type )
 {
@@ -482,15 +677,15 @@ savageChooseTextureFormat( GLcontext *ctx, GLint internalFormat,
       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;
+        return do32bpt ? MESA_FORMAT_ARGB8888 : MESA_FORMAT_ARGB1555;
       case GL_UNSIGNED_SHORT_4_4_4_4:
       case GL_UNSIGNED_SHORT_4_4_4_4_REV:
-        return &_mesa_texformat_argb4444;
+        return MESA_FORMAT_ARGB4444;
       case GL_UNSIGNED_SHORT_5_5_5_1:
       case GL_UNSIGNED_SHORT_1_5_5_5_REV:
-        return &_mesa_texformat_argb1555;
+        return MESA_FORMAT_ARGB1555;
       default:
-         return do32bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_argb4444;
+         return do32bpt ? MESA_FORMAT_ARGB8888 : MESA_FORMAT_ARGB4444;
       }
 
    case 3:
@@ -499,96 +694,153 @@ savageChooseTextureFormat( GLcontext *ctx, GLint internalFormat,
       switch ( type ) {
       case GL_UNSIGNED_SHORT_4_4_4_4:
       case GL_UNSIGNED_SHORT_4_4_4_4_REV:
-        return &_mesa_texformat_argb4444;
+        return MESA_FORMAT_ARGB4444;
       case GL_UNSIGNED_SHORT_5_5_5_1:
       case GL_UNSIGNED_SHORT_1_5_5_5_REV:
-        return &_mesa_texformat_argb1555;
+        return MESA_FORMAT_ARGB1555;
       case GL_UNSIGNED_SHORT_5_6_5:
       case GL_UNSIGNED_SHORT_5_6_5_REV:
-        return &_mesa_texformat_rgb565;
+        return MESA_FORMAT_RGB565;
       default:
-         return do32bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_rgb565;
+         return do32bpt ? MESA_FORMAT_ARGB8888 : MESA_FORMAT_RGB565;
       }
 
    case GL_RGBA8:
    case GL_RGBA12:
    case GL_RGBA16:
       return !force16bpt ?
-         &_mesa_texformat_argb8888 : &_mesa_texformat_argb4444;
+         MESA_FORMAT_ARGB8888 : MESA_FORMAT_ARGB4444;
 
    case GL_RGB10_A2:
       return !force16bpt ?
-         &_mesa_texformat_argb8888 : &_mesa_texformat_argb1555;
+         MESA_FORMAT_ARGB8888 : MESA_FORMAT_ARGB1555;
 
    case GL_RGBA4:
    case GL_RGBA2:
-      return &_mesa_texformat_argb4444;
+      return MESA_FORMAT_ARGB4444;
 
    case GL_RGB5_A1:
-      return &_mesa_texformat_argb1555;
+      return MESA_FORMAT_ARGB1555;
 
    case GL_RGB8:
    case GL_RGB10:
    case GL_RGB12:
    case GL_RGB16:
-      return !force16bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_rgb565;
+      return !force16bpt ? MESA_FORMAT_ARGB8888 : MESA_FORMAT_RGB565;
 
    case GL_RGB5:
    case GL_RGB4:
    case GL_R3_G3_B2:
-      return &_mesa_texformat_rgb565;
+      return MESA_FORMAT_RGB565;
 
    case GL_ALPHA:
    case GL_COMPRESSED_ALPHA:
-      return isSavage4 ? &_mesa_texformat_a8 : (
-        do32bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_argb4444);
+#if 0
+      return isSavage4 ? MESA_FORMAT_a8 : (
+        do32bpt ? &_savage_texformat_a1118888 : &_savage_texformat_a1114444);
+#else
+      if (isSavage4)
+         return MESA_FORMAT_A8;
+      else if (do32bpt)
+         return MESA_FORMAT_ARGB8888;
+      else
+         return MESA_FORMAT_ARGB4444;
+#endif
    case GL_ALPHA4:
-      return isSavage4 ? &_mesa_texformat_a8 : &_mesa_texformat_argb4444;
+#if 0
+      return isSavage4 ? MESA_FORMAT_a8 : &_savage_texformat_a1114444;
+#else
+      if (isSavage4)
+         return MESA_FORMAT_A8;
+      else
+         return MESA_FORMAT_ARGB4444;
+#endif
    case GL_ALPHA8:
    case GL_ALPHA12:
    case GL_ALPHA16:
-      return isSavage4 ? &_mesa_texformat_a8 : (
-        !force16bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_argb4444);
-
+#if 0
+      return isSavage4 ? MESA_FORMAT_a8 : (
+        !force16bpt ? &_savage_texformat_a1118888 : &_savage_texformat_a1114444);
+#else
+      if (isSavage4)
+         return MESA_FORMAT_A8;
+      else if (force16bpt)
+         return MESA_FORMAT_ARGB4444;
+      else
+         return MESA_FORMAT_ARGB8888;
+#endif
    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);
+      return isSavage4 ? MESA_FORMAT_L8 : (
+        do32bpt ? MESA_FORMAT_ARGB8888 : MESA_FORMAT_ARGB1555);
    case GL_LUMINANCE4:
-      return isSavage4 ? &_mesa_texformat_l8 : &_mesa_texformat_argb1555;
+      return isSavage4 ? MESA_FORMAT_L8 : MESA_FORMAT_ARGB1555;
    case GL_LUMINANCE8:
    case GL_LUMINANCE12:
    case GL_LUMINANCE16:
-      return isSavage4 ? &_mesa_texformat_l8 : (
-        !force16bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_argb1555);
+      return isSavage4 ? MESA_FORMAT_L8 : (
+        !force16bpt ? MESA_FORMAT_ARGB8888 : MESA_FORMAT_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;
+      return do32bpt ? MESA_FORMAT_ARGB8888 : MESA_FORMAT_ARGB4444;
    case GL_LUMINANCE4_ALPHA4:
    case GL_LUMINANCE6_ALPHA2:
-      return &_mesa_texformat_argb4444;
+      return MESA_FORMAT_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;
-
+      return !force16bpt ? MESA_FORMAT_ARGB8888 : MESA_FORMAT_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_FORMAT_i8 : (
+        do32bpt ? MESA_FORMAT_ARGB8888 : MESA_FORMAT_ARGB4444);
+   case GL_INTENSITY4:
+      return isSavage4 ? MESA_FORMAT_i8 : MESA_FORMAT_ARGB4444;
+   case GL_INTENSITY8:
+   case GL_INTENSITY12:
+   case GL_INTENSITY16:
+      return isSavage4 ? MESA_FORMAT_i8 : (
+        !force16bpt ? MESA_FORMAT_ARGB8888 : MESA_FORMAT_ARGB4444);
+#else
    case GL_INTENSITY:
    case GL_COMPRESSED_INTENSITY:
-      return isSavage4 ? &_mesa_texformat_i8 : (
-        do32bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_argb4444);
+      return do32bpt ? MESA_FORMAT_ARGB8888 : MESA_FORMAT_ARGB4444;
    case GL_INTENSITY4:
-      return isSavage4 ? &_mesa_texformat_i8 : &_mesa_texformat_argb4444;
+      return MESA_FORMAT_ARGB4444;
    case GL_INTENSITY8:
    case GL_INTENSITY12:
    case GL_INTENSITY16:
-      return isSavage4 ? &_mesa_texformat_i8 : (
-        !force16bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_argb4444);
+      return !force16bpt ? MESA_FORMAT_ARGB8888 : MESA_FORMAT_ARGB4444;
+#endif
+
+   case GL_RGB_S3TC:
+   case GL_RGB4_S3TC:
+   case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
+      return MESA_FORMAT_RGB_DXT1;
+   case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
+      return MESA_FORMAT_RGBA_DXT1;
+
+   case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
+      return MESA_FORMAT_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_FORMAT_RGBA_DXT1;
+      /* fall through */
+   case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
+      return MESA_FORMAT_RGBA_DXT5;
+
 /*
    case GL_COLOR_INDEX:
    case GL_COLOR_INDEX1_EXT:
@@ -601,7 +853,7 @@ savageChooseTextureFormat( GLcontext *ctx, GLint internalFormat,
 */
    default:
       _mesa_problem(ctx, "unexpected texture format in %s", __FUNCTION__);
-      return NULL;
+      return MESA_FORMAT_NONE;
    }
 }
 
@@ -610,40 +862,60 @@ static void savageSetTexImages( savageContextPtr imesa,
 {
    savageTexObjPtr t = (savageTexObjPtr) tObj->DriverData;
    struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel];
-   GLuint offset, i, textureFormat, size;
+   GLuint offset, i, textureFormat, tileIndex, size;
    GLint firstLevel, lastLevel;
 
    assert(t);
    assert(image);
 
-   switch (image->TexFormat->MesaFormat) {
+   switch (image->TexFormat) {
    case MESA_FORMAT_ARGB8888:
       textureFormat = TFT_ARGB8888;
-      t->texelBytes = 4;
+      t->texelBytes = tileIndex = 4;
       break;
    case MESA_FORMAT_ARGB1555:
       textureFormat = TFT_ARGB1555;
-      t->texelBytes = 2;
+      t->texelBytes = tileIndex = 2;
       break;
    case MESA_FORMAT_ARGB4444:
       textureFormat = TFT_ARGB4444;
-      t->texelBytes = 2;
+      t->texelBytes = tileIndex = 2;
       break;
    case MESA_FORMAT_RGB565:
       textureFormat = TFT_RGB565;
-      t->texelBytes = 2;
+      t->texelBytes = tileIndex = 2;
       break;
    case MESA_FORMAT_L8:
       textureFormat = TFT_L8;
-      t->texelBytes = 1;
+      t->texelBytes = tileIndex = 1;
       break;
    case MESA_FORMAT_I8:
       textureFormat = TFT_I8;
-      t->texelBytes = 1;
+      t->texelBytes = tileIndex = 1;
       break;
    case MESA_FORMAT_A8:
       textureFormat = TFT_A8;
-      t->texelBytes = 1;
+      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__);
@@ -651,11 +923,11 @@ static void savageSetTexImages( savageContextPtr imesa,
    }
    t->hwFormat = textureFormat;
 
-   /* Select tiling format depending on the chipset and bytes per texel */
+   /* Select tiling format depending on the chipset and texture format */
    if (imesa->savageScreen->chipset <= S3_SAVAGE4)
-       t->tileInfo = &tileInfo_s3d_s4[t->texelBytes];
+       t->tileInfo = &tileInfo_s3d_s4[tileIndex];
    else
-       t->tileInfo = &tileInfo_pro[t->texelBytes];
+       t->tileInfo = &tileInfo_pro[tileIndex];
 
    /* Compute which mipmap levels we really want to send to the hardware.
     */
@@ -687,8 +959,12 @@ static void savageSetTexImages( savageContextPtr imesa,
       t->image[i].offset = offset;
 
       image = tObj->Image[0][i];
-      size = savageTexImageSize (image->Width2, image->Height2,
-                                t->texelBytes);
+      if (t->texelBytes >= 8)
+        size = savageCompressedTexImageSize (image->Width2, image->Height2,
+                                             t->texelBytes);
+      else
+        size = savageTexImageSize (image->Width2, image->Height2,
+                                   t->texelBytes);
       offset += size;
    }
 
@@ -697,7 +973,7 @@ static void savageSetTexImages( savageContextPtr imesa,
    /* the last three mipmap levels don't add to the offset. They are packed
     * into 64 pixels. */
    if (size == 0)
-       t->base.totalSize += 64 * t->texelBytes;
+       t->base.totalSize += (t->texelBytes >= 8 ? 4 : 64) * t->texelBytes;
    /* 2k-aligned (really needed?) */
    t->base.totalSize = (t->base.totalSize + 2047UL) & ~2047UL;
 }
@@ -754,7 +1030,7 @@ static void savageUploadTexImages( savageContextPtr imesa, savageTexObjPtr t )
 
       ofs = t->base.memBlock->ofs;
       t->setup.physAddr = imesa->savageScreen->textureOffset[heap] + ofs;
-      t->bufAddr = (char *)((GLuint) imesa->savageScreen->texVirtual[heap] + ofs);
+      t->bufAddr = (GLubyte *)imesa->savageScreen->texVirtual[heap] + ofs;
       imesa->dirty |= SAVAGE_UPLOAD_GLOBAL; /* FIXME: really needed? */
    }
 
@@ -770,7 +1046,7 @@ static void savageUploadTexImages( savageContextPtr imesa, savageTexObjPtr t )
       /* 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) {
+      if (imesa->savageScreen->driScrnPriv->drm_version.minor >= 3) {
          unsigned int heap = t->base.heap->heapId;
          LOCK_HARDWARE(imesa);
          savageWaitEvent (imesa, imesa->textureHeaps[heap]->timestamp);
@@ -807,6 +1083,78 @@ static void savageUploadTexImages( savageContextPtr imesa, savageTexObjPtr t )
 }
 
 
+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 )
@@ -818,12 +1166,11 @@ static void savageUpdateTex0State_s4( GLcontext *ctx )
    GLuint format;
 
    /* disable */
-   if (ctx->Texture.Unit[0]._ReallyEnabled == 0) {
-      imesa->regs.s4.texDescr.ni.tex0En = GL_FALSE;
-      imesa->regs.s4.texBlendCtrl[0].ui = TBC_NoTexMap;
-      imesa->regs.s4.texCtrl[0].ui = 0x20f040;
+   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))
@@ -852,7 +1199,7 @@ static void savageUpdateTex0State_s4( GLcontext *ctx )
    
    driUpdateTextureLRU( &t->base );
 
-   format = tObj->Image[0][tObj->BaseLevel]->Format;
+   format = tObj->Image[0][tObj->BaseLevel]->_BaseFormat;
 
    switch (ctx->Texture.Unit[0].EnvMode) {
    case GL_REPLACE:
@@ -914,6 +1261,7 @@ static void savageUpdateTex0State_s4( GLcontext *ctx )
         break;
 
     case GL_BLEND:
+       imesa->regs.s4.texBlendColor.ui = imesa->texEnvColor;
 
         switch (format)
         {
@@ -983,12 +1331,28 @@ static void savageUpdateTex0State_s4( GLcontext *ctx )
                                      &imesa->regs.s4.texBlendCtrl[0]);
         break;
 
-        /*
-         GL_ADD
-        */
     case GL_ADD:
         imesa->regs.s4.texCtrl[0].ni.clrArg1Invert = GL_FALSE;
-        imesa->regs.s4.texBlendCtrl[0].ui = TBC_AddAlpha;
+        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;
@@ -1006,39 +1370,8 @@ static void savageUpdateTex0State_s4( GLcontext *ctx )
       break;                   
    }
 
-    imesa->regs.s4.texCtrl[0].ni.uMode =
-       t->setup.sWrapMode == GL_REPEAT ? 0 : 1;
-    imesa->regs.s4.texCtrl[0].ni.vMode = 
-       t->setup.tWrapMode == GL_REPEAT ? 0 : 1;
-
-    switch (t->setup.minFilter)
-    {
-        case GL_NEAREST:
-            imesa->regs.s4.texCtrl[0].ni.filterMode   = TFM_Point;
-            imesa->regs.s4.texCtrl[0].ni.mipmapEnable = GL_FALSE;
-            break;
-
-        case GL_LINEAR:
-            imesa->regs.s4.texCtrl[0].ni.filterMode   = TFM_Bilin;
-            imesa->regs.s4.texCtrl[0].ni.mipmapEnable = GL_FALSE;
-            break;
-
-        case GL_NEAREST_MIPMAP_NEAREST:
-            imesa->regs.s4.texCtrl[0].ni.filterMode   = TFM_Point;
-            imesa->regs.s4.texCtrl[0].ni.mipmapEnable = GL_TRUE;
-            break;
-
-        case GL_LINEAR_MIPMAP_NEAREST:
-            imesa->regs.s4.texCtrl[0].ni.filterMode   = TFM_Bilin;
-            imesa->regs.s4.texCtrl[0].ni.mipmapEnable = GL_TRUE;
-            break;
-
-        case GL_NEAREST_MIPMAP_LINEAR:
-        case GL_LINEAR_MIPMAP_LINEAR:
-            imesa->regs.s4.texCtrl[0].ni.filterMode   = TFM_Trilin;
-            imesa->regs.s4.texCtrl[0].ni.mipmapEnable = GL_TRUE;
-            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))
@@ -1062,7 +1395,7 @@ static void savageUpdateTex0State_s4( GLcontext *ctx )
     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;
+    imesa->regs.s4.texAddr[0].ui = (uint32_t) t->setup.physAddr | 0x2;
     if(t->base.heap->heapId == SAVAGE_AGP_HEAP)
        imesa->regs.s4.texAddr[0].ui |= 0x1;
     
@@ -1083,13 +1416,12 @@ static void savageUpdateTex1State_s4( GLcontext *ctx )
        return;
    }
 
-   if (ctx->Texture.Unit[1]._ReallyEnabled == 0) {
-      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;
+   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;
 
@@ -1120,7 +1452,7 @@ static void savageUpdateTex1State_s4( GLcontext *ctx )
    
    driUpdateTextureLRU( &t->base );
 
-   format = tObj->Image[0][tObj->BaseLevel]->Format;
+   format = tObj->Image[0][tObj->BaseLevel]->_BaseFormat;
 
    switch (ctx->Texture.Unit[1].EnvMode) {
    case GL_REPLACE:
@@ -1150,13 +1482,30 @@ static void savageUpdateTex1State_s4( GLcontext *ctx )
        __HWEnvCombineSingleUnitScale(imesa, 0, 1, &imesa->regs.s4.texBlendCtrl);
        break;
 
-/*#if GL_EXT_texture_env_add*/
     case GL_ADD:
         imesa->regs.s4.texCtrl[1].ni.clrArg1Invert = GL_FALSE;
-        imesa->regs.s4.texBlendCtrl[1].ui = TBC_AddAlpha1;
+        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;
-/*#endif*/
 
 #if GL_ARB_texture_env_combine
     case GL_COMBINE_ARB:
@@ -1203,45 +1552,14 @@ static void savageUpdateTex1State_s4( GLcontext *ctx )
       break;
 
    default:
-      fprintf(stderr, "unkown tex 1 env mode\n");
+      fprintf(stderr, "unknown tex 1 env mode\n");
       exit(1);
       break;                   
    }
 
-    imesa->regs.s4.texCtrl[1].ni.uMode =
-       t->setup.sWrapMode == GL_REPEAT ? 0 : 1;
-    imesa->regs.s4.texCtrl[1].ni.vMode =
-       t->setup.tWrapMode == GL_REPEAT ? 0 : 1;
+    savage4_set_wrap_mode( imesa, 1, t->setup.sWrapMode, t->setup.tWrapMode );
+    savage4_set_filter_mode( imesa, 1, t->setup.minFilter, t->setup.magFilter );
 
-    switch (t->setup.minFilter)
-    {
-        case GL_NEAREST:
-            imesa->regs.s4.texCtrl[1].ni.filterMode   = TFM_Point;
-            imesa->regs.s4.texCtrl[1].ni.mipmapEnable = GL_FALSE;
-            break;
-
-        case GL_LINEAR:
-            imesa->regs.s4.texCtrl[1].ni.filterMode   = TFM_Bilin;
-            imesa->regs.s4.texCtrl[1].ni.mipmapEnable = GL_FALSE;
-            break;
-
-        case GL_NEAREST_MIPMAP_NEAREST:
-            imesa->regs.s4.texCtrl[1].ni.filterMode   = TFM_Point;
-            imesa->regs.s4.texCtrl[1].ni.mipmapEnable = GL_TRUE;
-            break;
-
-        case GL_LINEAR_MIPMAP_NEAREST:
-            imesa->regs.s4.texCtrl[1].ni.filterMode   = TFM_Bilin;
-            imesa->regs.s4.texCtrl[1].ni.mipmapEnable = GL_TRUE;
-            break;
-
-        case GL_NEAREST_MIPMAP_LINEAR:
-        case GL_LINEAR_MIPMAP_LINEAR:
-            imesa->regs.s4.texCtrl[1].ni.filterMode   = TFM_Trilin;
-            imesa->regs.s4.texCtrl[1].ni.mipmapEnable = GL_TRUE;
-            break;
-    }
-    
     if((ctx->Texture.Unit[1].LodBias !=0.0F) ||
        (imesa->regs.s4.texCtrl[1].ni.dBias != 0))
     {
@@ -1262,7 +1580,7 @@ static void savageUpdateTex1State_s4( GLcontext *ctx )
     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;
+    imesa->regs.s4.texAddr[1].ui = (uint32_t) t->setup.physAddr | 2;
     if(t->base.heap->heapId == SAVAGE_AGP_HEAP)
        imesa->regs.s4.texAddr[1].ui |= 0x1;
 }
@@ -1275,13 +1593,12 @@ static void savageUpdateTexState_s3d( GLcontext *ctx )
     GLuint format;
 
     /* disable */
-    if (ctx->Texture.Unit[0]._ReallyEnabled == 0) {
-       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;
+    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))
@@ -1309,37 +1626,52 @@ static void savageUpdateTexState_s3d( GLcontext *ctx )
 
     driUpdateTextureLRU( &t->base );
 
-    format = tObj->Image[0][tObj->BaseLevel]->Format;
+    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_DECAL_S3D;
+       imesa->regs.s3d.drawCtrl.ni.texBlendCtrl = SAVAGETBC_DECALALPHA_S3D;
        break;
     case GL_REPLACE:
-       imesa->regs.s3d.drawCtrl.ni.texBlendCtrl = SAVAGETBC_COPY_S3D;
+       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: /* FIXIT */
+    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, "unkown tex env mode\n");
+       fprintf(stderr, "unknown tex env mode\n");
        /*exit(1);*/
        break;                  
     }
 
-    imesa->regs.s3d.drawCtrl.ni.flushPdDestWrites = GL_TRUE;
-    imesa->regs.s3d.drawCtrl.ni.flushPdZbufWrites = GL_TRUE;
-
-    /* FIXME: this is how the utah-driver works. I doubt it's the ultimate 
-       truth. */
+    /* 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;
-    if (t->setup.sWrapMode == GL_CLAMP)
-       imesa->regs.s3d.texCtrl.ni.wrapMode = TAM_Clamp;
-    else
-       imesa->regs.s3d.texCtrl.ni.wrapMode = TAM_Wrap;
+    imesa->regs.s3d.texCtrl.ni.wrapMode =
+       (t->setup.sWrapMode == GL_REPEAT) ? TAM_Wrap : TAM_Clamp;
 
     switch (t->setup.minFilter) {
     case GL_NEAREST:
@@ -1399,7 +1731,7 @@ static void savageUpdateTexState_s3d( GLcontext *ctx )
     assert (t->hwFormat <= 7);
     imesa->regs.s3d.texDescr.ni.texFmt = t->hwFormat;
 
-    imesa->regs.s3d.texAddr.ui = (u_int32_t) t->setup.physAddr | 2;
+    imesa->regs.s3d.texAddr.ui = (uint32_t) t->setup.physAddr | 2;
     if(t->base.heap->heapId == SAVAGE_AGP_HEAP)
        imesa->regs.s3d.texAddr.ui |= 0x1;
 }
@@ -1411,7 +1743,7 @@ static void savageTimestampTextures( savageContextPtr imesa )
     * 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) {
+       imesa->savageScreen->driScrnPriv->drm_version.minor >= 3) {
        unsigned int e;
        FLUSH_BATCH(imesa);
        e = savageEmitEvent(imesa, SAVAGE_WAIT_3D);
@@ -1497,16 +1829,14 @@ static void savageTexEnv( GLcontext *ctx, GLenum target,
       struct gl_texture_unit *texUnit = 
         &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
       const GLfloat *fc = texUnit->EnvColor;
-      GLuint r, g, b, a, col;
+      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]);
 
-      col = ((a << 24) | 
-            (r << 16) | 
-            (g <<  8) | 
-            (b <<  0));
+      imesa->texEnvColor = ((a << 24) | (r << 16) | 
+                           (g <<  8) | (b <<  0));
     
 
    } 
@@ -1640,6 +1970,63 @@ static void savageTexSubImage2D( GLcontext *ctx,
    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 )
@@ -1662,7 +2049,7 @@ static void savageTexParameter( GLcontext *ctx, GLenum target,
       break;
   
    case GL_TEXTURE_BORDER_COLOR:
-      savageSetTexBorderColor(t,tObj->_BorderChan);
+      savageSetTexBorderColor(t,tObj->BorderColor);
       break;
 
    default:
@@ -1717,9 +2104,29 @@ void savageDDInitTextureFuncs( struct dd_function_table *functions )
    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. */
+#if 0
+   _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;
+#endif
 }