main: Add entry points for ClearNamedBuffer[Sub]Data.
[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 GLubyte *tempImageSlices[1];
146 int rgbRowStride = 3 * srcWidth * sizeof(GLubyte);
147 tempImage = malloc(srcWidth * srcHeight * 3 * sizeof(GLubyte));
148 if (!tempImage)
149 return GL_FALSE; /* out of memory */
150 tempImageSlices[0] = (GLubyte *) tempImage;
151 _mesa_texstore(ctx, dims,
152 baseInternalFormat,
153 MESA_FORMAT_RGB_UNORM8,
154 rgbRowStride, tempImageSlices,
155 srcWidth, srcHeight, srcDepth,
156 srcFormat, srcType, srcAddr,
157 srcPacking);
158 pixels = tempImage;
159 srcFormat = GL_RGB;
160 }
161 else {
162 pixels = _mesa_image_address2d(srcPacking, srcAddr, srcWidth, srcHeight,
163 srcFormat, srcType, 0, 0);
164 }
165
166 dst = dstSlices[0];
167
168 if (ext_tx_compress_dxtn) {
169 (*ext_tx_compress_dxtn)(3, srcWidth, srcHeight, pixels,
170 GL_COMPRESSED_RGB_S3TC_DXT1_EXT,
171 dst, dstRowStride);
172 }
173 else {
174 _mesa_warning(ctx, "external dxt library not available: texstore_rgb_dxt1");
175 }
176
177 free((void *) tempImage);
178
179 return GL_TRUE;
180 }
181
182
183 /**
184 * Store user's image in rgba_dxt1 format.
185 */
186 GLboolean
187 _mesa_texstore_rgba_dxt1(TEXSTORE_PARAMS)
188 {
189 const GLubyte *pixels;
190 GLubyte *dst;
191 const GLubyte *tempImage = NULL;
192
193 assert(dstFormat == MESA_FORMAT_RGBA_DXT1 ||
194 dstFormat == MESA_FORMAT_SRGBA_DXT1);
195
196 if (srcFormat != GL_RGBA ||
197 srcType != GL_UNSIGNED_BYTE ||
198 ctx->_ImageTransferState ||
199 srcPacking->RowLength != srcWidth ||
200 srcPacking->SwapBytes) {
201 /* convert image to RGBA/GLubyte */
202 GLubyte *tempImageSlices[1];
203 int rgbaRowStride = 4 * srcWidth * sizeof(GLubyte);
204 tempImage = malloc(srcWidth * srcHeight * 4 * sizeof(GLubyte));
205 if (!tempImage)
206 return GL_FALSE; /* out of memory */
207 tempImageSlices[0] = (GLubyte *) tempImage;
208 _mesa_texstore(ctx, dims,
209 baseInternalFormat,
210 MESA_FORMAT_R8G8B8A8_UNORM,
211 rgbaRowStride, tempImageSlices,
212 srcWidth, srcHeight, srcDepth,
213 srcFormat, srcType, srcAddr,
214 srcPacking);
215 pixels = tempImage;
216 srcFormat = GL_RGBA;
217 }
218 else {
219 pixels = _mesa_image_address2d(srcPacking, srcAddr, srcWidth, srcHeight,
220 srcFormat, srcType, 0, 0);
221 }
222
223 dst = dstSlices[0];
224
225 if (ext_tx_compress_dxtn) {
226 (*ext_tx_compress_dxtn)(4, srcWidth, srcHeight, pixels,
227 GL_COMPRESSED_RGBA_S3TC_DXT1_EXT,
228 dst, dstRowStride);
229 }
230 else {
231 _mesa_warning(ctx, "external dxt library not available: texstore_rgba_dxt1");
232 }
233
234 free((void*) tempImage);
235
236 return GL_TRUE;
237 }
238
239
240 /**
241 * Store user's image in rgba_dxt3 format.
242 */
243 GLboolean
244 _mesa_texstore_rgba_dxt3(TEXSTORE_PARAMS)
245 {
246 const GLubyte *pixels;
247 GLubyte *dst;
248 const GLubyte *tempImage = NULL;
249
250 assert(dstFormat == MESA_FORMAT_RGBA_DXT3 ||
251 dstFormat == MESA_FORMAT_SRGBA_DXT3);
252
253 if (srcFormat != GL_RGBA ||
254 srcType != GL_UNSIGNED_BYTE ||
255 ctx->_ImageTransferState ||
256 srcPacking->RowLength != srcWidth ||
257 srcPacking->SwapBytes) {
258 /* convert image to RGBA/GLubyte */
259 GLubyte *tempImageSlices[1];
260 int rgbaRowStride = 4 * srcWidth * sizeof(GLubyte);
261 tempImage = malloc(srcWidth * srcHeight * 4 * sizeof(GLubyte));
262 if (!tempImage)
263 return GL_FALSE; /* out of memory */
264 tempImageSlices[0] = (GLubyte *) tempImage;
265 _mesa_texstore(ctx, dims,
266 baseInternalFormat,
267 MESA_FORMAT_R8G8B8A8_UNORM,
268 rgbaRowStride, tempImageSlices,
269 srcWidth, srcHeight, srcDepth,
270 srcFormat, srcType, srcAddr,
271 srcPacking);
272 pixels = tempImage;
273 }
274 else {
275 pixels = _mesa_image_address2d(srcPacking, srcAddr, srcWidth, srcHeight,
276 srcFormat, srcType, 0, 0);
277 }
278
279 dst = dstSlices[0];
280
281 if (ext_tx_compress_dxtn) {
282 (*ext_tx_compress_dxtn)(4, srcWidth, srcHeight, pixels,
283 GL_COMPRESSED_RGBA_S3TC_DXT3_EXT,
284 dst, dstRowStride);
285 }
286 else {
287 _mesa_warning(ctx, "external dxt library not available: texstore_rgba_dxt3");
288 }
289
290 free((void *) tempImage);
291
292 return GL_TRUE;
293 }
294
295
296 /**
297 * Store user's image in rgba_dxt5 format.
298 */
299 GLboolean
300 _mesa_texstore_rgba_dxt5(TEXSTORE_PARAMS)
301 {
302 const GLubyte *pixels;
303 GLubyte *dst;
304 const GLubyte *tempImage = NULL;
305
306 assert(dstFormat == MESA_FORMAT_RGBA_DXT5 ||
307 dstFormat == MESA_FORMAT_SRGBA_DXT5);
308
309 if (srcFormat != GL_RGBA ||
310 srcType != GL_UNSIGNED_BYTE ||
311 ctx->_ImageTransferState ||
312 srcPacking->RowLength != srcWidth ||
313 srcPacking->SwapBytes) {
314 /* convert image to RGBA/GLubyte */
315 GLubyte *tempImageSlices[1];
316 int rgbaRowStride = 4 * srcWidth * sizeof(GLubyte);
317 tempImage = malloc(srcWidth * srcHeight * 4 * sizeof(GLubyte));
318 if (!tempImage)
319 return GL_FALSE; /* out of memory */
320 tempImageSlices[0] = (GLubyte *) tempImage;
321 _mesa_texstore(ctx, dims,
322 baseInternalFormat,
323 MESA_FORMAT_R8G8B8A8_UNORM,
324 rgbaRowStride, tempImageSlices,
325 srcWidth, srcHeight, srcDepth,
326 srcFormat, srcType, srcAddr,
327 srcPacking);
328 pixels = tempImage;
329 }
330 else {
331 pixels = _mesa_image_address2d(srcPacking, srcAddr, srcWidth, srcHeight,
332 srcFormat, srcType, 0, 0);
333 }
334
335 dst = dstSlices[0];
336
337 if (ext_tx_compress_dxtn) {
338 (*ext_tx_compress_dxtn)(4, srcWidth, srcHeight, pixels,
339 GL_COMPRESSED_RGBA_S3TC_DXT5_EXT,
340 dst, dstRowStride);
341 }
342 else {
343 _mesa_warning(ctx, "external dxt library not available: texstore_rgba_dxt5");
344 }
345
346 free((void *) tempImage);
347
348 return GL_TRUE;
349 }
350
351
352 /** Report problem with dxt texture decompression, once */
353 static void
354 problem(const char *func)
355 {
356 static GLboolean warned = GL_FALSE;
357 if (!warned) {
358 _mesa_debug(NULL, "attempted to decode DXT texture without "
359 "library available: %s\n", func);
360 warned = GL_TRUE;
361 }
362 }
363
364
365 static void
366 fetch_rgb_dxt1(const GLubyte *map,
367 GLint rowStride, GLint i, GLint j, GLfloat *texel)
368 {
369 if (fetch_ext_rgb_dxt1) {
370 GLubyte tex[4];
371 fetch_ext_rgb_dxt1(rowStride, map, i, j, tex);
372 texel[RCOMP] = UBYTE_TO_FLOAT(tex[RCOMP]);
373 texel[GCOMP] = UBYTE_TO_FLOAT(tex[GCOMP]);
374 texel[BCOMP] = UBYTE_TO_FLOAT(tex[BCOMP]);
375 texel[ACOMP] = UBYTE_TO_FLOAT(tex[ACOMP]);
376 }
377 else {
378 problem("rgb_dxt1");
379 }
380 }
381
382 static void
383 fetch_rgba_dxt1(const GLubyte *map,
384 GLint rowStride, GLint i, GLint j, GLfloat *texel)
385 {
386 if (fetch_ext_rgba_dxt1) {
387 GLubyte tex[4];
388 fetch_ext_rgba_dxt1(rowStride, map, i, j, tex);
389 texel[RCOMP] = UBYTE_TO_FLOAT(tex[RCOMP]);
390 texel[GCOMP] = UBYTE_TO_FLOAT(tex[GCOMP]);
391 texel[BCOMP] = UBYTE_TO_FLOAT(tex[BCOMP]);
392 texel[ACOMP] = UBYTE_TO_FLOAT(tex[ACOMP]);
393 }
394 else {
395 problem("rgba_dxt1");
396 }
397 }
398
399 static void
400 fetch_rgba_dxt3(const GLubyte *map,
401 GLint rowStride, GLint i, GLint j, GLfloat *texel)
402 {
403 if (fetch_ext_rgba_dxt3) {
404 GLubyte tex[4];
405 fetch_ext_rgba_dxt3(rowStride, map, i, j, tex);
406 texel[RCOMP] = UBYTE_TO_FLOAT(tex[RCOMP]);
407 texel[GCOMP] = UBYTE_TO_FLOAT(tex[GCOMP]);
408 texel[BCOMP] = UBYTE_TO_FLOAT(tex[BCOMP]);
409 texel[ACOMP] = UBYTE_TO_FLOAT(tex[ACOMP]);
410 }
411 else {
412 problem("rgba_dxt3");
413 }
414 }
415
416 static void
417 fetch_rgba_dxt5(const GLubyte *map,
418 GLint rowStride, GLint i, GLint j, GLfloat *texel)
419 {
420 if (fetch_ext_rgba_dxt5) {
421 GLubyte tex[4];
422 fetch_ext_rgba_dxt5(rowStride, map, i, j, tex);
423 texel[RCOMP] = UBYTE_TO_FLOAT(tex[RCOMP]);
424 texel[GCOMP] = UBYTE_TO_FLOAT(tex[GCOMP]);
425 texel[BCOMP] = UBYTE_TO_FLOAT(tex[BCOMP]);
426 texel[ACOMP] = UBYTE_TO_FLOAT(tex[ACOMP]);
427 }
428 else {
429 problem("rgba_dxt5");
430 }
431 }
432
433
434 static void
435 fetch_srgb_dxt1(const GLubyte *map,
436 GLint rowStride, GLint i, GLint j, GLfloat *texel)
437 {
438 if (fetch_ext_rgb_dxt1) {
439 GLubyte tex[4];
440 fetch_ext_rgb_dxt1(rowStride, map, i, j, tex);
441 texel[RCOMP] = util_format_srgb_8unorm_to_linear_float(tex[RCOMP]);
442 texel[GCOMP] = util_format_srgb_8unorm_to_linear_float(tex[GCOMP]);
443 texel[BCOMP] = util_format_srgb_8unorm_to_linear_float(tex[BCOMP]);
444 texel[ACOMP] = UBYTE_TO_FLOAT(tex[ACOMP]);
445 }
446 else {
447 problem("srgb_dxt1");
448 }
449 }
450
451 static void
452 fetch_srgba_dxt1(const GLubyte *map,
453 GLint rowStride, GLint i, GLint j, GLfloat *texel)
454 {
455 if (fetch_ext_rgba_dxt1) {
456 GLubyte tex[4];
457 fetch_ext_rgba_dxt1(rowStride, map, i, j, tex);
458 texel[RCOMP] = util_format_srgb_8unorm_to_linear_float(tex[RCOMP]);
459 texel[GCOMP] = util_format_srgb_8unorm_to_linear_float(tex[GCOMP]);
460 texel[BCOMP] = util_format_srgb_8unorm_to_linear_float(tex[BCOMP]);
461 texel[ACOMP] = UBYTE_TO_FLOAT(tex[ACOMP]);
462 }
463 else {
464 problem("srgba_dxt1");
465 }
466 }
467
468 static void
469 fetch_srgba_dxt3(const GLubyte *map,
470 GLint rowStride, GLint i, GLint j, GLfloat *texel)
471 {
472 if (fetch_ext_rgba_dxt3) {
473 GLubyte tex[4];
474 fetch_ext_rgba_dxt3(rowStride, map, i, j, tex);
475 texel[RCOMP] = util_format_srgb_8unorm_to_linear_float(tex[RCOMP]);
476 texel[GCOMP] = util_format_srgb_8unorm_to_linear_float(tex[GCOMP]);
477 texel[BCOMP] = util_format_srgb_8unorm_to_linear_float(tex[BCOMP]);
478 texel[ACOMP] = UBYTE_TO_FLOAT(tex[ACOMP]);
479 }
480 else {
481 problem("srgba_dxt3");
482 }
483 }
484
485 static void
486 fetch_srgba_dxt5(const GLubyte *map,
487 GLint rowStride, GLint i, GLint j, GLfloat *texel)
488 {
489 if (fetch_ext_rgba_dxt5) {
490 GLubyte tex[4];
491 fetch_ext_rgba_dxt5(rowStride, map, i, j, tex);
492 texel[RCOMP] = util_format_srgb_8unorm_to_linear_float(tex[RCOMP]);
493 texel[GCOMP] = util_format_srgb_8unorm_to_linear_float(tex[GCOMP]);
494 texel[BCOMP] = util_format_srgb_8unorm_to_linear_float(tex[BCOMP]);
495 texel[ACOMP] = UBYTE_TO_FLOAT(tex[ACOMP]);
496 }
497 else {
498 problem("srgba_dxt5");
499 }
500 }
501
502
503
504 compressed_fetch_func
505 _mesa_get_dxt_fetch_func(mesa_format format)
506 {
507 switch (format) {
508 case MESA_FORMAT_RGB_DXT1:
509 return fetch_rgb_dxt1;
510 case MESA_FORMAT_RGBA_DXT1:
511 return fetch_rgba_dxt1;
512 case MESA_FORMAT_RGBA_DXT3:
513 return fetch_rgba_dxt3;
514 case MESA_FORMAT_RGBA_DXT5:
515 return fetch_rgba_dxt5;
516 case MESA_FORMAT_SRGB_DXT1:
517 return fetch_srgb_dxt1;
518 case MESA_FORMAT_SRGBA_DXT1:
519 return fetch_srgba_dxt1;
520 case MESA_FORMAT_SRGBA_DXT3:
521 return fetch_srgba_dxt3;
522 case MESA_FORMAT_SRGBA_DXT5:
523 return fetch_srgba_dxt5;
524 default:
525 return NULL;
526 }
527 }