There's also a quick hack for software mesa (the fetch texel functions) should an app ever hit a fallback for texturing (tested with the gimp dds plugin which uses OGL to read .dds files though this plugin has some bugs and just fails to read a lot of .dds files for some reason, but that's another topic - other than that it seems to work). It's just a straight implementation taken from the extension registry (http://oss.sgi.com/projects/ogl-sample/registry/EXT/texture_compression_s3tc.txt). Due to the fishy IP status, all relevant parts are #ifdefed out (lots of projects have potentially patent infringing code in their projects and just don't enable it per default when building, for instance the hinting stuff (which is now almost obsolete AFAIK) in the freetype library).
Issues:
Not sure if hardware decompression of all DXT formats works correctly (especially unsure about RGBA_DXT1). Unfortunately I couldn't find a simple test program which uses precompressed textures (there are some half-useful example programs which read and display .dds files for windows, seemed to work with wine).
No compression of textures (and thus mipmaps, though I'm unsure if auto mipmapping is supported for CompressedTexSubImage2D - don't think so, apps which use compressed textures always seem to supply all their mipmaps themselves so this shouldn't be too much of a problem). This means games such as QuakeIII which don't use precompressed textures won't benefit at all obviously. Compression is of course more complicated than decompression, and I don't know if any open-source compressors exist which could easily be included in mesa (black box games have released such a compressor as source, you can download it at nvidia - the nvidia license wouldn't allow its use, I have no idea what the original license was). Of course someone could write a compressor...
What works:
nwn, ut2k3 demo seem to use compressed textures just happily. Probably all games which use precompressed textures (likely a lot of new games) should work.
Index: texcompress.c =================================================================== RCS file: /cvsroot/mesa3d/Mesa-newtree/src/mesa/main/texcompress.c,v retrieving revision 1.9 diff -u -r1.9 texcompress.c --- texcompress.c 21 Nov 2003 09:56:50 -0000 1.9 +++ texcompress.c 18 Dec 2003 00:54:43 -0000 @@ -59,6 +59,9 @@ } } if (ctx->Extensions.EXT_texture_compression_s3tc) { + /* quick hack. don't announce s3tc formats, hopefully noone then will try to + compress textures despite having the s3tc extension */ +#if !MESA_S3TC if (formats) { formats[n++] = GL_COMPRESSED_RGB_S3TC_DXT1_EXT; /* Skip this one because it has a restriction (all transparent @@ -72,6 +75,7 @@ else { n += 3; } +#endif } if (ctx->Extensions.S3_s3tc) { if (formats) { Index: texformat.h =================================================================== RCS file: /cvsroot/mesa3d/Mesa-newtree/src/mesa/main/texformat.h,v retrieving revision 1.16 diff -u -r1.16 texformat.h --- texformat.h 29 Oct 2003 14:35:32 -0000 1.16 +++ texformat.h 18 Dec 2003 00:54:44 -0000 @@ -35,6 +35,8 @@ #include "mtypes.h" +#define MESA_S3TC 0 + /** * Mesa internal texture image types. Index: texformat_tmp.h =================================================================== RCS file: /cvsroot/mesa3d/Mesa-newtree/src/mesa/main/texformat_tmp.h,v retrieving revision 1.14 diff -u -r1.14 texformat_tmp.h --- texformat_tmp.h 18 Nov 2003 00:48:24 -0000 1.14 +++ texformat_tmp.h 18 Dec 2003 00:54:48 -0000 @@ -383,12 +383,88 @@ #if DIM == 2 +#if MESA_S3TC +/* super inefficient. To be efficient, it would be necessary to decode 16 pixels at once */ +static void dxt135_decode_imageblock ( GLubyte *img_block_src, + GLint i, GLint j, GLuint dxt_type, GLvoid *texel ) { + GLchan *rgba = (GLchan *) texel; + const GLubyte *c0_lo = img_block_src + 0; + const GLubyte *c0_hi = img_block_src + 1; + const GLubyte *c1_lo = img_block_src + 2; + const GLubyte *c1_hi = img_block_src + 3; + const GLubyte *bits_0 = img_block_src + 4; + const GLubyte *bits_1 = img_block_src + 5; + const GLubyte *bits_2 = img_block_src + 6; + const GLubyte *bits_3 = img_block_src + 7; + GLushort color0 = *c0_lo + *c0_hi * 256; + GLushort color1 = *c1_lo + *c1_hi * 256; + GLuint bits = *bits_0 + 256 * (*bits_1 + 256 * (*bits_2 + 256 * *bits_3)); + /* What about big/little endian? */ + GLubyte bit_pos = 2 * (j * 4 + i) ; + GLubyte code = (GLubyte) ((bits >> bit_pos) & 3); + switch (code) { + case 0: + rgba[RCOMP] = UBYTE_TO_CHAN( ((color0 >> 8) & 0xf8) * 255 / 0xf8 ); + rgba[GCOMP] = UBYTE_TO_CHAN( ((color0 >> 3) & 0xfc) * 255 / 0xfc ); + rgba[BCOMP] = UBYTE_TO_CHAN( ((color0 << 3) & 0xf8) * 255 / 0xf8 ); + rgba[ACOMP] = CHAN_MAX; + break; + case 1: + rgba[RCOMP] = UBYTE_TO_CHAN( ((color1 >> 8) & 0xf8) * 255 / 0xf8 ); + rgba[GCOMP] = UBYTE_TO_CHAN( ((color1 >> 3) & 0xfc) * 255 / 0xfc ); + rgba[BCOMP] = UBYTE_TO_CHAN( ((color1 << 3) & 0xf8) * 255 / 0xf8 ); + rgba[ACOMP] = CHAN_MAX; + break; + case 2: + if (color0 > color1) { + rgba[RCOMP] = UBYTE_TO_CHAN( (((color0 >> 8) & 0xf8) * 255 / 0xf8 * 2 + ((color1 >> 8) & 0xf8) * 255 / 0xf8 ) / 3); + rgba[GCOMP] = UBYTE_TO_CHAN( (((color0 >> 3) & 0xfc) * 255 / 0xfc * 2 + ((color1 >> 3) & 0xfc) * 255 / 0xfc ) / 3); + rgba[BCOMP] = UBYTE_TO_CHAN( (((color0 << 3) & 0xf8) * 255 / 0xf8 * 2 + ((color1 << 3) & 0xf8) * 255 / 0xf8 ) / 3); + rgba[ACOMP] = CHAN_MAX; + } + else { + rgba[RCOMP] = UBYTE_TO_CHAN( (((color0 >> 8) & 0xf8) * 255 / 0xf8 + ((color1 >> 8) & 0xf8) * 255 / 0xf8 ) / 2); + rgba[GCOMP] = UBYTE_TO_CHAN( (((color0 >> 3) & 0xfc) * 255 / 0xfc + ((color1 >> 3) & 0xfc) * 255 / 0xfc ) / 2); + rgba[BCOMP] = UBYTE_TO_CHAN( (((color0 << 3) & 0xf8) * 255 / 0xf8 + ((color1 << 3) & 0xf8) * 255 / 0xf8 ) / 2); + rgba[ACOMP] = CHAN_MAX; + } + break; + case 3: + /* don't understand the spec. Is the dxt_type switch necessary for other code cases too? */ + if ((dxt_type > 1) || (color0 > color1)) { + rgba[RCOMP] = UBYTE_TO_CHAN( (((color0 >> 8) & 0xf8) * 255 / 0xf8 + ((color1 >> 8) & 0xf8) * 255 / 0xf8 * 2) / 3); + rgba[GCOMP] = UBYTE_TO_CHAN( (((color0 >> 3) & 0xfc) * 255 / 0xfc + ((color1 >> 3) & 0xfc) * 255 / 0xfc * 2) / 3); + rgba[BCOMP] = UBYTE_TO_CHAN( (((color0 << 3) & 0xf8) * 255 / 0xf8 + ((color1 << 3) & 0xf8) * 255 / 0xf8 * 2) / 3); + rgba[ACOMP] = CHAN_MAX; + } + else { + rgba[RCOMP] = 0; + rgba[GCOMP] = 0; + rgba[BCOMP] = 0; + rgba[ACOMP] = CHAN_MAX; + if (dxt_type == 1) rgba[ACOMP] = UBYTE_TO_CHAN(0); + } + break; + default: + /* CANNOT happen (I hope) */ + break; + } + +} +#endif +#endif + +#if DIM == 2 static void FETCH(rgb_dxt1)( const struct gl_texture_image *texImage, GLint i, GLint j, GLint k, GLvoid *texel ) { /* Extract the (i,j) pixel from texImage->Data and return it * in texel[RCOMP], texel[GCOMP], texel[BCOMP], texel[ACOMP]. */ +#if MESA_S3TC + GLubyte *src = ((GLubyte *)(texImage)->Data + (((texImage)->RowStride + 3) / 4 * (j / 4) + (i / 4)) * (8)); + dxt135_decode_imageblock(src, (i&3), (j&3), 0, texel); +#endif } #endif @@ -399,6 +475,10 @@ /* Extract the (i,j) pixel from texImage->Data and return it * in texel[RCOMP], texel[GCOMP], texel[BCOMP], texel[ACOMP]. */ +#if MESA_S3TC + GLubyte *src = ((GLubyte *)(texImage)->Data + (((texImage)->RowStride + 3) / 4 * (j / 4) + (i / 4)) * (8)); + dxt135_decode_imageblock(src, (i&3), (j&3), 1, texel); +#endif } #endif @@ -409,6 +489,28 @@ /* Extract the (i,j) pixel from texImage->Data and return it * in texel[RCOMP], texel[GCOMP], texel[BCOMP], texel[ACOMP]. */ +#if MESA_S3TC + GLchan *rgba = (GLchan *) texel; + GLubyte *src = ((GLubyte *)(texImage)->Data + (((texImage)->RowStride + 3) / 4 * (j / 4) + (i / 4)) * (16)); + dxt135_decode_imageblock(src + 8, (i&3), (j&3), 2, texel); + GLubyte bit_pos = 4 * ((j&3) * 4 + (i&3)); + /* straight implementation from the OGL extension registry, needs 64bit types. Doesn't work. */ +/* unsigned long long alpha = *src++ | (*src++ << 8) | (*src++ << 16) | (*src++ << 24) | (*src++ << 32) | + (*src++ << 40) | (*src++ << 48) | (*src++ << 56); */ + /*endianness trouble? */ +/* rgba[ACOMP] = UBYTE_TO_CHAN((GLubyte)((((alpha >> bit_pos) & 15) * 255) / 15));*/ + /* Simple 32bit version. It doesn't work, WHY THE HECK NOT??? + GLuint alpha_low = *src++ | (*src++ << 8) | (*src++ << 16) | (*src++ << 24); + GLuint alpha_high = *src++ | (*src++ << 8) | (*src++ << 16) | (*src++ << 24); */ + /* this one works, at least on x86, what about big_endian boxes or doesn't it matter? */ + GLuint alpha_low = *((GLuint *)src)++; + GLuint alpha_high = *(GLuint *)src; + + if (bit_pos < 32) + rgba[ACOMP] = UBYTE_TO_CHAN((GLubyte)((((alpha_low >> bit_pos) & 15) * 255) / 15)); + else + rgba[ACOMP] = UBYTE_TO_CHAN((GLubyte)((((alpha_high >> (bit_pos - 32)) & 15) * 255) / 15)); +#endif } #endif @@ -419,9 +521,71 @@ /* Extract the (i,j) pixel from texImage->Data and return it * in texel[RCOMP], texel[GCOMP], texel[BCOMP], texel[ACOMP]. */ +#if MESA_S3TC + GLchan *rgba = (GLchan *) texel; + GLubyte code; + GLubyte *src = ((GLubyte *)(texImage)->Data + (((texImage)->RowStride + 3) / 4 * (j / 4) + (i / 4)) * (16)); + dxt135_decode_imageblock(src + 8, (i&3), (j&3), 2, texel); + GLushort alpha0 = *src++; + GLushort alpha1 = *src++; + GLubyte bit_pos = 3 * ((j&3) * 4 + (i&3)); + /* need 48 bit, same problems as dxt3 */ +/* unsigned long long bits = *src++ | (*src++ << 8 | (*src++ << 16) | (*src++ << 24 | + (*src++ << 32) | (*src++ 40); + code = (GLubyte) ((bits >> bit_pos) & 7); */ + /* spec says 3 bit control code but forumla says 2 - must be 3 */ + + GLuint bits_low = *((GLuint *)src)++; + GLuint bits_high = *(GLuint *)src; + if (bit_pos < 30) + code = (GLubyte) ((bits_low >> bit_pos) & 7); + else if (bit_pos == 30) + code = (GLubyte) ((bits_low >> 30) & 3) | ((bits_high << 2) & 4); + else + code = (GLubyte) ((bits_high >> (bit_pos - 32)) & 7); + if (alpha0 > alpha1) + switch (code) { + case 0: + rgba[ACOMP] = UBYTE_TO_CHAN((GLubyte) alpha0); + break; + case 1: + rgba[ACOMP] = UBYTE_TO_CHAN((GLubyte) alpha1); + break; + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + rgba[ACOMP] = UBYTE_TO_CHAN((GLubyte) + ((alpha0 * (8 - code) + (alpha1 * (code - 1))) / 7)); + break; + } + else + switch (code) { + case 0: + rgba[ACOMP] = UBYTE_TO_CHAN((GLubyte) alpha0); + break; + case 1: + rgba[ACOMP] = UBYTE_TO_CHAN((GLubyte) alpha1); + break; + case 2: + case 3: + case 4: + case 5: + rgba[ACOMP] = UBYTE_TO_CHAN((GLubyte) + ((alpha0 * (6 - code) + (alpha1 * (code - 1))) / 5));; + break; + case 6: + rgba[ACOMP] = 0; + break; + case 7: + rgba[ACOMP] = CHAN_MAX; + break; + } +#endif } #endif - /* big-endian */
Index: r200_context.c =================================================================== RCS file: /cvsroot/mesa3d/Mesa-newtree/src/mesa/drivers/dri/r200/r200_context.c,v retrieving revision 1.11 diff -u -r1.11 r200_context.c --- r200_context.c 12 Dec 2003 16:38:58 -0000 1.11 +++ r200_context.c 18 Dec 2003 00:11:08 -0000 @@ -147,6 +147,9 @@ "GL_SGIS_generate_mipmap", "GL_SGIS_texture_border_clamp", "GL_SGIS_texture_edge_clamp", +#if ENABLE_HW_S3TC + "GL_EXT_texture_compression_s3tc", +#endif NULL }; @@ -332,6 +335,12 @@ 11, /* max texture rectangle size is 2048x2048 */ 12, GL_FALSE ); + +#if ENABLE_HW_S3TC +/* adjust max texture size a bit. Hack, but I really want to use 2048x2048 textures + which will work just fine in 99.999999% of all cases, especially with texture compression... */ + if (ctx->Const.MaxTextureLevels < 12) ctx->Const.MaxTextureLevels += 1; +#endif ctx->Const.MaxTextureMaxAnisotropy = 16.0; Index: r200_context.h =================================================================== RCS file: /cvsroot/mesa3d/Mesa-newtree/src/mesa/drivers/dri/r200/r200_context.h,v retrieving revision 1.7 diff -u -r1.7 r200_context.h --- r200_context.h 11 Dec 2003 16:25:37 -0000 1.7 +++ r200_context.h 18 Dec 2003 00:11:11 -0000 @@ -49,6 +49,7 @@ #include "r200_reg.h" #define ENABLE_HW_3D_TEXTURE 0 /* XXX this is temporary! */ +#define ENABLE_HW_S3TC 1 struct r200_context; typedef struct r200_context r200ContextRec; Index: r200_tex.c =================================================================== RCS file: /cvsroot/mesa3d/Mesa-newtree/src/mesa/drivers/dri/r200/r200_tex.c,v retrieving revision 1.5 diff -u -r1.5 r200_tex.c --- r200_tex.c 11 Dec 2003 16:25:37 -0000 1.5 +++ r200_tex.c 18 Dec 2003 00:11:16 -0000 @@ -412,6 +412,17 @@ else return &_mesa_texformat_ycbcr_rev; +#if ENABLE_HW_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_COMPRESSED_RGBA_S3TC_DXT5_EXT: + return &_mesa_texformat_rgba_dxt5; +#endif + default: _mesa_problem(ctx, "unexpected texture format in %s", __FUNCTION__); return NULL; @@ -705,6 +716,118 @@ t->dirty_images[face] |= (1 << level); } +#if ENABLE_HW_S3TC +static void r200CompressedTexImage2D( 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 ) +{ + driTextureObject * t = (driTextureObject *) texObj->DriverData; + GLuint face; + + /* which cube face or ordinary 2D image */ + switch (target) { + case GL_TEXTURE_CUBE_MAP_POSITIVE_X: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: + face = (GLuint) target - (GLuint) GL_TEXTURE_CUBE_MAP_POSITIVE_X; + ASSERT(face < 6); + break; + default: + face = 0; + } + + if ( t != NULL ) { + driSwapOutTextureObject( t ); + } + else { + t = (driTextureObject *) r200AllocTexObj( texObj ); + if (!t) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCompressedTexImage2D"); + return; + } + } + + texImage->IsClientData = GL_FALSE; +/* can't call this, different parameters. Would never evaluate to true anyway currently + if (r200ValidateClientStorage( ctx, target, + internalFormat, + width, height, + format, type, pixels, + packing, texObj, texImage)) { + if (R200_DEBUG & DEBUG_TEXTURE) + fprintf(stderr, "%s: Using client storage\n", __FUNCTION__); + } + else */{ + if (R200_DEBUG & DEBUG_TEXTURE) + fprintf(stderr, "%s: Using normal storage\n", __FUNCTION__); + + /* Normal path: copy (to cached memory) and eventually upload + * via another copy to GART memory and then a blit... Could + * eliminate one copy by going straight to (permanent) GART. + * + * Note, this will call r200ChooseTextureFormat. + */ + _mesa_store_compressed_teximage2d(ctx, target, level, internalFormat, width, + height, border, imageSize, data, texObj, texImage); + + t->dirty_images[face] |= (1 << level); + } +} +#endif + + +#if ENABLE_HW_S3TC +static void r200CompressedTexSubImage2D( 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 ) +{ + driTextureObject * t = (driTextureObject *) texObj->DriverData; + GLuint face; + + + /* which cube face or ordinary 2D image */ + switch (target) { + case GL_TEXTURE_CUBE_MAP_POSITIVE_X: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: + face = (GLuint) target - (GLuint) GL_TEXTURE_CUBE_MAP_POSITIVE_X; + ASSERT(face < 6); + break; + default: + face = 0; + } + + assert( t ); /* this _should_ be true */ + if ( t ) { + driSwapOutTextureObject( t ); + } + else { + t = (driTextureObject *) r200AllocTexObj( texObj ); + if (!t) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCompressedTexSubImage2D"); + return; + } + } + + _mesa_store_compressed_texsubimage2d(ctx, target, level, xoffset, yoffset, width, + height, format, imageSize, data, texObj, texImage); + + t->dirty_images[face] |= (1 << level); +} +#endif #if ENABLE_HW_3D_TEXTURE static void r200TexImage3D( GLcontext *ctx, GLenum target, GLint level, @@ -1013,6 +1135,11 @@ ctx->Driver.TexEnv = r200TexEnv; ctx->Driver.TexParameter = r200TexParameter; ctx->Driver.TexGen = r200TexGen; + +#if ENABLE_HW_S3TC + ctx->Driver.CompressedTexImage2D = r200CompressedTexImage2D; + ctx->Driver.CompressedTexSubImage2D = r200CompressedTexSubImage2D; +#endif driInitTextureObjects( ctx, & rmesa->swapped, DRI_TEXMGR_DO_TEXTURE_1D Index: r200_texmem.c =================================================================== RCS file: /cvsroot/mesa3d/Mesa-newtree/src/mesa/drivers/dri/r200/r200_texmem.c,v retrieving revision 1.4 diff -u -r1.4 r200_texmem.c --- r200_texmem.c 11 Dec 2003 16:25:37 -0000 1.4 +++ r200_texmem.c 18 Dec 2003 00:11:18 -0000 @@ -137,15 +137,15 @@ r200EmitWait( rmesa, RADEON_WAIT_3D ); - r200EmitBlit( rmesa, blit_format, - srcPitch, - srcOffset, + r200EmitBlit( rmesa, blit_format, + srcPitch, + srcOffset, dstPitch, t->bufAddr, - x, - y, + x, + y, t->image[0][hwlevel].x + x, - t->image[0][hwlevel].y + y, + t->image[0][hwlevel].y + y, width, height ); @@ -291,9 +291,9 @@ const int level = hwlevel + t->base.firstLevel; if ( R200_DEBUG & DEBUG_TEXTURE ) { - fprintf( stderr, "%s( %p, %p ) level/width/height/face = %d/%d/%d/%u\n", + fprintf( stderr, "%s( %p, %p ) level/width/height/face/type = %d/%d/%d/%u/%x\n", __FUNCTION__, (void *)t, (void *)t->base.tObj, - level, width, height, face ); + level, width, height, face, t->base.tObj->Image[t->base.tObj->BaseLevel]->IntFormat ); } ASSERT(face < 6); @@ -356,7 +356,7 @@ else if ( R200_DEBUG & DEBUG_TEXTURE ) fprintf( stderr, "%s: image data is in normal memory\n", __FUNCTION__); - + imageWidth = texImage->Width; imageHeight = texImage->Height; @@ -394,10 +394,39 @@ tex.height = imageHeight; } else { - tex.width = imageWidth; /* compressed */ - tex.height = imageHeight; - if (tex.height < 4) - tex.height = 4; + /* doesn't work, the padding in the radeon kernel module will rip the 4x4 dxt blocks apart + if the textures/mipmaps are small */ + /* tex.width = imageWidth; *//* compressed */ + /* if (tex.height < 4) + tex.height = 4;*/ + + /* do really really ugly hack instead to avoid changing kernel module. + In case of for instance 8x8 texture (2x2 dxt blocks), padding after the first two blocks is + needed (only with dxt1 since 2 dxt3/dxt5 blocks already use 32 Byte). */ + /* set tex.height to 1/4 since 1 "macropixel" (dxt-block) has 4 real pixels. Only needed hopefully + so the kernel module reads the right amount of data. */ + tex.height = (imageHeight + 3) / 4; + tex.width = (imageWidth + 3) / 4; + /* correct tex width to avoid wrong padding in the kernel module. */ +/* switch (texImage->TexFormat->MesaFormat) { + case MESA_FORMAT_RGB_DXT1: + case MESA_FORMAT_RGBA_DXT1: + tex.width *= 8; + break; + case MESA_FORMAT_RGBA_DXT3: + case MESA_FORMAT_RGBA_DXT5: + tex.width *= 16; + break; + } */ + switch (t->pp_txformat & R200_TXFORMAT_FORMAT_MASK) { + case R200_TXFORMAT_DXT1: + tex.width *= 8; + break; + case R200_TXFORMAT_DXT23: + case R200_TXFORMAT_DXT45: + tex.width *= 16; + break; + } } tex.image = &tmp; Index: r200_texstate.c =================================================================== RCS file: /cvsroot/mesa3d/Mesa-newtree/src/mesa/drivers/dri/r200/r200_texstate.c,v retrieving revision 1.4 diff -u -r1.4 r200_texstate.c --- r200_texstate.c 11 Dec 2003 16:25:37 -0000 1.4 +++ r200_texstate.c 18 Dec 2003 00:11:25 -0000 @@ -51,6 +51,10 @@ #define R200_TXFORMAT_AL88 R200_TXFORMAT_AI88 #define R200_TXFORMAT_YCBCR R200_TXFORMAT_YVYU422 #define R200_TXFORMAT_YCBCR_REV R200_TXFORMAT_VYUY422 +#define R200_TXFORMAT_RGB_DXT1 R200_TXFORMAT_DXT1 +#define R200_TXFORMAT_RGBA_DXT1 R200_TXFORMAT_DXT1 +#define R200_TXFORMAT_RGBA_DXT3 R200_TXFORMAT_DXT23 +#define R200_TXFORMAT_RGBA_DXT5 R200_TXFORMAT_DXT45 #define _COLOR(f) \ [ MESA_FORMAT_ ## f ] = { R200_TXFORMAT_ ## f, 0 } @@ -60,8 +64,14 @@ [ MESA_FORMAT_ ## f ] = { R200_TXFORMAT_ ## f, R200_YUV_TO_RGB } #define _INVALID(f) \ [ MESA_FORMAT_ ## f ] = { 0xffffffff, 0 } +#if ENABLE_HW_S3TC +#define VALID_FORMAT(f) ( ((f) <= MESA_FORMAT_RGBA_DXT5) \ + && (tx_table[f].format != 0xffffffff) ) +#else #define VALID_FORMAT(f) ( ((f) <= MESA_FORMAT_YCBCR_REV) \ && (tx_table[f].format != 0xffffffff) ) +#endif + static const struct { GLuint format, filter; @@ -81,6 +91,12 @@ _INVALID(CI8), _YUV(YCBCR), _YUV(YCBCR_REV), +#if ENABLE_HW_S3TC + _COLOR(RGB_DXT1), + _ALPHA(RGBA_DXT1), + _ALPHA(RGBA_DXT3), + _ALPHA(RGBA_DXT5), +#endif }; #undef _COLOR @@ -153,7 +169,8 @@ /* find image size in bytes */ if (texImage->IsCompressed) { - size = texImage->CompressedSize; + /* looks like 64Byte alignment is needed here */ + size = (texImage->CompressedSize + 63) & ~63; } else if (tObj->Target == GL_TEXTURE_RECTANGLE_NV) { size = ((texImage->Width * texImage->TexFormat->TexelBytes + 63)
Index: radeon_context.c =================================================================== RCS file: /cvsroot/mesa3d/Mesa-newtree/src/mesa/drivers/dri/radeon/radeon_context.c,v retrieving revision 1.9 diff -u -r1.9 radeon_context.c --- radeon_context.c 12 Dec 2003 16:38:58 -0000 1.9 +++ radeon_context.c 18 Dec 2003 00:21:52 -0000 @@ -143,6 +143,9 @@ "GL_SGIS_generate_mipmap", "GL_SGIS_texture_border_clamp", "GL_SGIS_texture_edge_clamp", +#if ENABLE_HW_S3TC + "GL_EXT_texture_compression_s3tc", +#endif NULL }; @@ -318,6 +321,12 @@ 11, /* max rect texture size is 2048x2048. */ 12, GL_FALSE ); + +#if ENABLE_HW_S3TC +/* adjust max texture size a bit. Hack, but I really want to use 2048x2048 textures + which will work just fine in 99.999999% of all cases, especially with texture compression... */ + if (ctx->Const.MaxTextureLevels < 12) ctx->Const.MaxTextureLevels += 1; +#endif ctx->Const.MaxTextureMaxAnisotropy = 16.0; Index: radeon_context.h =================================================================== RCS file: /cvsroot/mesa3d/Mesa-newtree/src/mesa/drivers/dri/radeon/radeon_context.h,v retrieving revision 1.6 diff -u -r1.6 radeon_context.h --- radeon_context.h 7 Dec 2003 23:53:32 -0000 1.6 +++ radeon_context.h 18 Dec 2003 00:21:55 -0000 @@ -74,6 +74,8 @@ */ #define BLIT_WIDTH_BYTES 1024 +#define ENABLE_HW_S3TC 1 + /* Use the templated vertex format: */ #define COLOR_IS_RGBA Index: radeon_tex.c =================================================================== RCS file: /cvsroot/mesa3d/Mesa-newtree/src/mesa/drivers/dri/radeon/radeon_tex.c,v retrieving revision 1.3 diff -u -r1.3 radeon_tex.c --- radeon_tex.c 5 Dec 2003 22:14:51 -0000 1.3 +++ radeon_tex.c 18 Dec 2003 00:21:59 -0000 @@ -373,6 +373,17 @@ else return &_mesa_texformat_ycbcr_rev; +#if ENABLE_HW_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_COMPRESSED_RGBA_S3TC_DXT5_EXT: + return &_mesa_texformat_rgba_dxt5; +#endif + default: _mesa_problem(ctx, "unexpected texture format in %s", __FUNCTION__); return NULL; @@ -536,6 +547,98 @@ t->dirty_images[face] |= (1 << level); } +#if ENABLE_HW_S3TC +static void radeonCompressedTexImage2D( 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 ) +{ + driTextureObject * t = (driTextureObject *) texObj->DriverData; + GLuint face; + + /* which cube face or ordinary 2D image */ + switch (target) { + case GL_TEXTURE_CUBE_MAP_POSITIVE_X: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: + face = (GLuint) target - (GLuint) GL_TEXTURE_CUBE_MAP_POSITIVE_X; + ASSERT(face < 6); + break; + default: + face = 0; + } + + if ( t != NULL ) { + driSwapOutTextureObject( t ); + } + else { + t = (driTextureObject *) radeonAllocTexObj( texObj ); + if (!t) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCompressedTexImage2D"); + return; + } + } + + /* Note, this will call ChooseTextureFormat */ + _mesa_store_compressed_teximage2d(ctx, target, level, internalFormat, width, + height, border, imageSize, data, texObj, texImage); + + t->dirty_images[face] |= (1 << level); +} +#endif + + +#if ENABLE_HW_S3TC +static void radeonCompressedTexSubImage2D( 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 ) +{ + driTextureObject * t = (driTextureObject *) texObj->DriverData; + GLuint face; + + + /* which cube face or ordinary 2D image */ + switch (target) { + case GL_TEXTURE_CUBE_MAP_POSITIVE_X: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: + face = (GLuint) target - (GLuint) GL_TEXTURE_CUBE_MAP_POSITIVE_X; + ASSERT(face < 6); + break; + default: + face = 0; + } + + assert( t ); /* this _should_ be true */ + if ( t ) { + driSwapOutTextureObject( t ); + } + else { + t = (driTextureObject *) radeonAllocTexObj( texObj ); + if (!t) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCompressedTexSubImage2D"); + return; + } + } + + _mesa_store_compressed_texsubimage2d(ctx, target, level, xoffset, yoffset, width, + height, format, imageSize, data, texObj, texImage); + + t->dirty_images[face] |= (1 << level); +} +#endif #define SCALED_FLOAT_TO_BYTE( x, scale ) \ @@ -743,6 +846,11 @@ ctx->Driver.TexEnv = radeonTexEnv; ctx->Driver.TexParameter = radeonTexParameter; ctx->Driver.TexGen = radeonTexGen; + +#if ENABLE_HW_S3TC + ctx->Driver.CompressedTexImage2D = radeonCompressedTexImage2D; + ctx->Driver.CompressedTexSubImage2D = radeonCompressedTexSubImage2D; +#endif driInitTextureObjects( ctx, & rmesa->swapped, DRI_TEXMGR_DO_TEXTURE_1D Index: radeon_texmem.c =================================================================== RCS file: /cvsroot/mesa3d/Mesa-newtree/src/mesa/drivers/dri/radeon/radeon_texmem.c,v retrieving revision 1.3 diff -u -r1.3 radeon_texmem.c --- radeon_texmem.c 21 Oct 2003 06:05:50 -0000 1.3 +++ radeon_texmem.c 18 Dec 2003 00:22:00 -0000 @@ -188,7 +188,7 @@ const int level = hwlevel + t->base.firstLevel; if ( RADEON_DEBUG & DEBUG_TEXTURE ) { - fprintf( stderr, "%s( %p, %p ) level/width/height/face = %d/%d/%d/%u\n", + fprintf( stderr, "%s( %p, %p ) level/width/height/face = %d/%d/%d/%u\n", __FUNCTION__, t, t->base.tObj, level, width, height, face ); } @@ -278,10 +278,20 @@ tex.height = imageHeight; } else { - tex.width = imageWidth; /* compressed */ - tex.height = imageHeight; - if (tex.height < 4) - tex.height = 4; + /* set tex.height to 1/4 since 1 "macropixel" (dxt-block) has 4 real pixels. Only needed hopefully + so the kernel module reads the right amount of data. */ + tex.height = (imageHeight + 3) / 4; + tex.width = (imageWidth + 3) / 4; + /* correct tex width to avoid wrong padding in the kernel module. */ + switch (t->pp_txformat & RADEON_TXFORMAT_FORMAT_MASK) { + case RADEON_TXFORMAT_DXT1: + tex.width *= 8; + break; + case RADEON_TXFORMAT_DXT23: + case RADEON_TXFORMAT_DXT45: + tex.width *= 16; + break; + } } tex.image = &tmp; Index: radeon_texstate.c =================================================================== RCS file: /cvsroot/mesa3d/Mesa-newtree/src/mesa/drivers/dri/radeon/radeon_texstate.c,v retrieving revision 1.3 diff -u -r1.3 radeon_texstate.c --- radeon_texstate.c 21 Oct 2003 06:05:50 -0000 1.3 +++ radeon_texstate.c 18 Dec 2003 00:22:07 -0000 @@ -53,6 +53,11 @@ #define RADEON_TXFORMAT_AL88 RADEON_TXFORMAT_AI88 #define RADEON_TXFORMAT_YCBCR RADEON_TXFORMAT_YVYU422 #define RADEON_TXFORMAT_YCBCR_REV RADEON_TXFORMAT_VYUY422 +#define RADEON_TXFORMAT_RGB_DXT1 RADEON_TXFORMAT_DXT1 +#define RADEON_TXFORMAT_RGBA_DXT1 RADEON_TXFORMAT_DXT1 +#define RADEON_TXFORMAT_RGBA_DXT3 RADEON_TXFORMAT_DXT23 +#define RADEON_TXFORMAT_RGBA_DXT5 RADEON_TXFORMAT_DXT45 + #define _COLOR(f) \ [ MESA_FORMAT_ ## f ] = { RADEON_TXFORMAT_ ## f, 0 } @@ -62,8 +67,13 @@ [ MESA_FORMAT_ ## f ] = { RADEON_TXFORMAT_ ## f, RADEON_YUV_TO_RGB } #define _INVALID(f) \ [ MESA_FORMAT_ ## f ] = { 0xffffffff, 0 } +#if ENABLE_HW_S3TC +#define VALID_FORMAT(f) ( ((f) <= MESA_FORMAT_RGBA_DXT5) \ + && (tx_table[f].format != 0xffffffff) ) +#else #define VALID_FORMAT(f) ( ((f) <= MESA_FORMAT_YCBCR_REV) \ && (tx_table[f].format != 0xffffffff) ) +#endif static const struct { GLuint format, filter; @@ -83,6 +93,13 @@ _INVALID(CI8), _YUV(YCBCR), _YUV(YCBCR_REV), +#if ENABLE_HW_S3TC + _COLOR(RGB_DXT1), + _ALPHA(RGBA_DXT1), + _ALPHA(RGBA_DXT3), + _ALPHA(RGBA_DXT5), +#endif + }; #undef _COLOR @@ -155,7 +172,8 @@ /* find image size in bytes */ if (texImage->IsCompressed) { - size = texImage->CompressedSize; + /* looks like 64Byte alignment is needed here */ + size = (texImage->CompressedSize + 63) & ~63; } else if (tObj->Target == GL_TEXTURE_RECTANGLE_NV) { size = ((texImage->Width * texImage->TexFormat->TexelBytes + 63)