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