texcompress_s3tc.c revision 3464ebd5
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 48 49#if FEATURE_texture_s3tc 50 51 52#if defined(_WIN32) || defined(WIN32) 53#define DXTN_LIBNAME "dxtn.dll" 54#define RTLD_LAZY 0 55#define RTLD_GLOBAL 0 56#elif defined(__DJGPP__) 57#define DXTN_LIBNAME "dxtn.dxe" 58#else 59#define DXTN_LIBNAME "libtxc_dxtn.so" 60#endif 61 62#if FEATURE_EXT_texture_sRGB 63/** 64 * Convert an 8-bit sRGB value from non-linear space to a 65 * linear RGB value in [0, 1]. 66 * Implemented with a 256-entry lookup table. 67 */ 68static INLINE GLfloat 69nonlinear_to_linear(GLubyte cs8) 70{ 71 static GLfloat table[256]; 72 static GLboolean tableReady = GL_FALSE; 73 if (!tableReady) { 74 /* compute lookup table now */ 75 GLuint i; 76 for (i = 0; i < 256; i++) { 77 const GLfloat cs = UBYTE_TO_FLOAT(i); 78 if (cs <= 0.04045) { 79 table[i] = cs / 12.92f; 80 } 81 else { 82 table[i] = (GLfloat) pow((cs + 0.055) / 1.055, 2.4); 83 } 84 } 85 tableReady = GL_TRUE; 86 } 87 return table[cs8]; 88} 89#endif /* FEATURE_EXT_texture_sRGB */ 90 91typedef void (*dxtFetchTexelFuncExt)( GLint srcRowstride, GLubyte *pixdata, GLint col, GLint row, GLvoid *texelOut ); 92 93dxtFetchTexelFuncExt fetch_ext_rgb_dxt1 = NULL; 94dxtFetchTexelFuncExt fetch_ext_rgba_dxt1 = NULL; 95dxtFetchTexelFuncExt fetch_ext_rgba_dxt3 = NULL; 96dxtFetchTexelFuncExt fetch_ext_rgba_dxt5 = NULL; 97 98typedef void (*dxtCompressTexFuncExt)(GLint srccomps, GLint width, 99 GLint height, const GLchan *srcPixData, 100 GLenum destformat, GLubyte *dest, 101 GLint dstRowStride); 102 103static dxtCompressTexFuncExt ext_tx_compress_dxtn = NULL; 104 105static void *dxtlibhandle = NULL; 106 107 108void 109_mesa_init_texture_s3tc( struct gl_context *ctx ) 110{ 111 /* called during context initialization */ 112 ctx->Mesa_DXTn = GL_FALSE; 113#if USE_EXTERNAL_DXTN_LIB 114 if (!dxtlibhandle) { 115 dxtlibhandle = _mesa_dlopen(DXTN_LIBNAME, 0); 116 if (!dxtlibhandle) { 117 _mesa_warning(ctx, "couldn't open " DXTN_LIBNAME ", software DXTn " 118 "compression/decompression unavailable"); 119 } 120 else { 121 /* the fetch functions are not per context! Might be problematic... */ 122 fetch_ext_rgb_dxt1 = (dxtFetchTexelFuncExt) 123 _mesa_dlsym(dxtlibhandle, "fetch_2d_texel_rgb_dxt1"); 124 fetch_ext_rgba_dxt1 = (dxtFetchTexelFuncExt) 125 _mesa_dlsym(dxtlibhandle, "fetch_2d_texel_rgba_dxt1"); 126 fetch_ext_rgba_dxt3 = (dxtFetchTexelFuncExt) 127 _mesa_dlsym(dxtlibhandle, "fetch_2d_texel_rgba_dxt3"); 128 fetch_ext_rgba_dxt5 = (dxtFetchTexelFuncExt) 129 _mesa_dlsym(dxtlibhandle, "fetch_2d_texel_rgba_dxt5"); 130 ext_tx_compress_dxtn = (dxtCompressTexFuncExt) 131 _mesa_dlsym(dxtlibhandle, "tx_compress_dxtn"); 132 133 if (!fetch_ext_rgb_dxt1 || 134 !fetch_ext_rgba_dxt1 || 135 !fetch_ext_rgba_dxt3 || 136 !fetch_ext_rgba_dxt5 || 137 !ext_tx_compress_dxtn) { 138 _mesa_warning(ctx, "couldn't reference all symbols in " 139 DXTN_LIBNAME ", software DXTn compression/decompression " 140 "unavailable"); 141 fetch_ext_rgb_dxt1 = NULL; 142 fetch_ext_rgba_dxt1 = NULL; 143 fetch_ext_rgba_dxt3 = NULL; 144 fetch_ext_rgba_dxt5 = NULL; 145 ext_tx_compress_dxtn = NULL; 146 _mesa_dlclose(dxtlibhandle); 147 dxtlibhandle = NULL; 148 } 149 } 150 } 151 if (dxtlibhandle) { 152 ctx->Mesa_DXTn = GL_TRUE; 153 } 154#else 155 (void) ctx; 156#endif 157} 158 159/** 160 * Store user's image in rgb_dxt1 format. 161 */ 162GLboolean 163_mesa_texstore_rgb_dxt1(TEXSTORE_PARAMS) 164{ 165 const GLchan *pixels; 166 GLubyte *dst; 167 const GLint texWidth = dstRowStride * 4 / 8; /* a bit of a hack */ 168 const GLchan *tempImage = NULL; 169 170 ASSERT(dstFormat == MESA_FORMAT_RGB_DXT1 || 171 dstFormat == MESA_FORMAT_SRGB_DXT1); 172 ASSERT(dstXoffset % 4 == 0); 173 ASSERT(dstYoffset % 4 == 0); 174 ASSERT(dstZoffset % 4 == 0); 175 (void) dstZoffset; 176 (void) dstImageOffsets; 177 178 if (srcFormat != GL_RGB || 179 srcType != CHAN_TYPE || 180 ctx->_ImageTransferState || 181 srcPacking->SwapBytes) { 182 /* convert image to RGB/GLchan */ 183 tempImage = _mesa_make_temp_chan_image(ctx, dims, 184 baseInternalFormat, 185 _mesa_get_format_base_format(dstFormat), 186 srcWidth, srcHeight, srcDepth, 187 srcFormat, srcType, srcAddr, 188 srcPacking); 189 if (!tempImage) 190 return GL_FALSE; /* out of memory */ 191 pixels = tempImage; 192 srcFormat = GL_RGB; 193 } 194 else { 195 pixels = (const GLchan *) srcAddr; 196 } 197 198 dst = _mesa_compressed_image_address(dstXoffset, dstYoffset, 0, 199 dstFormat, 200 texWidth, (GLubyte *) dstAddr); 201 202 if (ext_tx_compress_dxtn) { 203 (*ext_tx_compress_dxtn)(3, srcWidth, srcHeight, pixels, 204 GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 205 dst, dstRowStride); 206 } 207 else { 208 _mesa_warning(ctx, "external dxt library not available: texstore_rgb_dxt1"); 209 } 210 211 if (tempImage) 212 free((void *) tempImage); 213 214 return GL_TRUE; 215} 216 217 218/** 219 * Store user's image in rgba_dxt1 format. 220 */ 221GLboolean 222_mesa_texstore_rgba_dxt1(TEXSTORE_PARAMS) 223{ 224 const GLchan *pixels; 225 GLubyte *dst; 226 const GLint texWidth = dstRowStride * 4 / 8; /* a bit of a hack */ 227 const GLchan *tempImage = NULL; 228 229 ASSERT(dstFormat == MESA_FORMAT_RGBA_DXT1 || 230 dstFormat == MESA_FORMAT_SRGBA_DXT1); 231 ASSERT(dstXoffset % 4 == 0); 232 ASSERT(dstYoffset % 4 == 0); 233 ASSERT(dstZoffset % 4 == 0); 234 (void) dstZoffset; 235 (void) dstImageOffsets; 236 237 if (srcFormat != GL_RGBA || 238 srcType != CHAN_TYPE || 239 ctx->_ImageTransferState || 240 srcPacking->SwapBytes) { 241 /* convert image to RGBA/GLchan */ 242 tempImage = _mesa_make_temp_chan_image(ctx, dims, 243 baseInternalFormat, 244 _mesa_get_format_base_format(dstFormat), 245 srcWidth, srcHeight, srcDepth, 246 srcFormat, srcType, srcAddr, 247 srcPacking); 248 if (!tempImage) 249 return GL_FALSE; /* out of memory */ 250 pixels = tempImage; 251 srcFormat = GL_RGBA; 252 } 253 else { 254 pixels = (const GLchan *) srcAddr; 255 } 256 257 dst = _mesa_compressed_image_address(dstXoffset, dstYoffset, 0, 258 dstFormat, 259 texWidth, (GLubyte *) dstAddr); 260 if (ext_tx_compress_dxtn) { 261 (*ext_tx_compress_dxtn)(4, srcWidth, srcHeight, pixels, 262 GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, 263 dst, dstRowStride); 264 } 265 else { 266 _mesa_warning(ctx, "external dxt library not available: texstore_rgba_dxt1"); 267 } 268 269 if (tempImage) 270 free((void*) tempImage); 271 272 return GL_TRUE; 273} 274 275 276/** 277 * Store user's image in rgba_dxt3 format. 278 */ 279GLboolean 280_mesa_texstore_rgba_dxt3(TEXSTORE_PARAMS) 281{ 282 const GLchan *pixels; 283 GLubyte *dst; 284 const GLint texWidth = dstRowStride * 4 / 16; /* a bit of a hack */ 285 const GLchan *tempImage = NULL; 286 287 ASSERT(dstFormat == MESA_FORMAT_RGBA_DXT3 || 288 dstFormat == MESA_FORMAT_SRGBA_DXT3); 289 ASSERT(dstXoffset % 4 == 0); 290 ASSERT(dstYoffset % 4 == 0); 291 ASSERT(dstZoffset % 4 == 0); 292 (void) dstZoffset; 293 (void) dstImageOffsets; 294 295 if (srcFormat != GL_RGBA || 296 srcType != CHAN_TYPE || 297 ctx->_ImageTransferState || 298 srcPacking->SwapBytes) { 299 /* convert image to RGBA/GLchan */ 300 tempImage = _mesa_make_temp_chan_image(ctx, dims, 301 baseInternalFormat, 302 _mesa_get_format_base_format(dstFormat), 303 srcWidth, srcHeight, srcDepth, 304 srcFormat, srcType, srcAddr, 305 srcPacking); 306 if (!tempImage) 307 return GL_FALSE; /* out of memory */ 308 pixels = tempImage; 309 } 310 else { 311 pixels = (const GLchan *) srcAddr; 312 } 313 314 dst = _mesa_compressed_image_address(dstXoffset, dstYoffset, 0, 315 dstFormat, 316 texWidth, (GLubyte *) dstAddr); 317 if (ext_tx_compress_dxtn) { 318 (*ext_tx_compress_dxtn)(4, srcWidth, srcHeight, pixels, 319 GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, 320 dst, dstRowStride); 321 } 322 else { 323 _mesa_warning(ctx, "external dxt library not available: texstore_rgba_dxt3"); 324 } 325 326 if (tempImage) 327 free((void *) tempImage); 328 329 return GL_TRUE; 330} 331 332 333/** 334 * Store user's image in rgba_dxt5 format. 335 */ 336GLboolean 337_mesa_texstore_rgba_dxt5(TEXSTORE_PARAMS) 338{ 339 const GLchan *pixels; 340 GLubyte *dst; 341 const GLint texWidth = dstRowStride * 4 / 16; /* a bit of a hack */ 342 const GLchan *tempImage = NULL; 343 344 ASSERT(dstFormat == MESA_FORMAT_RGBA_DXT5 || 345 dstFormat == MESA_FORMAT_SRGBA_DXT5); 346 ASSERT(dstXoffset % 4 == 0); 347 ASSERT(dstYoffset % 4 == 0); 348 ASSERT(dstZoffset % 4 == 0); 349 (void) dstZoffset; 350 (void) dstImageOffsets; 351 352 if (srcFormat != GL_RGBA || 353 srcType != CHAN_TYPE || 354 ctx->_ImageTransferState || 355 srcPacking->SwapBytes) { 356 /* convert image to RGBA/GLchan */ 357 tempImage = _mesa_make_temp_chan_image(ctx, dims, 358 baseInternalFormat, 359 _mesa_get_format_base_format(dstFormat), 360 srcWidth, srcHeight, srcDepth, 361 srcFormat, srcType, srcAddr, 362 srcPacking); 363 if (!tempImage) 364 return GL_FALSE; /* out of memory */ 365 pixels = tempImage; 366 } 367 else { 368 pixels = (const GLchan *) srcAddr; 369 } 370 371 dst = _mesa_compressed_image_address(dstXoffset, dstYoffset, 0, 372 dstFormat, 373 texWidth, (GLubyte *) dstAddr); 374 if (ext_tx_compress_dxtn) { 375 (*ext_tx_compress_dxtn)(4, srcWidth, srcHeight, pixels, 376 GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, 377 dst, dstRowStride); 378 } 379 else { 380 _mesa_warning(ctx, "external dxt library not available: texstore_rgba_dxt5"); 381 } 382 383 if (tempImage) 384 free((void *) tempImage); 385 386 return GL_TRUE; 387} 388 389 390static void 391fetch_texel_2d_rgb_dxt1( const struct gl_texture_image *texImage, 392 GLint i, GLint j, GLint k, GLchan *texel ) 393{ 394 (void) k; 395 if (fetch_ext_rgb_dxt1) { 396 ASSERT (sizeof(GLchan) == sizeof(GLubyte)); 397 fetch_ext_rgb_dxt1(texImage->RowStride, 398 (GLubyte *)(texImage)->Data, i, j, texel); 399 } 400 else 401 _mesa_debug(NULL, "attempted to decode s3tc texture without library available: fetch_texel_2d_rgb_dxt1"); 402} 403 404 405void 406_mesa_fetch_texel_2d_f_rgb_dxt1(const struct gl_texture_image *texImage, 407 GLint i, GLint j, GLint k, GLfloat *texel) 408{ 409 /* just sample as GLchan and convert to float here */ 410 GLchan rgba[4]; 411 fetch_texel_2d_rgb_dxt1(texImage, i, j, k, rgba); 412 texel[RCOMP] = CHAN_TO_FLOAT(rgba[RCOMP]); 413 texel[GCOMP] = CHAN_TO_FLOAT(rgba[GCOMP]); 414 texel[BCOMP] = CHAN_TO_FLOAT(rgba[BCOMP]); 415 texel[ACOMP] = CHAN_TO_FLOAT(rgba[ACOMP]); 416} 417 418 419static void 420fetch_texel_2d_rgba_dxt1( const struct gl_texture_image *texImage, 421 GLint i, GLint j, GLint k, GLchan *texel ) 422{ 423 (void) k; 424 if (fetch_ext_rgba_dxt1) { 425 fetch_ext_rgba_dxt1(texImage->RowStride, 426 (GLubyte *)(texImage)->Data, i, j, texel); 427 } 428 else 429 _mesa_debug(NULL, "attempted to decode s3tc texture without library available: fetch_texel_2d_rgba_dxt1\n"); 430} 431 432 433void 434_mesa_fetch_texel_2d_f_rgba_dxt1(const struct gl_texture_image *texImage, 435 GLint i, GLint j, GLint k, GLfloat *texel) 436{ 437 /* just sample as GLchan and convert to float here */ 438 GLchan rgba[4]; 439 fetch_texel_2d_rgba_dxt1(texImage, i, j, k, rgba); 440 texel[RCOMP] = CHAN_TO_FLOAT(rgba[RCOMP]); 441 texel[GCOMP] = CHAN_TO_FLOAT(rgba[GCOMP]); 442 texel[BCOMP] = CHAN_TO_FLOAT(rgba[BCOMP]); 443 texel[ACOMP] = CHAN_TO_FLOAT(rgba[ACOMP]); 444} 445 446 447static void 448fetch_texel_2d_rgba_dxt3( const struct gl_texture_image *texImage, 449 GLint i, GLint j, GLint k, GLchan *texel ) 450{ 451 (void) k; 452 if (fetch_ext_rgba_dxt3) { 453 ASSERT (sizeof(GLchan) == sizeof(GLubyte)); 454 fetch_ext_rgba_dxt3(texImage->RowStride, (GLubyte *)(texImage)->Data, 455 i, j, texel); 456 } 457 else 458 _mesa_debug(NULL, "attempted to decode s3tc texture without library available: fetch_texel_2d_rgba_dxt3\n"); 459} 460 461 462void 463_mesa_fetch_texel_2d_f_rgba_dxt3(const struct gl_texture_image *texImage, 464 GLint i, GLint j, GLint k, GLfloat *texel) 465{ 466 /* just sample as GLchan and convert to float here */ 467 GLchan rgba[4]; 468 fetch_texel_2d_rgba_dxt3(texImage, i, j, k, rgba); 469 texel[RCOMP] = CHAN_TO_FLOAT(rgba[RCOMP]); 470 texel[GCOMP] = CHAN_TO_FLOAT(rgba[GCOMP]); 471 texel[BCOMP] = CHAN_TO_FLOAT(rgba[BCOMP]); 472 texel[ACOMP] = CHAN_TO_FLOAT(rgba[ACOMP]); 473} 474 475 476static void 477fetch_texel_2d_rgba_dxt5( const struct gl_texture_image *texImage, 478 GLint i, GLint j, GLint k, GLchan *texel ) 479{ 480 (void) k; 481 if (fetch_ext_rgba_dxt5) { 482 fetch_ext_rgba_dxt5(texImage->RowStride, (GLubyte *)(texImage)->Data, 483 i, j, texel); 484 } 485 else 486 _mesa_debug(NULL, "attempted to decode s3tc texture without library available: fetch_texel_2d_rgba_dxt5\n"); 487} 488 489 490void 491_mesa_fetch_texel_2d_f_rgba_dxt5(const struct gl_texture_image *texImage, 492 GLint i, GLint j, GLint k, GLfloat *texel) 493{ 494 /* just sample as GLchan and convert to float here */ 495 GLchan rgba[4]; 496 fetch_texel_2d_rgba_dxt5(texImage, i, j, k, rgba); 497 texel[RCOMP] = CHAN_TO_FLOAT(rgba[RCOMP]); 498 texel[GCOMP] = CHAN_TO_FLOAT(rgba[GCOMP]); 499 texel[BCOMP] = CHAN_TO_FLOAT(rgba[BCOMP]); 500 texel[ACOMP] = CHAN_TO_FLOAT(rgba[ACOMP]); 501} 502 503#if FEATURE_EXT_texture_sRGB 504void 505_mesa_fetch_texel_2d_f_srgb_dxt1( const struct gl_texture_image *texImage, 506 GLint i, GLint j, GLint k, GLfloat *texel ) 507{ 508 /* just sample as GLchan and convert to float here */ 509 GLchan rgba[4]; 510 fetch_texel_2d_rgb_dxt1(texImage, i, j, k, rgba); 511 texel[RCOMP] = nonlinear_to_linear(rgba[RCOMP]); 512 texel[GCOMP] = nonlinear_to_linear(rgba[GCOMP]); 513 texel[BCOMP] = nonlinear_to_linear(rgba[BCOMP]); 514 texel[ACOMP] = CHAN_TO_FLOAT(rgba[ACOMP]); 515} 516 517void 518_mesa_fetch_texel_2d_f_srgba_dxt1(const struct gl_texture_image *texImage, 519 GLint i, GLint j, GLint k, GLfloat *texel) 520{ 521 /* just sample as GLchan and convert to float here */ 522 GLchan rgba[4]; 523 fetch_texel_2d_rgba_dxt1(texImage, i, j, k, rgba); 524 texel[RCOMP] = nonlinear_to_linear(rgba[RCOMP]); 525 texel[GCOMP] = nonlinear_to_linear(rgba[GCOMP]); 526 texel[BCOMP] = nonlinear_to_linear(rgba[BCOMP]); 527 texel[ACOMP] = CHAN_TO_FLOAT(rgba[ACOMP]); 528} 529 530void 531_mesa_fetch_texel_2d_f_srgba_dxt3(const struct gl_texture_image *texImage, 532 GLint i, GLint j, GLint k, GLfloat *texel) 533{ 534 /* just sample as GLchan and convert to float here */ 535 GLchan rgba[4]; 536 fetch_texel_2d_rgba_dxt3(texImage, i, j, k, rgba); 537 texel[RCOMP] = nonlinear_to_linear(rgba[RCOMP]); 538 texel[GCOMP] = nonlinear_to_linear(rgba[GCOMP]); 539 texel[BCOMP] = nonlinear_to_linear(rgba[BCOMP]); 540 texel[ACOMP] = CHAN_TO_FLOAT(rgba[ACOMP]); 541} 542 543void 544_mesa_fetch_texel_2d_f_srgba_dxt5(const struct gl_texture_image *texImage, 545 GLint i, GLint j, GLint k, GLfloat *texel) 546{ 547 /* just sample as GLchan and convert to float here */ 548 GLchan rgba[4]; 549 fetch_texel_2d_rgba_dxt5(texImage, i, j, k, rgba); 550 texel[RCOMP] = nonlinear_to_linear(rgba[RCOMP]); 551 texel[GCOMP] = nonlinear_to_linear(rgba[GCOMP]); 552 texel[BCOMP] = nonlinear_to_linear(rgba[BCOMP]); 553 texel[ACOMP] = CHAN_TO_FLOAT(rgba[ACOMP]); 554} 555#endif /* FEATURE_EXT_texture_sRGB */ 556 557 558#endif /* FEATURE_texture_s3tc */ 559