mesa: Don't expose compressed paletted formats via GL_{NUM_,}COMPRESSED_TEXTURE_FORMATS
[mesa.git] / src / mesa / main / texcompress.c
index c1b8c7675a27be612bf0d81451381efa68807941..03e05d5ef7b02a8d0dbc16346a0f31f0623b676d 100644 (file)
 #include "glheader.h"
 #include "imports.h"
 #include "colormac.h"
-#include "context.h"
-#include "image.h"
-#include "mipmap.h"
+#include "formats.h"
+#include "mfeatures.h"
+#include "mtypes.h"
 #include "texcompress.h"
-#include "texformat.h"
-#include "texstore.h"
+#include "texcompress_fxt1.h"
+#include "texcompress_rgtc.h"
+#include "texcompress_s3tc.h"
+#include "swrast/s_context.h"
 
 
+/**
+ * Get the GL base format of a specified GL compressed texture format
+ *
+ * From page 232 of the OpenGL 3.3 (Compatiblity Profile) spec:
+ *
+ *     "Compressed Internal Format      Base Internal Format    Type
+ *     ---------------------------     --------------------    ---------
+ *     COMPRESSED_ALPHA                ALPHA                   Generic
+ *     COMPRESSED_LUMINANCE            LUMINANCE               Generic
+ *     COMPRESSED_LUMINANCE_ALPHA      LUMINANCE_ALPHA         Generic
+ *     COMPRESSED_INTENSITY            INTENSITY               Generic
+ *     COMPRESSED_RED                  RED                     Generic
+ *     COMPRESSED_RG                   RG                      Generic
+ *     COMPRESSED_RGB                  RGB                     Generic
+ *     COMPRESSED_RGBA                 RGBA                    Generic
+ *     COMPRESSED_SRGB                 RGB                     Generic
+ *     COMPRESSED_SRGB_ALPHA           RGBA                    Generic
+ *     COMPRESSED_SLUMINANCE           LUMINANCE               Generic
+ *     COMPRESSED_SLUMINANCE_ALPHA     LUMINANCE_ALPHA         Generic
+ *     COMPRESSED_RED_RGTC1            RED                     Specific
+ *     COMPRESSED_SIGNED_RED_RGTC1     RED                     Specific
+ *     COMPRESSED_RG_RGTC2             RG                      Specific
+ *     COMPRESSED_SIGNED_RG_RGTC2      RG                      Specific"
+ *
+ * \return
+ * The base format of \c format if \c format is a compressed format (either
+ * generic or specific.  Otherwise 0 is returned.
+ */
+GLenum
+_mesa_gl_compressed_format_base_format(GLenum format)
+{
+   switch (format) {
+   case GL_COMPRESSED_RED:
+   case GL_COMPRESSED_RED_RGTC1:
+   case GL_COMPRESSED_SIGNED_RED_RGTC1:
+      return GL_RED;
+
+   case GL_COMPRESSED_RG:
+   case GL_COMPRESSED_RG_RGTC2:
+   case GL_COMPRESSED_SIGNED_RG_RGTC2:
+      return GL_RG;
+
+   case GL_COMPRESSED_RGB:
+   case GL_COMPRESSED_SRGB:
+   case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
+   case GL_COMPRESSED_RGB_FXT1_3DFX:
+   case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT:
+      return GL_RGB;
+
+   case GL_COMPRESSED_RGBA:
+   case GL_COMPRESSED_SRGB_ALPHA:
+   case GL_COMPRESSED_RGBA_BPTC_UNORM_ARB:
+   case GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB:
+   case GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB:
+   case GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB:
+   case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
+   case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
+   case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
+   case GL_COMPRESSED_RGBA_FXT1_3DFX:
+   case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT:
+   case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT:
+   case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT:
+      return GL_RGBA;
+
+   case GL_COMPRESSED_ALPHA:
+      return GL_ALPHA;
+
+   case GL_COMPRESSED_LUMINANCE:
+   case GL_COMPRESSED_SLUMINANCE:
+   case GL_COMPRESSED_LUMINANCE_LATC1_EXT:
+   case GL_COMPRESSED_SIGNED_LUMINANCE_LATC1_EXT:
+      return GL_LUMINANCE;
+
+   case GL_COMPRESSED_LUMINANCE_ALPHA:
+   case GL_COMPRESSED_SLUMINANCE_ALPHA:
+   case GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT:
+   case GL_COMPRESSED_SIGNED_LUMINANCE_ALPHA_LATC2_EXT:
+   case GL_COMPRESSED_LUMINANCE_ALPHA_3DC_ATI:
+      return GL_LUMINANCE_ALPHA;
+
+   case GL_COMPRESSED_INTENSITY:
+      return GL_INTENSITY;
+
+   default:
+      return 0;
+   }
+}
+
 /**
  * Return list of (and count of) all specific texture compression
  * formats that are supported.
  *
+ * Some formats are \b not returned by this function.  The
+ * \c GL_COMPRESSED_TEXTURE_FORMATS query only returns formats that are
+ * "suitable for general-purpose usage."  All texture compression extensions
+ * have taken this to mean either linear RGB or linear RGBA.
+ *
+ * The GL_ARB_texture_compress_rgtc spec says:
+ *
+ *    "19) Should the GL_NUM_COMPRESSED_TEXTURE_FORMATS and
+ *        GL_COMPRESSED_TEXTURE_FORMATS queries return the RGTC formats?
+ *
+ *        RESOLVED:  No.
+ *
+ *        The OpenGL 2.1 specification says "The only values returned
+ *        by this query [GL_COMPRESSED_TEXTURE_FORMATS"] are those
+ *        corresponding to formats suitable for general-purpose usage.
+ *        The renderer will not enumerate formats with restrictions that
+ *        need to be specifically understood prior to use."
+ *
+ *        Compressed textures with just red or red-green components are
+ *        not general-purpose so should not be returned by these queries
+ *        because they have restrictions.
+ *
+ *        Applications that seek to use the RGTC formats should do so
+ *        by looking for this extension's name in the string returned by
+ *        glGetString(GL_EXTENSIONS) rather than
+ *        what GL_NUM_COMPRESSED_TEXTURE_FORMATS and
+ *        GL_COMPRESSED_TEXTURE_FORMATS return."
+ *
+ * There is nearly identical wording in the GL_EXT_texture_compression_rgtc
+ * spec.
+ *
+ * The GL_EXT_texture_rRGB spec says:
+ *
+ *    "22) Should the new COMPRESSED_SRGB_* formats be listed in an
+ *        implementation's GL_COMPRESSED_TEXTURE_FORMATS list?
+ *
+ *        RESOLVED:  No.  Section 3.8.1 says formats listed by
+ *        GL_COMPRESSED_TEXTURE_FORMATS are "suitable for general-purpose
+ *        usage."  The non-linear distribution of red, green, and
+ *        blue for these sRGB compressed formats makes them not really
+ *        general-purpose."
+ *
+ * The GL_EXT_texture_compression_latc spec says:
+ *
+ *    "16) Should the GL_NUM_COMPRESSED_TEXTURE_FORMATS and
+ *        GL_COMPRESSED_TEXTURE_FORMATS queries return the LATC formats?
+ *
+ *        RESOLVED:  No.
+ *
+ *        The OpenGL 2.1 specification says "The only values returned
+ *        by this query [GL_COMPRESSED_TEXTURE_FORMATS"] are those
+ *        corresponding to formats suitable for general-purpose usage.
+ *        The renderer will not enumerate formats with restrictions that
+ *        need to be specifically understood prior to use."
+ *
+ *        Historically, OpenGL implementation have advertised the RGB and
+ *        RGBA versions of the S3TC extensions compressed format tokens
+ *        through this mechanism.
+ *
+ *        The specification is not sufficiently clear about what "suitable
+ *        for general-purpose usage" means.  Historically that seems to mean
+ *        unsigned RGB or unsigned RGBA.  The DXT1 format supporting alpha
+ *        (GL_COMPRESSED_RGBA_S3TC_DXT1_EXT) is not exposed in the list (at
+ *        least for NVIDIA drivers) because the alpha is always 1.0 expect
+ *        when it is 0.0 when RGB is required to be black.  NVIDIA's even
+ *        limits itself to true linear RGB or RGBA formats, specifically
+ *        not including EXT_texture_sRGB's sRGB S3TC compressed formats.
+ *
+ *        Adding luminance and luminance-alpha texture formats (and
+ *        certainly signed versions of luminance and luminance-alpha
+ *        formats!) invites potential comptaibility problems with old
+ *        applications using this mechanism since old applications are
+ *        unlikely to expect non-RGB or non-RGBA formats to be advertised
+ *        through this mechanism.  However no specific misinteractions
+ *        with old applications is known.
+ *
+ *        Applications that seek to use the LATC formats should do so
+ *        by looking for this extension's name in the string returned by
+ *        glGetString(GL_EXTENSIONS) rather than
+ *        what GL_NUM_COMPRESSED_TEXTURE_FORMATS and
+ *        GL_COMPRESSED_TEXTURE_FORMATS return."
+ *
+ * There is no formal spec for GL_ATI_texture_compression_3dc.  Since the
+ * formats added by this extension are luminance-alpha formats, it is
+ * reasonable to expect them to follow the same rules as
+ * GL_EXT_texture_compression_latc.  At the very least, Catalyst 11.6 does not
+ * expose the 3dc formats through this mechanism.
+ *
  * \param ctx  the GL context
  * \param formats  the resulting format list (may be NULL).
- * \param all  if true return all formats, even those with  some kind
- *             of restrictions/limitations (See GL_ARB_texture_compression
- *             spec for more info).
  *
  * \return number of formats.
  */
 GLuint
