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