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