-_mesa_get_compressed_formats(GLcontext *ctx, GLint *formats, GLboolean all)
+_mesa_get_compressed_formats(struct gl_context *ctx, GLint *formats)
 {
    GLuint n = 0;
    if (ctx->Extensions.TDFX_texture_compression_FXT1) {
@@ -66,23 +241,15 @@ _mesa_get_compressed_formats(GLcontext *ctx, GLint *formats, GLboolean all)
          n += 2;
       }
    }
+
    if (ctx->Extensions.EXT_texture_compression_s3tc) {
       if (formats) {
          formats[n++] = GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
-         /* This format has some restrictions/limitations and so should
-          * not be returned via the GL_COMPRESSED_TEXTURE_FORMATS query.
-          * Specifically, all transparent pixels become black.  NVIDIA
-          * omits this format too.
-          */
-         if (all)
-             formats[n++] = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
          formats[n++] = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
          formats[n++] = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
       }
       else {
          n += 3;
-         if (all)
-             n += 1;
       }
    }
    if (ctx->Extensions.S3_s3tc) {
@@ -96,267 +263,267 @@ _mesa_get_compressed_formats(GLcontext *ctx, GLint *formats, GLboolean all)
          n += 4;
       }
    }
-#if FEATURE_EXT_texture_sRGB
-   if (ctx->Extensions.EXT_texture_sRGB) {
+
+#if FEATURE_ES1
+   if (ctx->API == API_OPENGLES) {
       if (formats) {
-         formats[n++] = GL_COMPRESSED_SRGB_S3TC_DXT1_EXT;
-         formats[n++] = GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT;
-         formats[n++] = GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT;
-         formats[n++] = GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT;
+        formats[n++] = GL_PALETTE4_RGB8_OES;
+        formats[n++] = GL_PALETTE4_RGBA8_OES;
+        formats[n++] = GL_PALETTE4_R5_G6_B5_OES;
+        formats[n++] = GL_PALETTE4_RGBA4_OES;
+        formats[n++] = GL_PALETTE4_RGB5_A1_OES;
+        formats[n++] = GL_PALETTE8_RGB8_OES;
+        formats[n++] = GL_PALETTE8_RGBA8_OES;
+        formats[n++] = GL_PALETTE8_R5_G6_B5_OES;
+        formats[n++] = GL_PALETTE8_RGBA4_OES;
+        formats[n++] = GL_PALETTE8_RGB5_A1_OES;
       }
       else {
-         n += 4;
+        n += 10;
       }
    }
-#endif /* FEATURE_EXT_texture_sRGB */
+#endif
+
    return n;
 }
 
 
