1 /* 2 * Mesa 3-D graphics library 3 * Version: 6.5.3 4 * 5 * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. 6 * Copyright (c) 2008 VMware, Inc. 7 * 8 * Permission is hereby granted, free of charge, to any person obtaining a 9 * copy of this software and associated documentation files (the "Software"), 10 * to deal in the Software without restriction, including without limitation 11 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 12 * and/or sell copies of the Software, and to permit persons to whom the 13 * Software is furnished to do so, subject to the following conditions: 14 * 15 * The above copyright notice and this permission notice shall be included 16 * in all copies or substantial portions of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 21 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 22 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 23 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 */ 25 26 27 /** 28 * \file texcompress_s3tc.c 29 * GL_EXT_texture_compression_s3tc support. 30 */ 31 32 #ifndef USE_EXTERNAL_DXTN_LIB 33 #define USE_EXTERNAL_DXTN_LIB 1 34 #endif 35 36 #include "glheader.h" 37 #include "imports.h" 38 #include "colormac.h" 39 #include "dlopen.h" 40 #include "image.h" 41 #include "macros.h" 42 #include "mfeatures.h" 43 #include "mtypes.h" 44 #include "texcompress.h" 45 #include "texcompress_s3tc.h" 46 #include "texstore.h" 47 #include "swrast/s_context.h" 48 49 50 #if FEATURE_texture_s3tc 51 52 53 #if defined(_WIN32) || defined(WIN32) 54 #define DXTN_LIBNAME "dxtn.dll" 55 #define RTLD_LAZY 0 56 #define RTLD_GLOBAL 0 57 #elif defined(__DJGPP__) 58 #define DXTN_LIBNAME "dxtn.dxe" 59 #else 60 #define DXTN_LIBNAME "libtxc_dxtn.so" 61 #endif 62 63 #if FEATURE_EXT_texture_sRGB 64 /** 65 * Convert an 8-bit sRGB value from non-linear space to a 66 * linear RGB value in [0, 1]. 67 * Implemented with a 256-entry lookup table. 68 */ 69 static inline GLfloat 70 nonlinear_to_linear(GLubyte cs8) 71 { 72 static GLfloat table[256]; 73 static GLboolean tableReady = GL_FALSE; 74 if (!tableReady) { 75 /* compute lookup table now */ 76 GLuint i; 77 for (i = 0; i < 256; i++) { 78 const GLfloat cs = UBYTE_TO_FLOAT(i); 79 if (cs <= 0.04045) { 80 table[i] = cs / 12.92f; 81 } 82 else { 83 table[i] = (GLfloat) pow((cs + 0.055) / 1.055, 2.4); 84 } 85 } 86 tableReady = GL_TRUE; 87 } 88 return table[cs8]; 89 } 90 #endif /* FEATURE_EXT_texture_sRGB */ 91 92 typedef void (*dxtFetchTexelFuncExt)( GLint srcRowstride, GLubyte *pixdata, GLint col, GLint row, GLvoid *texelOut ); 93 94 dxtFetchTexelFuncExt fetch_ext_rgb_dxt1 = NULL; 95 dxtFetchTexelFuncExt fetch_ext_rgba_dxt1 = NULL; 96 dxtFetchTexelFuncExt fetch_ext_rgba_dxt3 = NULL; 97 dxtFetchTexelFuncExt fetch_ext_rgba_dxt5 = NULL; 98 99 typedef void (*dxtCompressTexFuncExt)(GLint srccomps, GLint width, 100 GLint height, const GLubyte *srcPixData, 101 GLenum destformat, GLubyte *dest, 102 GLint dstRowStride); 103 104 static dxtCompressTexFuncExt ext_tx_compress_dxtn = NULL; 105 106 static void *dxtlibhandle = NULL; 107 108 109 void 110 _mesa_init_texture_s3tc( struct gl_context *ctx ) 111 { 112 /* called during context initialization */ 113 ctx->Mesa_DXTn = GL_FALSE; 114 #if USE_EXTERNAL_DXTN_LIB 115 if (!dxtlibhandle) { 116 dxtlibhandle = _mesa_dlopen(DXTN_LIBNAME, 0); 117 if (!dxtlibhandle) { 118 _mesa_warning(ctx, "couldn't open " DXTN_LIBNAME ", software DXTn " 119 "compression/decompression unavailable"); 120 } 121 else { 122 /* the fetch functions are not per context! Might be problematic... */ 123 fetch_ext_rgb_dxt1 = (dxtFetchTexelFuncExt) 124 _mesa_dlsym(dxtlibhandle, "fetch_2d_texel_rgb_dxt1"); 125 fetch_ext_rgba_dxt1 = (dxtFetchTexelFuncExt) 126 _mesa_dlsym(dxtlibhandle, "fetch_2d_texel_rgba_dxt1"); 127 fetch_ext_rgba_dxt3 = (dxtFetchTexelFuncExt) 128 _mesa_dlsym(dxtlibhandle, "fetch_2d_texel_rgba_dxt3"); 129 fetch_ext_rgba_dxt5 = (dxtFetchTexelFuncExt) 130 _mesa_dlsym(dxtlibhandle, "fetch_2d_texel_rgba_dxt5"); 131 ext_tx_compress_dxtn = (dxtCompressTexFuncExt) 132 _mesa_dlsym(dxtlibhandle, "tx_compress_dxtn"); 133 134 if (!fetch_ext_rgb_dxt1 || 135 !fetch_ext_rgba_dxt1 || 136 !fetch_ext_rgba_dxt3 || 137 !fetch_ext_rgba_dxt5 || 138 !ext_tx_compress_dxtn) { 139 _mesa_warning(ctx, "couldn't reference all symbols in " 140 DXTN_LIBNAME ", software DXTn compression/decompression " 141 "unavailable"); 142 fetch_ext_rgb_dxt1 = NULL; 143 fetch_ext_rgba_dxt1 = NULL; 144 fetch_ext_rgba_dxt3 = NULL; 145 fetch_ext_rgba_dxt5 = NULL; 146 ext_tx_compress_dxtn = NULL; 147 _mesa_dlclose(dxtlibhandle); 148 dxtlibhandle = NULL; 149 } 150 } 151 } 152 if (dxtlibhandle) { 153 ctx->Mesa_DXTn = GL_TRUE; 154 } 155 #else 156 (void) ctx; 157 #endif 158 } 159 160 /** 161 * Store user's image in rgb_dxt1 format. 162 */ 163 GLboolean 164 _mesa_texstore_rgb_dxt1(TEXSTORE_PARAMS) 165 { 166 const GLubyte *pixels; 167 GLubyte *dst; 168 const GLubyte *tempImage = NULL; 169 170 ASSERT(dstFormat == MESA_FORMAT_RGB_DXT1 || 171 dstFormat == MESA_FORMAT_SRGB_DXT1); 172 173 if (srcFormat != GL_RGB || 174 srcType != GL_UNSIGNED_BYTE || 175 ctx->_ImageTransferState || 176 srcPacking->RowLength != srcWidth || 177 srcPacking->SwapBytes) { 178 /* convert image to RGB/GLubyte */ 179 tempImage = _mesa_make_temp_ubyte_image(ctx, dims, 180 baseInternalFormat, 181 _mesa_get_format_base_format(dstFormat), 182 srcWidth, srcHeight, srcDepth, 183 srcFormat, srcType, srcAddr, 184 srcPacking); 185 if (!tempImage) 186 return GL_FALSE; /* out of memory */ 187 pixels = tempImage; 188 srcFormat = GL_RGB; 189 } 190 else { 191 pixels = _mesa_image_address2d(srcPacking, srcAddr, srcWidth, srcHeight, 192 srcFormat, srcType, 0, 0); 193 } 194 195 dst = dstSlices[0]; 196 197 if (ext_tx_compress_dxtn) { 198 (*ext_tx_compress_dxtn)(3, srcWidth, srcHeight, pixels, 199 GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 200 dst, dstRowStride); 201 } 202 else { 203 _mesa_warning(ctx, "external dxt library not available: texstore_rgb_dxt1"); 204 } 205 206 if (tempImage) 207 free((void *) tempImage); 208 209 return GL_TRUE; 210 } 211 212 213 /** 214 * Store user's image in rgba_dxt1 format. 215 */ 216 GLboolean 217 _mesa_texstore_rgba_dxt1(TEXSTORE_PARAMS) 218 { 219 const GLubyte *pixels; 220 GLubyte *dst; 221 const GLubyte *tempImage = NULL; 222 223 ASSERT(dstFormat == MESA_FORMAT_RGBA_DXT1 || 224 dstFormat == MESA_FORMAT_SRGBA_DXT1); 225 226 if (srcFormat != GL_RGBA || 227 srcType != GL_UNSIGNED_BYTE || 228 ctx->_ImageTransferState || 229 srcPacking->RowLength != srcWidth || 230 srcPacking->SwapBytes) { 231 /* convert image to RGBA/GLubyte */ 232 tempImage = _mesa_make_temp_ubyte_image(ctx, dims, 233 baseInternalFormat, 234 _mesa_get_format_base_format(dstFormat), 235 srcWidth, srcHeight, srcDepth, 236 srcFormat, srcType, srcAddr, 237 srcPacking); 238 if (!tempImage) 239 return GL_FALSE; /* out of memory */ 240 pixels = tempImage; 241 srcFormat = GL_RGBA; 242 } 243 else { 244 pixels = _mesa_image_address2d(srcPacking, srcAddr, srcWidth, srcHeight, 245 srcFormat, srcType, 0, 0); 246 } 247 248 dst = dstSlices[0]; 249 250 if (ext_tx_compress_dxtn) { 251 (*ext_tx_compress_dxtn)(4, srcWidth, srcHeight, pixels, 252 GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, 253 dst, dstRowStride); 254 } 255 else { 256 _mesa_warning(ctx, "external dxt library not available: texstore_rgba_dxt1"); 257 } 258 259 if (tempImage) 260 free((void*) tempImage); 261 262 return GL_TRUE; 263 } 264 265 266 /** 267 * Store user's image in rgba_dxt3 format. 268 */ 269 GLboolean 270 _mesa_texstore_rgba_dxt3(TEXSTORE_PARAMS) 271 { 272 const GLubyte *pixels; 273 GLubyte *dst; 274 const GLubyte *tempImage = NULL; 275 276 ASSERT(dstFormat == MESA_FORMAT_RGBA_DXT3 || 277 dstFormat == MESA_FORMAT_SRGBA_DXT3); 278 279 if (srcFormat != GL_RGBA || 280 srcType != GL_UNSIGNED_BYTE || 281 ctx->_ImageTransferState || 282 srcPacking->RowLength != srcWidth || 283 srcPacking->SwapBytes) { 284 /* convert image to RGBA/GLubyte */ 285 tempImage = _mesa_make_temp_ubyte_image(ctx, dims, 286 baseInternalFormat, 287 _mesa_get_format_base_format(dstFormat), 288 srcWidth, srcHeight, srcDepth, 289 srcFormat, srcType, srcAddr, 290 srcPacking); 291 if (!tempImage) 292 return GL_FALSE; /* out of memory */ 293 pixels = tempImage; 294 } 295 else { 296 pixels = _mesa_image_address2d(srcPacking, srcAddr, srcWidth, srcHeight, 297 srcFormat, srcType, 0, 0); 298 } 299 300 dst = dstSlices[0]; 301 302 if (ext_tx_compress_dxtn) { 303 (*ext_tx_compress_dxtn)(4, srcWidth, srcHeight, pixels, 304 GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, 305 dst, dstRowStride); 306 } 307 else { 308 _mesa_warning(ctx, "external dxt library not available: texstore_rgba_dxt3"); 309 } 310 311 if (tempImage) 312 free((void *) tempImage); 313 314 return GL_TRUE; 315 } 316 317 318 /** 319 * Store user's image in rgba_dxt5 format. 320 */ 321 GLboolean 322 _mesa_texstore_rgba_dxt5(TEXSTORE_PARAMS) 323 { 324 const GLubyte *pixels; 325 GLubyte *dst; 326 const GLubyte *tempImage = NULL; 327 328 ASSERT(dstFormat == MESA_FORMAT_RGBA_DXT5 || 329 dstFormat == MESA_FORMAT_SRGBA_DXT5); 330 331 if (srcFormat != GL_RGBA || 332 srcType != GL_UNSIGNED_BYTE || 333 ctx->_ImageTransferState || 334 srcPacking->RowLength != srcWidth || 335 srcPacking->SwapBytes) { 336 /* convert image to RGBA/GLubyte */ 337 tempImage = _mesa_make_temp_ubyte_image(ctx, dims, 338 baseInternalFormat, 339 _mesa_get_format_base_format(dstFormat), 340 srcWidth, srcHeight, srcDepth, 341 srcFormat, srcType, srcAddr, 342 srcPacking); 343 if (!tempImage) 344 return GL_FALSE; /* out of memory */ 345 pixels = tempImage; 346 } 347 else { 348 pixels = _mesa_image_address2d(srcPacking, srcAddr, srcWidth, srcHeight, 349 srcFormat, srcType, 0, 0); 350 } 351 352 dst = dstSlices[0]; 353 354 if (ext_tx_compress_dxtn) { 355 (*ext_tx_compress_dxtn)(4, srcWidth, srcHeight, pixels, 356 GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, 357 dst, dstRowStride); 358 } 359 else { 360 _mesa_warning(ctx, "external dxt library not available: texstore_rgba_dxt5"); 361 } 362 363 if (tempImage) 364 free((void *) tempImage); 365 366 return GL_TRUE; 367 } 368 369 370 static void 371 fetch_texel_2d_rgb_dxt1(const struct swrast_texture_image *texImage, 372 GLint i, GLint j, GLint k, GLubyte *texel) 373 { 374 (void) k; 375 if (fetch_ext_rgb_dxt1) { 376 GLint sliceOffset = k ? texImage->ImageOffsets[k] / 2 : 0; 377 fetch_ext_rgb_dxt1(texImage->RowStride, 378 texImage->Map + sliceOffset, i, j, texel); 379 } 380 else 381 _mesa_debug(NULL, "attempted to decode s3tc texture without library available: fetch_texel_2d_rgb_dxt1"); 382 } 383 384 385 void 386 _mesa_fetch_texel_rgb_dxt1(const struct swrast_texture_image *texImage, 387 GLint i, GLint j, GLint k, GLfloat *texel) 388 { 389 /* just sample as GLubyte and convert to float here */ 390 GLubyte rgba[4]; 391 fetch_texel_2d_rgb_dxt1(texImage, i, j, k, rgba); 392 texel[RCOMP] = UBYTE_TO_FLOAT(rgba[RCOMP]); 393 texel[GCOMP] = UBYTE_TO_FLOAT(rgba[GCOMP]); 394 texel[BCOMP] = UBYTE_TO_FLOAT(rgba[BCOMP]); 395 texel[ACOMP] = UBYTE_TO_FLOAT(rgba[ACOMP]); 396 } 397 398 399 static void 400 fetch_texel_2d_rgba_dxt1(const struct swrast_texture_image *texImage, 401 GLint i, GLint j, GLint k, GLubyte *texel) 402 { 403 (void) k; 404 if (fetch_ext_rgba_dxt1) { 405 GLint sliceOffset = k ? texImage->ImageOffsets[k] / 2 : 0; 406 fetch_ext_rgba_dxt1(texImage->RowStride, 407 texImage->Map + sliceOffset, i, j, texel); 408 } 409 else 410 _mesa_debug(NULL, "attempted to decode s3tc texture without library available: fetch_texel_2d_rgba_dxt1\n"); 411 } 412 413 414 void 415 _mesa_fetch_texel_rgba_dxt1(const struct swrast_texture_image *texImage, 416 GLint i, GLint j, GLint k, GLfloat *texel) 417 { 418 /* just sample as GLubyte and convert to float here */ 419 GLubyte rgba[4]; 420 fetch_texel_2d_rgba_dxt1(texImage, i, j, k, rgba); 421 texel[RCOMP] = UBYTE_TO_FLOAT(rgba[RCOMP]); 422 texel[GCOMP] = UBYTE_TO_FLOAT(rgba[GCOMP]); 423 texel[BCOMP] = UBYTE_TO_FLOAT(rgba[BCOMP]); 424 texel[ACOMP] = UBYTE_TO_FLOAT(rgba[ACOMP]); 425 } 426 427 428 static void 429 fetch_texel_2d_rgba_dxt3(const struct swrast_texture_image *texImage, 430 GLint i, GLint j, GLint k, GLubyte *texel) 431 { 432 (void) k; 433 if (fetch_ext_rgba_dxt3) { 434 GLint sliceOffset = k ? texImage->ImageOffsets[k] : 0; 435 fetch_ext_rgba_dxt3(texImage->RowStride, 436 texImage->Map + sliceOffset, i, j, texel); 437 } 438 else 439 _mesa_debug(NULL, "attempted to decode s3tc texture without library available: fetch_texel_2d_rgba_dxt3\n"); 440 } 441 442 443 void 444 _mesa_fetch_texel_rgba_dxt3(const struct swrast_texture_image *texImage, 445 GLint i, GLint j, GLint k, GLfloat *texel) 446 { 447 /* just sample as GLubyte and convert to float here */ 448 GLubyte rgba[4]; 449 fetch_texel_2d_rgba_dxt3(texImage, i, j, k, rgba); 450 texel[RCOMP] = UBYTE_TO_FLOAT(rgba[RCOMP]); 451 texel[GCOMP] = UBYTE_TO_FLOAT(rgba[GCOMP]); 452 texel[BCOMP] = UBYTE_TO_FLOAT(rgba[BCOMP]); 453 texel[ACOMP] = UBYTE_TO_FLOAT(rgba[ACOMP]); 454 } 455 456 457 static void 458 fetch_texel_2d_rgba_dxt5(const struct swrast_texture_image *texImage, 459 GLint i, GLint j, GLint k, GLubyte *texel) 460 { 461 (void) k; 462 if (fetch_ext_rgba_dxt5) { 463 GLint sliceOffset = k ? texImage->ImageOffsets[k] : 0; 464 fetch_ext_rgba_dxt5(texImage->RowStride, 465 texImage->Map + sliceOffset, i, j, texel); 466 } 467 else 468 _mesa_debug(NULL, "attempted to decode s3tc texture without library available: fetch_texel_2d_rgba_dxt5\n"); 469 } 470 471 472 void 473 _mesa_fetch_texel_rgba_dxt5(const struct swrast_texture_image *texImage, 474 GLint i, GLint j, GLint k, GLfloat *texel) 475 { 476 /* just sample as GLubyte and convert to float here */ 477 GLubyte rgba[4]; 478 fetch_texel_2d_rgba_dxt5(texImage, i, j, k, rgba); 479 texel[RCOMP] = UBYTE_TO_FLOAT(rgba[RCOMP]); 480 texel[GCOMP] = UBYTE_TO_FLOAT(rgba[GCOMP]); 481 texel[BCOMP] = UBYTE_TO_FLOAT(rgba[BCOMP]); 482 texel[ACOMP] = UBYTE_TO_FLOAT(rgba[ACOMP]); 483 } 484 485 #if FEATURE_EXT_texture_sRGB 486 void 487 _mesa_fetch_texel_srgb_dxt1(const struct swrast_texture_image *texImage, 488 GLint i, GLint j, GLint k, GLfloat *texel) 489 { 490 /* just sample as GLubyte and convert to float here */ 491 GLubyte rgba[4]; 492 fetch_texel_2d_rgb_dxt1(texImage, i, j, k, rgba); 493 texel[RCOMP] = nonlinear_to_linear(rgba[RCOMP]); 494 texel[GCOMP] = nonlinear_to_linear(rgba[GCOMP]); 495 texel[BCOMP] = nonlinear_to_linear(rgba[BCOMP]); 496 texel[ACOMP] = UBYTE_TO_FLOAT(rgba[ACOMP]); 497 } 498 499 void 500 _mesa_fetch_texel_srgba_dxt1(const struct swrast_texture_image *texImage, 501 GLint i, GLint j, GLint k, GLfloat *texel) 502 { 503 /* just sample as GLubyte and convert to float here */ 504 GLubyte rgba[4]; 505 fetch_texel_2d_rgba_dxt1(texImage, i, j, k, rgba); 506 texel[RCOMP] = nonlinear_to_linear(rgba[RCOMP]); 507 texel[GCOMP] = nonlinear_to_linear(rgba[GCOMP]); 508 texel[BCOMP] = nonlinear_to_linear(rgba[BCOMP]); 509 texel[ACOMP] = UBYTE_TO_FLOAT(rgba[ACOMP]); 510 } 511 512 void 513 _mesa_fetch_texel_srgba_dxt3(const struct swrast_texture_image *texImage, 514 GLint i, GLint j, GLint k, GLfloat *texel) 515 { 516 /* just sample as GLubyte and convert to float here */ 517 GLubyte rgba[4]; 518 fetch_texel_2d_rgba_dxt3(texImage, i, j, k, rgba); 519 texel[RCOMP] = nonlinear_to_linear(rgba[RCOMP]); 520 texel[GCOMP] = nonlinear_to_linear(rgba[GCOMP]); 521 texel[BCOMP] = nonlinear_to_linear(rgba[BCOMP]); 522 texel[ACOMP] = UBYTE_TO_FLOAT(rgba[ACOMP]); 523 } 524 525 void 526 _mesa_fetch_texel_srgba_dxt5(const struct swrast_texture_image *texImage, 527 GLint i, GLint j, GLint k, GLfloat *texel) 528 { 529 /* just sample as GLubyte and convert to float here */ 530 GLubyte rgba[4]; 531 fetch_texel_2d_rgba_dxt5(texImage, i, j, k, rgba); 532 texel[RCOMP] = nonlinear_to_linear(rgba[RCOMP]); 533 texel[GCOMP] = nonlinear_to_linear(rgba[GCOMP]); 534 texel[BCOMP] = nonlinear_to_linear(rgba[BCOMP]); 535 texel[ACOMP] = UBYTE_TO_FLOAT(rgba[ACOMP]); 536 } 537 #endif /* FEATURE_EXT_texture_sRGB */ 538 539 540 #endif /* FEATURE_texture_s3tc */ 541