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