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