Home | History | Annotate | Download | only in main
      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