-
 /**
- * Return number of bytes needed to store a texture of the given size
- * using the specified compressed format.
- * This is called via the ctx->Driver.CompressedTextureSize function,
- * unless a device driver overrides it.
- *
- * \param width texture width in texels.
- * \param height texture height in texels.
- * \param depth texture depth in texels.
- * \param mesaFormat  one of the MESA_FORMAT_* compressed formats
- *
- * \return size in bytes, or zero if bad format
+ * Convert a compressed MESA_FORMAT_x to a GLenum.
  */
-GLuint
-_mesa_compressed_texture_size( GLcontext *ctx,
-                               GLsizei width, GLsizei height, GLsizei depth,
-                               GLuint mesaFormat )
+gl_format
+_mesa_glenum_to_compressed_format(GLenum format)
 {
-   GLuint size;
-
-   ASSERT(depth == 1);
-   (void) depth;
-   (void) size;
-
-   switch (mesaFormat) {
-#if FEATURE_texture_fxt1
-   case MESA_FORMAT_RGB_FXT1:
-   case MESA_FORMAT_RGBA_FXT1:
-      /* round up width to next multiple of 8, height to next multiple of 4 */
-      width = (width + 7) & ~7;
-      height = (height + 3) & ~3;
-      /* 16 bytes per 8x4 tile of RGB[A] texels */
-      size = width * height / 2;
-      /* Textures smaller than 8x4 will effectively be made into 8x4 and
-       * take 16 bytes.
-       */
-      return size;
-#endif
-#if FEATURE_texture_s3tc
-   case MESA_FORMAT_RGB_DXT1:
-   case MESA_FORMAT_RGBA_DXT1:
-#if FEATURE_EXT_texture_sRGB
-   case MESA_FORMAT_SRGB_DXT1:
-   case MESA_FORMAT_SRGBA_DXT1:
-#endif
-      /* round up width, height to next multiple of 4 */
-      width = (width + 3) & ~3;
-      height = (height + 3) & ~3;
-      /* 8 bytes per 4x4 tile of RGB[A] texels */
-      size = width * height / 2;
-      /* Textures smaller than 4x4 will effectively be made into 4x4 and
-       * take 8 bytes.
-       */
-      return size;
-   case MESA_FORMAT_RGBA_DXT3:
-   case MESA_FORMAT_RGBA_DXT5:
-#if FEATURE_EXT_texture_sRGB
-   case MESA_FORMAT_SRGBA_DXT3:
-   case MESA_FORMAT_SRGBA_DXT5:
-#endif
-      /* round up width, height to next multiple of 4 */
-      width = (width + 3) & ~3;
-      height = (height + 3) & ~3;
-      /* 16 bytes per 4x4 tile of RGBA texels */
-      size = width * height; /* simple! */
-      /* Textures smaller than 4x4 will effectively be made into 4x4 and
-       * take 16 bytes.
-       */
-      return size;
-#endif
-   default:
-      _mesa_problem(ctx, "bad mesaFormat in _mesa_compressed_texture_size");
-      return 0;
-   }
-}
-
-
-/**
- * As above, but format is specified by a GLenum (GL_COMPRESSED_*) token.
- *
- * Note: This function CAN NOT return a padded hardware texture size.
- * That's why we don't call the ctx->Driver.CompressedTextureSize() function.
- *
- * We use this function to validate the <imageSize> parameter
- * of glCompressedTex[Sub]Image1/2/3D(), which must be an exact match.
- */
-GLuint
-_mesa_compressed_texture_size_glenum(GLcontext *ctx,
-                                     GLsizei width, GLsizei height,
-                                     GLsizei depth, GLenum glformat)
-{
-   GLuint mesaFormat;
-
-   switch (glformat) {
-#if FEATURE_texture_fxt1
+   switch (format) {
    case GL_COMPRESSED_RGB_FXT1_3DFX:
-      mesaFormat = MESA_FORMAT_RGB_FXT1;
-      break;
+      return MESA_FORMAT_RGB_FXT1;
    case GL_COMPRESSED_RGBA_FXT1_3DFX:
-      mesaFormat = MESA_FORMAT_RGBA_FXT1;
-      break;
-#endif
-#if FEATURE_texture_s3tc
+      return MESA_FORMAT_RGBA_FXT1;
+
    case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
    case GL_RGB_S3TC:
-      mesaFormat = MESA_FORMAT_RGB_DXT1;
-      break;
+      return MESA_FORMAT_RGB_DXT1;
    case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
    case GL_RGB4_S3TC:
-      mesaFormat = MESA_FORMAT_RGBA_DXT1;
-      break;
+      return MESA_FORMAT_RGBA_DXT1;
    case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
    case GL_RGBA_S3TC:
-      mesaFormat = MESA_FORMAT_RGBA_DXT3;
-      break;
+      return MESA_FORMAT_RGBA_DXT3;
    case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
    case GL_RGBA4_S3TC:
-      mesaFormat = MESA_FORMAT_RGBA_DXT5;
-      break;
-#if FEATURE_EXT_texture_sRGB
+      return MESA_FORMAT_RGBA_DXT5;
+
    case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT:
-      mesaFormat = MESA_FORMAT_SRGB_DXT1;
-      break;
+      return MESA_FORMAT_SRGB_DXT1;
    case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT:
-      mesaFormat = MESA_FORMAT_SRGBA_DXT1;
-      break;
+      return MESA_FORMAT_SRGBA_DXT1;
    case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT:
-      mesaFormat = MESA_FORMAT_SRGBA_DXT3;
-      break;
+      return MESA_FORMAT_SRGBA_DXT3;
    case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT:
-      mesaFormat = MESA_FORMAT_SRGBA_DXT5;
-      break;
-#endif
-#endif
+      return MESA_FORMAT_SRGBA_DXT5;
+
+   case GL_COMPRESSED_RED_RGTC1:
+      return MESA_FORMAT_RED_RGTC1;
+   case GL_COMPRESSED_SIGNED_RED_RGTC1:
+      return MESA_FORMAT_SIGNED_RED_RGTC1;
+   case GL_COMPRESSED_RG_RGTC2:
+      return MESA_FORMAT_RG_RGTC2;
+   case GL_COMPRESSED_SIGNED_RG_RGTC2:
+      return MESA_FORMAT_SIGNED_RG_RGTC2;
+
+   case GL_COMPRESSED_LUMINANCE_LATC1_EXT:
+      return MESA_FORMAT_L_LATC1;
+   case GL_COMPRESSED_SIGNED_LUMINANCE_LATC1_EXT:
+      return MESA_FORMAT_SIGNED_L_LATC1;
+   case GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT:
+   case GL_COMPRESSED_LUMINANCE_ALPHA_3DC_ATI:
+      return MESA_FORMAT_LA_LATC2;
+   case GL_COMPRESSED_SIGNED_LUMINANCE_ALPHA_LATC2_EXT:
+      return MESA_FORMAT_SIGNED_LA_LATC2;
+
    default:
-      return 0;
+      return MESA_FORMAT_NONE;
    }
-
-   return _mesa_compressed_texture_size(ctx, width, height, depth, mesaFormat);
 }
 
 
-/*
- * Compute the bytes per row in a compressed texture image.
- * We use this for computing the destination address for sub-texture updates.
- * \param mesaFormat  one of the MESA_FORMAT_* compressed formats
- * \param width  image width in pixels
- * \return stride, in bytes, between rows for compressed image
+/**
+ * Given a compressed MESA_FORMAT_x value, return the corresponding
+ * GLenum for that format.
+ * This is needed for glGetTexLevelParameter(GL_TEXTURE_INTERNAL_FORMAT)
+ * which must return the specific texture format used when the user might
+ * have originally specified a generic compressed format in their
+ * glTexImage2D() call.
+ * For non-compressed textures, we always return the user-specified
+ * internal format unchanged.
  */
-GLint
-_mesa_compressed_row_stride(GLuint mesaFormat, GLsizei width)
+GLenum
+_mesa_compressed_format_to_glenum(struct gl_context *ctx, GLuint mesaFormat)
 {
-   GLint stride;
-
    switch (mesaFormat) {
 #if FEATURE_texture_fxt1
    case MESA_FORMAT_RGB_FXT1:
+      return GL_COMPRESSED_RGB_FXT1_3DFX;
    case MESA_FORMAT_RGBA_FXT1:
-      stride = ((width + 7) / 8) * 16; /* 16 bytes per 8x4 tile */
-      break;
+      return GL_COMPRESSED_RGBA_FXT1_3DFX;
 #endif
 #if FEATURE_texture_s3tc
    case MESA_FORMAT_RGB_DXT1:
+      return GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
    case MESA_FORMAT_RGBA_DXT1:
-#if FEATURE_EXT_texture_sRGB
-   case MESA_FORMAT_SRGB_DXT1:
-   case MESA_FORMAT_SRGBA_DXT1:
-#endif
-      stride = ((width + 3) / 4) * 8; /* 8 bytes per 4x4 tile */
-      break;
+      return GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
    case MESA_FORMAT_RGBA_DXT3:
+      return GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
    case MESA_FORMAT_RGBA_DXT5:
+      return GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
 #if FEATURE_EXT_texture_sRGB
+   case MESA_FORMAT_SRGB_DXT1:
+      return GL_COMPRESSED_SRGB_S3TC_DXT1_EXT;
+   case MESA_FORMAT_SRGBA_DXT1:
+      return GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT;
    case MESA_FORMAT_SRGBA_DXT3:
+      return GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT;
    case MESA_FORMAT_SRGBA_DXT5:
+      return GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT;
 #endif
-      stride = ((width + 3) / 4) * 16; /* 16 bytes per 4x4 tile */
-      break;
 #endif
+
+   case MESA_FORMAT_RED_RGTC1:
+      return GL_COMPRESSED_RED_RGTC1;
+   case MESA_FORMAT_SIGNED_RED_RGTC1:
+      return GL_COMPRESSED_SIGNED_RED_RGTC1;
+   case MESA_FORMAT_RG_RGTC2:
+      return GL_COMPRESSED_RG_RGTC2;
+   case MESA_FORMAT_SIGNED_RG_RGTC2:
+      return GL_COMPRESSED_SIGNED_RG_RGTC2;
+
+   case MESA_FORMAT_L_LATC1:
+      return GL_COMPRESSED_LUMINANCE_LATC1_EXT;
+   case MESA_FORMAT_SIGNED_L_LATC1:
+      return GL_COMPRESSED_SIGNED_LUMINANCE_LATC1_EXT;
+   case MESA_FORMAT_LA_LATC2:
+      return GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT;
+   case MESA_FORMAT_SIGNED_LA_LATC2:
+      return GL_COMPRESSED_SIGNED_LUMINANCE_ALPHA_LATC2_EXT;
+
    default:
-      _mesa_problem(NULL, "bad mesaFormat in _mesa_compressed_row_stride");
+      _mesa_problem(ctx, "Unexpected mesa texture format in"
+                    " _mesa_compressed_format_to_glenum()");
       return 0;
    }
-
-   return stride;
 }
 
 
 /*
  * Return the address of the pixel at (col, row, img) in a
  * compressed texture image.
- * \param col, row, img - image position (3D)
+ * \param col, row, img - image position (3D), should be a multiple of the
+ *                        format's block size.
  * \param format - compressed image format
- * \param width - image width
+ * \param width - image width (stride) in pixels
  * \param image - the image address
- * \return address of pixel at (row, col)
+ * \return address of pixel at (row, col, img)
  */
 GLubyte *
 _mesa_compressed_image_address(GLint col, GLint row, GLint img,
-                               GLuint mesaFormat,
+                               gl_format mesaFormat,
                                GLsizei width, const GLubyte *image)
 {
-   GLubyte *addr;
+   /* XXX only 2D images implemented, not 3D */
+   const GLuint blockSize = _mesa_get_format_bytes(mesaFormat);
+   GLuint bw, bh;
+   GLint offset;
 
-   (void) img;
+   _mesa_get_format_block_size(mesaFormat, &bw, &bh);
 
-   /* We try to spot a "complete" subtexture "above" ROW, COL;
-    * this texture is given by appropriate rounding of WIDTH x ROW.
-    * Then we just add the amount left (usually on the left).
-    *
-    * Example for X*Y microtiles (Z bytes each)
-    * offset = Z * (((width + X - 1) / X) * (row / Y) + col / X);
-    */
+   ASSERT(col % bw == 0);
+   ASSERT(row % bh == 0);
 
-   switch (mesaFormat) {
-#if FEATURE_texture_fxt1
-   case MESA_FORMAT_RGB_FXT1:
-   case MESA_FORMAT_RGBA_FXT1:
-      addr = (GLubyte *) image + 16 * (((width + 7) / 8) * (row / 4) + col / 8);
-      break;
-#endif
-#if FEATURE_texture_s3tc
+   offset = ((width + bw - 1) / bw) * (row / bh) + col / bw;
+   offset *= blockSize;
+
+   return (GLubyte *) image + offset;
+}
+
+
+/**
+ * Decompress a compressed texture image, returning a GL_RGBA/GL_FLOAT image.
+ */
+void
+_mesa_decompress_image(gl_format format, GLuint width, GLuint height,
+                       const GLubyte *src, GLint srcRowStride,
+                       GLfloat *dest)
+{
+   void (*fetch)(const struct swrast_texture_image *texImage,
+                 GLint i, GLint j, GLint k, GLfloat *texel);
+   struct swrast_texture_image texImage;  /* dummy teximage */
+   GLuint i, j;
+
+   /* setup dummy texture image info */
+   memset(&texImage, 0, sizeof(texImage));
+   texImage.Base.Data = (void *) src;
+   texImage.Base.RowStride = srcRowStride;
+
+   switch (format) {
+   /* DXT formats */
    case MESA_FORMAT_RGB_DXT1:
+      fetch = _mesa_fetch_texel_2d_f_rgb_dxt1;
+      break;
    case MESA_FORMAT_RGBA_DXT1:
-#if FEATURE_EXT_texture_sRGB
-   case MESA_FORMAT_SRGB_DXT1:
-   case MESA_FORMAT_SRGBA_DXT1:
-#endif
-      addr = (GLubyte *) image + 8 * (((width + 3) / 4) * (row / 4) + col / 4);
+      fetch = _mesa_fetch_texel_2d_f_rgba_dxt1;
       break;
    case MESA_FORMAT_RGBA_DXT3:
+      fetch = _mesa_fetch_texel_2d_f_rgba_dxt3;
+      break;
    case MESA_FORMAT_RGBA_DXT5:
-#if FEATURE_EXT_texture_sRGB
-   case MESA_FORMAT_SRGBA_DXT3:
-   case MESA_FORMAT_SRGBA_DXT5:
-#endif
-      addr = (GLubyte *) image + 16 * (((width + 3) / 4) * (row / 4) + col / 4);
+      fetch = _mesa_fetch_texel_2d_f_rgba_dxt5;
       break;
-#endif
+
+   /* FXT1 formats */
+   case MESA_FORMAT_RGB_FXT1:
+      fetch = _mesa_fetch_texel_2d_f_rgb_fxt1;
+      break;
+   case MESA_FORMAT_RGBA_FXT1:
+      fetch = _mesa_fetch_texel_2d_f_rgba_fxt1;
+      break;
+
+   /* Red/RG formats */
+   case MESA_FORMAT_RED_RGTC1:
+      fetch = _mesa_fetch_texel_2d_f_red_rgtc1;
+      break;
+   case MESA_FORMAT_SIGNED_RED_RGTC1:
+      fetch = _mesa_fetch_texel_2d_f_signed_red_rgtc1;
+      break;
+   case MESA_FORMAT_RG_RGTC2:
+      fetch = _mesa_fetch_texel_2d_f_rg_rgtc2;
+      break;
+   case MESA_FORMAT_SIGNED_RG_RGTC2:
+      fetch = _mesa_fetch_texel_2d_f_signed_rg_rgtc2;
+      break;
+
+   /* L/LA formats */
+   case MESA_FORMAT_L_LATC1:
+      fetch = _mesa_fetch_texel_2d_f_l_latc1;
+      break;
+   case MESA_FORMAT_SIGNED_L_LATC1:
+      fetch = _mesa_fetch_texel_2d_f_signed_l_latc1;
+      break;
+   case MESA_FORMAT_LA_LATC2:
+      fetch = _mesa_fetch_texel_2d_f_la_latc2;
+      break;
+   case MESA_FORMAT_SIGNED_LA_LATC2:
+      fetch = _mesa_fetch_texel_2d_f_signed_la_latc2;
+      break;
+
    default:
-      _mesa_problem(NULL, "bad mesaFormat in _mesa_compressed_image_address");
-      addr = NULL;
+      _mesa_problem(NULL, "Unexpected format in _mesa_decompress_image()");
+      return;
    }
 
-   return addr;
+   for (j = 0; j < height; j++) {
+      for (i = 0; i < width; i++) {
+         fetch(&texImage, i, j, 0, dest);
+         dest += 4;
+      }
+   }
 }