• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "glheader.h"
33 #include "imports.h"
34 #include "dlopen.h"
35 #include "image.h"
36 #include "macros.h"
37 #include "mtypes.h"
38 #include "texcompress.h"
39 #include "texcompress_s3tc.h"
40 #include "texstore.h"
41 #include "format_unpack.h"
42 #include "util/format_srgb.h"
43 
44 
45 #if defined(_WIN32) || defined(WIN32)
46 #define DXTN_LIBNAME "dxtn.dll"
47 #define RTLD_LAZY 0
48 #define RTLD_GLOBAL 0
49 #elif defined(__CYGWIN__)
50 #define DXTN_LIBNAME "cygtxc_dxtn.dll"
51 #else
52 #define DXTN_LIBNAME "libtxc_dxtn.so"
53 #endif
54 
55 typedef void (*dxtFetchTexelFuncExt)( GLint srcRowstride, const GLubyte *pixdata, GLint col, GLint row, GLvoid *texelOut );
56 
57 static dxtFetchTexelFuncExt fetch_ext_rgb_dxt1 = NULL;
58 static dxtFetchTexelFuncExt fetch_ext_rgba_dxt1 = NULL;
59 static dxtFetchTexelFuncExt fetch_ext_rgba_dxt3 = NULL;
60 static dxtFetchTexelFuncExt fetch_ext_rgba_dxt5 = NULL;
61 
62 typedef void (*dxtCompressTexFuncExt)(GLint srccomps, GLint width,
63                                       GLint height, const GLubyte *srcPixData,
64                                       GLenum destformat, GLubyte *dest,
65                                       GLint dstRowStride);
66 
67 static dxtCompressTexFuncExt ext_tx_compress_dxtn = NULL;
68 
69 static void *dxtlibhandle = NULL;
70 
71 
72 void
_mesa_init_texture_s3tc(struct gl_context * ctx)73 _mesa_init_texture_s3tc( struct gl_context *ctx )
74 {
75    /* called during context initialization */
76    ctx->Mesa_DXTn = GL_FALSE;
77    if (!dxtlibhandle) {
78       dxtlibhandle = _mesa_dlopen(DXTN_LIBNAME, 0);
79       if (!dxtlibhandle) {
80 	 _mesa_warning(ctx, "couldn't open " DXTN_LIBNAME ", software DXTn "
81 	    "compression/decompression unavailable");
82       }
83       else {
84          /* the fetch functions are not per context! Might be problematic... */
85          fetch_ext_rgb_dxt1 = (dxtFetchTexelFuncExt)
86             _mesa_dlsym(dxtlibhandle, "fetch_2d_texel_rgb_dxt1");
87          fetch_ext_rgba_dxt1 = (dxtFetchTexelFuncExt)
88             _mesa_dlsym(dxtlibhandle, "fetch_2d_texel_rgba_dxt1");
89          fetch_ext_rgba_dxt3 = (dxtFetchTexelFuncExt)
90             _mesa_dlsym(dxtlibhandle, "fetch_2d_texel_rgba_dxt3");
91          fetch_ext_rgba_dxt5 = (dxtFetchTexelFuncExt)
92             _mesa_dlsym(dxtlibhandle, "fetch_2d_texel_rgba_dxt5");
93          ext_tx_compress_dxtn = (dxtCompressTexFuncExt)
94             _mesa_dlsym(dxtlibhandle, "tx_compress_dxtn");
95 
96          if (!fetch_ext_rgb_dxt1 ||
97              !fetch_ext_rgba_dxt1 ||
98              !fetch_ext_rgba_dxt3 ||
99              !fetch_ext_rgba_dxt5 ||
100              !ext_tx_compress_dxtn) {
101 	    _mesa_warning(ctx, "couldn't reference all symbols in "
102 	       DXTN_LIBNAME ", software DXTn compression/decompression "
103 	       "unavailable");
104             fetch_ext_rgb_dxt1 = NULL;
105             fetch_ext_rgba_dxt1 = NULL;
106             fetch_ext_rgba_dxt3 = NULL;
107             fetch_ext_rgba_dxt5 = NULL;
108             ext_tx_compress_dxtn = NULL;
109             _mesa_dlclose(dxtlibhandle);
110             dxtlibhandle = NULL;
111          }
112       }
113    }
114    if (dxtlibhandle) {
115       ctx->Mesa_DXTn = GL_TRUE;
116    }
117 }
118 
119 /**
120  * Store user's image in rgb_dxt1 format.
121  */
122 GLboolean
_mesa_texstore_rgb_dxt1(TEXSTORE_PARAMS)123 _mesa_texstore_rgb_dxt1(TEXSTORE_PARAMS)
124 {
125    const GLubyte *pixels;
126    GLubyte *dst;
127    const GLubyte *tempImage = NULL;
128 
129    assert(dstFormat == MESA_FORMAT_RGB_DXT1 ||
130           dstFormat == MESA_FORMAT_SRGB_DXT1);
131 
132    if (srcFormat != GL_RGB ||
133        srcType != GL_UNSIGNED_BYTE ||
134        ctx->_ImageTransferState ||
135        ALIGN(srcPacking->RowLength, srcPacking->Alignment) != srcWidth ||
136        srcPacking->SwapBytes) {
137       /* convert image to RGB/GLubyte */
138       GLubyte *tempImageSlices[1];
139       int rgbRowStride = 3 * srcWidth * sizeof(GLubyte);
140       tempImage = malloc(srcWidth * srcHeight * 3 * sizeof(GLubyte));
141       if (!tempImage)
142          return GL_FALSE; /* out of memory */
143       tempImageSlices[0] = (GLubyte *) tempImage;
144       _mesa_texstore(ctx, dims,
145                      baseInternalFormat,
146                      MESA_FORMAT_RGB_UNORM8,
147                      rgbRowStride, tempImageSlices,
148                      srcWidth, srcHeight, srcDepth,
149                      srcFormat, srcType, srcAddr,
150                      srcPacking);
151       pixels = tempImage;
152       srcFormat = GL_RGB;
153    }
154    else {
155       pixels = _mesa_image_address2d(srcPacking, srcAddr, srcWidth, srcHeight,
156                                      srcFormat, srcType, 0, 0);
157    }
158 
159    dst = dstSlices[0];
160 
161    if (ext_tx_compress_dxtn) {
162       (*ext_tx_compress_dxtn)(3, srcWidth, srcHeight, pixels,
163                               GL_COMPRESSED_RGB_S3TC_DXT1_EXT,
164                               dst, dstRowStride);
165    }
166    else {
167       _mesa_warning(ctx, "external dxt library not available: texstore_rgb_dxt1");
168    }
169 
170    free((void *) tempImage);
171 
172    return GL_TRUE;
173 }
174 
175 
176 /**
177  * Store user's image in rgba_dxt1 format.
178  */
179 GLboolean
_mesa_texstore_rgba_dxt1(TEXSTORE_PARAMS)180 _mesa_texstore_rgba_dxt1(TEXSTORE_PARAMS)
181 {
182    const GLubyte *pixels;
183    GLubyte *dst;
184    const GLubyte *tempImage = NULL;
185 
186    assert(dstFormat == MESA_FORMAT_RGBA_DXT1 ||
187           dstFormat == MESA_FORMAT_SRGBA_DXT1);
188 
189    if (srcFormat != GL_RGBA ||
190        srcType != GL_UNSIGNED_BYTE ||
191        ctx->_ImageTransferState ||
192        ALIGN(srcPacking->RowLength, srcPacking->Alignment) != srcWidth ||
193        srcPacking->SwapBytes) {
194       /* convert image to RGBA/GLubyte */
195       GLubyte *tempImageSlices[1];
196       int rgbaRowStride = 4 * srcWidth * sizeof(GLubyte);
197       tempImage = malloc(srcWidth * srcHeight * 4 * sizeof(GLubyte));
198       if (!tempImage)
199          return GL_FALSE; /* out of memory */
200       tempImageSlices[0] = (GLubyte *) tempImage;
201       _mesa_texstore(ctx, dims,
202                      baseInternalFormat,
203                      _mesa_little_endian() ? MESA_FORMAT_R8G8B8A8_UNORM
204                                            : MESA_FORMAT_A8B8G8R8_UNORM,
205                      rgbaRowStride, tempImageSlices,
206                      srcWidth, srcHeight, srcDepth,
207                      srcFormat, srcType, srcAddr,
208                      srcPacking);
209       pixels = tempImage;
210       srcFormat = GL_RGBA;
211    }
212    else {
213       pixels = _mesa_image_address2d(srcPacking, srcAddr, srcWidth, srcHeight,
214                                      srcFormat, srcType, 0, 0);
215    }
216 
217    dst = dstSlices[0];
218 
219    if (ext_tx_compress_dxtn) {
220       (*ext_tx_compress_dxtn)(4, srcWidth, srcHeight, pixels,
221                               GL_COMPRESSED_RGBA_S3TC_DXT1_EXT,
222                               dst, dstRowStride);
223    }
224    else {
225       _mesa_warning(ctx, "external dxt library not available: texstore_rgba_dxt1");
226    }
227 
228    free((void*) tempImage);
229 
230    return GL_TRUE;
231 }
232 
233 
234 /**
235  * Store user's image in rgba_dxt3 format.
236  */
237 GLboolean
_mesa_texstore_rgba_dxt3(TEXSTORE_PARAMS)238 _mesa_texstore_rgba_dxt3(TEXSTORE_PARAMS)
239 {
240    const GLubyte *pixels;
241    GLubyte *dst;
242    const GLubyte *tempImage = NULL;
243 
244    assert(dstFormat == MESA_FORMAT_RGBA_DXT3 ||
245           dstFormat == MESA_FORMAT_SRGBA_DXT3);
246 
247    if (srcFormat != GL_RGBA ||
248        srcType != GL_UNSIGNED_BYTE ||
249        ctx->_ImageTransferState ||
250        ALIGN(srcPacking->RowLength, srcPacking->Alignment) != srcWidth ||
251        srcPacking->SwapBytes) {
252       /* convert image to RGBA/GLubyte */
253       GLubyte *tempImageSlices[1];
254       int rgbaRowStride = 4 * srcWidth * sizeof(GLubyte);
255       tempImage = malloc(srcWidth * srcHeight * 4 * sizeof(GLubyte));
256       if (!tempImage)
257          return GL_FALSE; /* out of memory */
258       tempImageSlices[0] = (GLubyte *) tempImage;
259       _mesa_texstore(ctx, dims,
260                      baseInternalFormat,
261                      _mesa_little_endian() ? MESA_FORMAT_R8G8B8A8_UNORM
262                                            : MESA_FORMAT_A8B8G8R8_UNORM,
263                      rgbaRowStride, tempImageSlices,
264                      srcWidth, srcHeight, srcDepth,
265                      srcFormat, srcType, srcAddr,
266                      srcPacking);
267       pixels = tempImage;
268    }
269    else {
270       pixels = _mesa_image_address2d(srcPacking, srcAddr, srcWidth, srcHeight,
271                                      srcFormat, srcType, 0, 0);
272    }
273 
274    dst = dstSlices[0];
275 
276    if (ext_tx_compress_dxtn) {
277       (*ext_tx_compress_dxtn)(4, srcWidth, srcHeight, pixels,
278                               GL_COMPRESSED_RGBA_S3TC_DXT3_EXT,
279                               dst, dstRowStride);
280    }
281    else {
282       _mesa_warning(ctx, "external dxt library not available: texstore_rgba_dxt3");
283    }
284 
285    free((void *) tempImage);
286 
287    return GL_TRUE;
288 }
289 
290 
291 /**
292  * Store user's image in rgba_dxt5 format.
293  */
294 GLboolean
_mesa_texstore_rgba_dxt5(TEXSTORE_PARAMS)295 _mesa_texstore_rgba_dxt5(TEXSTORE_PARAMS)
296 {
297    const GLubyte *pixels;
298    GLubyte *dst;
299    const GLubyte *tempImage = NULL;
300 
301    assert(dstFormat == MESA_FORMAT_RGBA_DXT5 ||
302           dstFormat == MESA_FORMAT_SRGBA_DXT5);
303 
304    if (srcFormat != GL_RGBA ||
305        srcType != GL_UNSIGNED_BYTE ||
306        ctx->_ImageTransferState ||
307        ALIGN(srcPacking->RowLength, srcPacking->Alignment) != srcWidth ||
308        srcPacking->SwapBytes) {
309       /* convert image to RGBA/GLubyte */
310       GLubyte *tempImageSlices[1];
311       int rgbaRowStride = 4 * srcWidth * sizeof(GLubyte);
312       tempImage = malloc(srcWidth * srcHeight * 4 * sizeof(GLubyte));
313       if (!tempImage)
314          return GL_FALSE; /* out of memory */
315       tempImageSlices[0] = (GLubyte *) tempImage;
316       _mesa_texstore(ctx, dims,
317                      baseInternalFormat,
318                      _mesa_little_endian() ? MESA_FORMAT_R8G8B8A8_UNORM
319                                            : MESA_FORMAT_A8B8G8R8_UNORM,
320                      rgbaRowStride, tempImageSlices,
321                      srcWidth, srcHeight, srcDepth,
322                      srcFormat, srcType, srcAddr,
323                      srcPacking);
324       pixels = tempImage;
325    }
326    else {
327       pixels = _mesa_image_address2d(srcPacking, srcAddr, srcWidth, srcHeight,
328                                      srcFormat, srcType, 0, 0);
329    }
330 
331    dst = dstSlices[0];
332 
333    if (ext_tx_compress_dxtn) {
334       (*ext_tx_compress_dxtn)(4, srcWidth, srcHeight, pixels,
335                               GL_COMPRESSED_RGBA_S3TC_DXT5_EXT,
336                               dst, dstRowStride);
337    }
338    else {
339       _mesa_warning(ctx, "external dxt library not available: texstore_rgba_dxt5");
340    }
341 
342    free((void *) tempImage);
343 
344    return GL_TRUE;
345 }
346 
347 
348 /** Report problem with dxt texture decompression, once */
349 static void
problem(const char * func)350 problem(const char *func)
351 {
352    static GLboolean warned = GL_FALSE;
353    if (!warned) {
354       _mesa_debug(NULL, "attempted to decode DXT texture without "
355                   "library available: %s\n", func);
356       warned = GL_TRUE;
357    }
358 }
359 
360 
361 static void
fetch_rgb_dxt1(const GLubyte * map,GLint rowStride,GLint i,GLint j,GLfloat * texel)362 fetch_rgb_dxt1(const GLubyte *map,
363                GLint rowStride, GLint i, GLint j, GLfloat *texel)
364 {
365    if (fetch_ext_rgb_dxt1) {
366       GLubyte tex[4];
367       fetch_ext_rgb_dxt1(rowStride, map, i, j, tex);
368       texel[RCOMP] = UBYTE_TO_FLOAT(tex[RCOMP]);
369       texel[GCOMP] = UBYTE_TO_FLOAT(tex[GCOMP]);
370       texel[BCOMP] = UBYTE_TO_FLOAT(tex[BCOMP]);
371       texel[ACOMP] = UBYTE_TO_FLOAT(tex[ACOMP]);
372    }
373    else {
374       problem("rgb_dxt1");
375    }
376 }
377 
378 static void
fetch_rgba_dxt1(const GLubyte * map,GLint rowStride,GLint i,GLint j,GLfloat * texel)379 fetch_rgba_dxt1(const GLubyte *map,
380                 GLint rowStride, GLint i, GLint j, GLfloat *texel)
381 {
382    if (fetch_ext_rgba_dxt1) {
383       GLubyte tex[4];
384       fetch_ext_rgba_dxt1(rowStride, map, i, j, tex);
385       texel[RCOMP] = UBYTE_TO_FLOAT(tex[RCOMP]);
386       texel[GCOMP] = UBYTE_TO_FLOAT(tex[GCOMP]);
387       texel[BCOMP] = UBYTE_TO_FLOAT(tex[BCOMP]);
388       texel[ACOMP] = UBYTE_TO_FLOAT(tex[ACOMP]);
389    }
390    else {
391       problem("rgba_dxt1");
392    }
393 }
394 
395 static void
fetch_rgba_dxt3(const GLubyte * map,GLint rowStride,GLint i,GLint j,GLfloat * texel)396 fetch_rgba_dxt3(const GLubyte *map,
397                 GLint rowStride, GLint i, GLint j, GLfloat *texel)
398 {
399    if (fetch_ext_rgba_dxt3) {
400       GLubyte tex[4];
401       fetch_ext_rgba_dxt3(rowStride, map, i, j, tex);
402       texel[RCOMP] = UBYTE_TO_FLOAT(tex[RCOMP]);
403       texel[GCOMP] = UBYTE_TO_FLOAT(tex[GCOMP]);
404       texel[BCOMP] = UBYTE_TO_FLOAT(tex[BCOMP]);
405       texel[ACOMP] = UBYTE_TO_FLOAT(tex[ACOMP]);
406    }
407    else {
408       problem("rgba_dxt3");
409    }
410 }
411 
412 static void
fetch_rgba_dxt5(const GLubyte * map,GLint rowStride,GLint i,GLint j,GLfloat * texel)413 fetch_rgba_dxt5(const GLubyte *map,
414                 GLint rowStride, GLint i, GLint j, GLfloat *texel)
415 {
416    if (fetch_ext_rgba_dxt5) {
417       GLubyte tex[4];
418       fetch_ext_rgba_dxt5(rowStride, map, i, j, tex);
419       texel[RCOMP] = UBYTE_TO_FLOAT(tex[RCOMP]);
420       texel[GCOMP] = UBYTE_TO_FLOAT(tex[GCOMP]);
421       texel[BCOMP] = UBYTE_TO_FLOAT(tex[BCOMP]);
422       texel[ACOMP] = UBYTE_TO_FLOAT(tex[ACOMP]);
423    }
424    else {
425       problem("rgba_dxt5");
426    }
427 }
428 
429 
430 static void
fetch_srgb_dxt1(const GLubyte * map,GLint rowStride,GLint i,GLint j,GLfloat * texel)431 fetch_srgb_dxt1(const GLubyte *map,
432                 GLint rowStride, GLint i, GLint j, GLfloat *texel)
433 {
434    if (fetch_ext_rgb_dxt1) {
435       GLubyte tex[4];
436       fetch_ext_rgb_dxt1(rowStride, map, i, j, tex);
437       texel[RCOMP] = util_format_srgb_8unorm_to_linear_float(tex[RCOMP]);
438       texel[GCOMP] = util_format_srgb_8unorm_to_linear_float(tex[GCOMP]);
439       texel[BCOMP] = util_format_srgb_8unorm_to_linear_float(tex[BCOMP]);
440       texel[ACOMP] = UBYTE_TO_FLOAT(tex[ACOMP]);
441    }
442    else {
443       problem("srgb_dxt1");
444    }
445 }
446 
447 static void
fetch_srgba_dxt1(const GLubyte * map,GLint rowStride,GLint i,GLint j,GLfloat * texel)448 fetch_srgba_dxt1(const GLubyte *map,
449                  GLint rowStride, GLint i, GLint j, GLfloat *texel)
450 {
451    if (fetch_ext_rgba_dxt1) {
452       GLubyte tex[4];
453       fetch_ext_rgba_dxt1(rowStride, map, i, j, tex);
454       texel[RCOMP] = util_format_srgb_8unorm_to_linear_float(tex[RCOMP]);
455       texel[GCOMP] = util_format_srgb_8unorm_to_linear_float(tex[GCOMP]);
456       texel[BCOMP] = util_format_srgb_8unorm_to_linear_float(tex[BCOMP]);
457       texel[ACOMP] = UBYTE_TO_FLOAT(tex[ACOMP]);
458    }
459    else {
460       problem("srgba_dxt1");
461    }
462 }
463 
464 static void
fetch_srgba_dxt3(const GLubyte * map,GLint rowStride,GLint i,GLint j,GLfloat * texel)465 fetch_srgba_dxt3(const GLubyte *map,
466                  GLint rowStride, GLint i, GLint j, GLfloat *texel)
467 {
468    if (fetch_ext_rgba_dxt3) {
469       GLubyte tex[4];
470       fetch_ext_rgba_dxt3(rowStride, map, i, j, tex);
471       texel[RCOMP] = util_format_srgb_8unorm_to_linear_float(tex[RCOMP]);
472       texel[GCOMP] = util_format_srgb_8unorm_to_linear_float(tex[GCOMP]);
473       texel[BCOMP] = util_format_srgb_8unorm_to_linear_float(tex[BCOMP]);
474       texel[ACOMP] = UBYTE_TO_FLOAT(tex[ACOMP]);
475    }
476    else {
477       problem("srgba_dxt3");
478    }
479 }
480 
481 static void
fetch_srgba_dxt5(const GLubyte * map,GLint rowStride,GLint i,GLint j,GLfloat * texel)482 fetch_srgba_dxt5(const GLubyte *map,
483                  GLint rowStride, GLint i, GLint j, GLfloat *texel)
484 {
485    if (fetch_ext_rgba_dxt5) {
486       GLubyte tex[4];
487       fetch_ext_rgba_dxt5(rowStride, map, i, j, tex);
488       texel[RCOMP] = util_format_srgb_8unorm_to_linear_float(tex[RCOMP]);
489       texel[GCOMP] = util_format_srgb_8unorm_to_linear_float(tex[GCOMP]);
490       texel[BCOMP] = util_format_srgb_8unorm_to_linear_float(tex[BCOMP]);
491       texel[ACOMP] = UBYTE_TO_FLOAT(tex[ACOMP]);
492    }
493    else {
494       problem("srgba_dxt5");
495    }
496 }
497 
498 
499 
500 compressed_fetch_func
_mesa_get_dxt_fetch_func(mesa_format format)501 _mesa_get_dxt_fetch_func(mesa_format format)
502 {
503    switch (format) {
504    case MESA_FORMAT_RGB_DXT1:
505       return fetch_rgb_dxt1;
506    case MESA_FORMAT_RGBA_DXT1:
507       return fetch_rgba_dxt1;
508    case MESA_FORMAT_RGBA_DXT3:
509       return fetch_rgba_dxt3;
510    case MESA_FORMAT_RGBA_DXT5:
511       return fetch_rgba_dxt5;
512    case MESA_FORMAT_SRGB_DXT1:
513       return fetch_srgb_dxt1;
514    case MESA_FORMAT_SRGBA_DXT1:
515       return fetch_srgba_dxt1;
516    case MESA_FORMAT_SRGBA_DXT3:
517       return fetch_srgba_dxt3;
518    case MESA_FORMAT_SRGBA_DXT5:
519       return fetch_srgba_dxt5;
520    default:
521       return NULL;
522    }
523 }
524