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 "util/glheader.h"
33
34 #include "image.h"
35 #include "macros.h"
36 #include "mtypes.h"
37 #include "texcompress.h"
38 #include "texcompress_s3tc.h"
39 #include "util/format/texcompress_s3tc_tmp.h"
40 #include "texstore.h"
41 #include "format_unpack.h"
42 #include "util/format_srgb.h"
43 #include "util/format/u_format_s3tc.h"
44
45
46 /**
47 * Store user's image in rgb_dxt1 format.
48 */
49 GLboolean
_mesa_texstore_rgb_dxt1(TEXSTORE_PARAMS)50 _mesa_texstore_rgb_dxt1(TEXSTORE_PARAMS)
51 {
52 const GLubyte *pixels;
53 GLubyte *dst;
54 const GLubyte *tempImage = NULL;
55 int srccomps = srcFormat == GL_RGB ? 3 : 4;
56
57 assert(dstFormat == MESA_FORMAT_RGB_DXT1 ||
58 dstFormat == MESA_FORMAT_SRGB_DXT1);
59
60 if (!(srcFormat == GL_RGB || srcFormat == GL_RGBA) ||
61 srcType != GL_UNSIGNED_BYTE ||
62 ctx->_ImageTransferState ||
63 _mesa_image_row_stride(srcPacking, srcWidth, srcFormat, srcType) != srccomps * srcWidth * sizeof(GLubyte) ||
64 srcPacking->SkipImages ||
65 srcPacking->SwapBytes) {
66 /* convert image to RGB/GLubyte */
67 GLubyte *tempImageSlices[1];
68 int rgbRowStride = 3 * srcWidth * sizeof(GLubyte);
69 tempImage = malloc(srcWidth * srcHeight * 3 * sizeof(GLubyte));
70 if (!tempImage)
71 return GL_FALSE; /* out of memory */
72 tempImageSlices[0] = (GLubyte *) tempImage;
73 _mesa_texstore(ctx, dims,
74 baseInternalFormat,
75 MESA_FORMAT_RGB_UNORM8,
76 rgbRowStride, tempImageSlices,
77 srcWidth, srcHeight, srcDepth,
78 srcFormat, srcType, srcAddr,
79 srcPacking);
80 pixels = tempImage;
81 srcFormat = GL_RGB;
82 srccomps = 3;
83 }
84 else {
85 pixels = _mesa_image_address2d(srcPacking, srcAddr, srcWidth, srcHeight,
86 srcFormat, srcType, 0, 0);
87 }
88
89 dst = dstSlices[0];
90
91 tx_compress_dxt1(srccomps, srcWidth, srcHeight, pixels,
92 dst, dstRowStride, 3);
93
94 free((void *) tempImage);
95
96 return GL_TRUE;
97 }
98
99
100 /**
101 * Store user's image in rgba_dxt1 format.
102 */
103 GLboolean
_mesa_texstore_rgba_dxt1(TEXSTORE_PARAMS)104 _mesa_texstore_rgba_dxt1(TEXSTORE_PARAMS)
105 {
106 const GLubyte *pixels;
107 GLubyte *dst;
108 const GLubyte *tempImage = NULL;
109 int rgbaRowStride = 4 * srcWidth * sizeof(GLubyte);
110
111 assert(dstFormat == MESA_FORMAT_RGBA_DXT1 ||
112 dstFormat == MESA_FORMAT_SRGBA_DXT1);
113
114 if (srcFormat != GL_RGBA ||
115 srcType != GL_UNSIGNED_BYTE ||
116 ctx->_ImageTransferState ||
117 _mesa_image_row_stride(srcPacking, srcWidth, srcFormat, srcType) != rgbaRowStride ||
118 srcPacking->SkipImages ||
119 srcPacking->SwapBytes) {
120 /* convert image to RGBA/GLubyte */
121 GLubyte *tempImageSlices[1];
122 tempImage = malloc(srcWidth * srcHeight * 4 * sizeof(GLubyte));
123 if (!tempImage)
124 return GL_FALSE; /* out of memory */
125 tempImageSlices[0] = (GLubyte *) tempImage;
126 _mesa_texstore(ctx, dims,
127 baseInternalFormat,
128 #if UTIL_ARCH_LITTLE_ENDIAN
129 MESA_FORMAT_R8G8B8A8_UNORM,
130 #else
131 MESA_FORMAT_A8B8G8R8_UNORM,
132 #endif
133 rgbaRowStride, tempImageSlices,
134 srcWidth, srcHeight, srcDepth,
135 srcFormat, srcType, srcAddr,
136 srcPacking);
137 pixels = tempImage;
138 srcFormat = GL_RGBA;
139 }
140 else {
141 pixels = _mesa_image_address2d(srcPacking, srcAddr, srcWidth, srcHeight,
142 srcFormat, srcType, 0, 0);
143 }
144
145 dst = dstSlices[0];
146
147 tx_compress_dxt1(4, srcWidth, srcHeight, pixels, dst, dstRowStride, 4);
148
149 free((void*) tempImage);
150
151 return GL_TRUE;
152 }
153
154
155 /**
156 * Store user's image in rgba_dxt3 format.
157 */
158 GLboolean
_mesa_texstore_rgba_dxt3(TEXSTORE_PARAMS)159 _mesa_texstore_rgba_dxt3(TEXSTORE_PARAMS)
160 {
161 const GLubyte *pixels;
162 GLubyte *dst;
163 const GLubyte *tempImage = NULL;
164 int rgbaRowStride = 4 * srcWidth * sizeof(GLubyte);
165
166 assert(dstFormat == MESA_FORMAT_RGBA_DXT3 ||
167 dstFormat == MESA_FORMAT_SRGBA_DXT3);
168
169 if (srcFormat != GL_RGBA ||
170 srcType != GL_UNSIGNED_BYTE ||
171 ctx->_ImageTransferState ||
172 _mesa_image_row_stride(srcPacking, srcWidth, srcFormat, srcType) != rgbaRowStride ||
173 srcPacking->SkipImages ||
174 srcPacking->SwapBytes) {
175 /* convert image to RGBA/GLubyte */
176 GLubyte *tempImageSlices[1];
177 tempImage = malloc(srcWidth * srcHeight * 4 * sizeof(GLubyte));
178 if (!tempImage)
179 return GL_FALSE; /* out of memory */
180 tempImageSlices[0] = (GLubyte *) tempImage;
181 _mesa_texstore(ctx, dims,
182 baseInternalFormat,
183 #if UTIL_ARCH_LITTLE_ENDIAN
184 MESA_FORMAT_R8G8B8A8_UNORM,
185 #else
186 MESA_FORMAT_A8B8G8R8_UNORM,
187 #endif
188 rgbaRowStride, tempImageSlices,
189 srcWidth, srcHeight, srcDepth,
190 srcFormat, srcType, srcAddr,
191 srcPacking);
192 pixels = tempImage;
193 }
194 else {
195 pixels = _mesa_image_address2d(srcPacking, srcAddr, srcWidth, srcHeight,
196 srcFormat, srcType, 0, 0);
197 }
198
199 dst = dstSlices[0];
200
201 tx_compress_dxt3(4, srcWidth, srcHeight, pixels, dst, dstRowStride);
202
203 free((void *) tempImage);
204
205 return GL_TRUE;
206 }
207
208
209 /**
210 * Store user's image in rgba_dxt5 format.
211 */
212 GLboolean
_mesa_texstore_rgba_dxt5(TEXSTORE_PARAMS)213 _mesa_texstore_rgba_dxt5(TEXSTORE_PARAMS)
214 {
215 const GLubyte *pixels;
216 GLubyte *dst;
217 const GLubyte *tempImage = NULL;
218 int rgbaRowStride = 4 * srcWidth * sizeof(GLubyte);
219
220 assert(dstFormat == MESA_FORMAT_RGBA_DXT5 ||
221 dstFormat == MESA_FORMAT_SRGBA_DXT5);
222
223 if (srcFormat != GL_RGBA ||
224 srcType != GL_UNSIGNED_BYTE ||
225 ctx->_ImageTransferState ||
226 _mesa_image_row_stride(srcPacking, srcWidth, srcFormat, srcType) != rgbaRowStride ||
227 srcPacking->SkipImages ||
228 srcPacking->SwapBytes) {
229 /* convert image to RGBA/GLubyte */
230 GLubyte *tempImageSlices[1];
231 tempImage = malloc(srcWidth * srcHeight * 4 * sizeof(GLubyte));
232 if (!tempImage)
233 return GL_FALSE; /* out of memory */
234 tempImageSlices[0] = (GLubyte *) tempImage;
235 _mesa_texstore(ctx, dims,
236 baseInternalFormat,
237 #if UTIL_ARCH_LITTLE_ENDIAN
238 MESA_FORMAT_R8G8B8A8_UNORM,
239 #else
240 MESA_FORMAT_A8B8G8R8_UNORM,
241 #endif
242 rgbaRowStride, tempImageSlices,
243 srcWidth, srcHeight, srcDepth,
244 srcFormat, srcType, srcAddr,
245 srcPacking);
246 pixels = tempImage;
247 }
248 else {
249 pixels = _mesa_image_address2d(srcPacking, srcAddr, srcWidth, srcHeight,
250 srcFormat, srcType, 0, 0);
251 }
252
253 dst = dstSlices[0];
254
255 tx_compress_dxt5(4, srcWidth, srcHeight, pixels, dst, dstRowStride);
256
257 free((void *) tempImage);
258
259 return GL_TRUE;
260 }
261
262
263 static void
fetch_rgb_dxt1(const GLubyte * map,GLint rowStride,GLint i,GLint j,GLfloat * texel)264 fetch_rgb_dxt1(const GLubyte *map,
265 GLint rowStride, GLint i, GLint j, GLfloat *texel)
266 {
267 GLubyte tex[4];
268 fetch_2d_texel_rgb_dxt1(rowStride, map, i, j, tex);
269 texel[RCOMP] = UBYTE_TO_FLOAT(tex[RCOMP]);
270 texel[GCOMP] = UBYTE_TO_FLOAT(tex[GCOMP]);
271 texel[BCOMP] = UBYTE_TO_FLOAT(tex[BCOMP]);
272 texel[ACOMP] = UBYTE_TO_FLOAT(tex[ACOMP]);
273 }
274
275 static void
fetch_rgba_dxt1(const GLubyte * map,GLint rowStride,GLint i,GLint j,GLfloat * texel)276 fetch_rgba_dxt1(const GLubyte *map,
277 GLint rowStride, GLint i, GLint j, GLfloat *texel)
278 {
279 GLubyte tex[4];
280 fetch_2d_texel_rgba_dxt1(rowStride, map, i, j, tex);
281 texel[RCOMP] = UBYTE_TO_FLOAT(tex[RCOMP]);
282 texel[GCOMP] = UBYTE_TO_FLOAT(tex[GCOMP]);
283 texel[BCOMP] = UBYTE_TO_FLOAT(tex[BCOMP]);
284 texel[ACOMP] = UBYTE_TO_FLOAT(tex[ACOMP]);
285 }
286
287 static void
fetch_rgba_dxt3(const GLubyte * map,GLint rowStride,GLint i,GLint j,GLfloat * texel)288 fetch_rgba_dxt3(const GLubyte *map,
289 GLint rowStride, GLint i, GLint j, GLfloat *texel)
290 {
291 GLubyte tex[4];
292 fetch_2d_texel_rgba_dxt3(rowStride, map, i, j, tex);
293 texel[RCOMP] = UBYTE_TO_FLOAT(tex[RCOMP]);
294 texel[GCOMP] = UBYTE_TO_FLOAT(tex[GCOMP]);
295 texel[BCOMP] = UBYTE_TO_FLOAT(tex[BCOMP]);
296 texel[ACOMP] = UBYTE_TO_FLOAT(tex[ACOMP]);
297 }
298
299 static void
fetch_rgba_dxt5(const GLubyte * map,GLint rowStride,GLint i,GLint j,GLfloat * texel)300 fetch_rgba_dxt5(const GLubyte *map,
301 GLint rowStride, GLint i, GLint j, GLfloat *texel)
302 {
303 GLubyte tex[4];
304 fetch_2d_texel_rgba_dxt5(rowStride, map, i, j, tex);
305 texel[RCOMP] = UBYTE_TO_FLOAT(tex[RCOMP]);
306 texel[GCOMP] = UBYTE_TO_FLOAT(tex[GCOMP]);
307 texel[BCOMP] = UBYTE_TO_FLOAT(tex[BCOMP]);
308 texel[ACOMP] = UBYTE_TO_FLOAT(tex[ACOMP]);
309 }
310
311
312 static void
fetch_srgb_dxt1(const GLubyte * map,GLint rowStride,GLint i,GLint j,GLfloat * texel)313 fetch_srgb_dxt1(const GLubyte *map,
314 GLint rowStride, GLint i, GLint j, GLfloat *texel)
315 {
316 GLubyte tex[4];
317 fetch_2d_texel_rgb_dxt1(rowStride, map, i, j, tex);
318 texel[RCOMP] = util_format_srgb_8unorm_to_linear_float(tex[RCOMP]);
319 texel[GCOMP] = util_format_srgb_8unorm_to_linear_float(tex[GCOMP]);
320 texel[BCOMP] = util_format_srgb_8unorm_to_linear_float(tex[BCOMP]);
321 texel[ACOMP] = UBYTE_TO_FLOAT(tex[ACOMP]);
322 }
323
324 static void
fetch_srgba_dxt1(const GLubyte * map,GLint rowStride,GLint i,GLint j,GLfloat * texel)325 fetch_srgba_dxt1(const GLubyte *map,
326 GLint rowStride, GLint i, GLint j, GLfloat *texel)
327 {
328 GLubyte tex[4];
329 fetch_2d_texel_rgba_dxt1(rowStride, map, i, j, tex);
330 texel[RCOMP] = util_format_srgb_8unorm_to_linear_float(tex[RCOMP]);
331 texel[GCOMP] = util_format_srgb_8unorm_to_linear_float(tex[GCOMP]);
332 texel[BCOMP] = util_format_srgb_8unorm_to_linear_float(tex[BCOMP]);
333 texel[ACOMP] = UBYTE_TO_FLOAT(tex[ACOMP]);
334 }
335
336 static void
fetch_srgba_dxt3(const GLubyte * map,GLint rowStride,GLint i,GLint j,GLfloat * texel)337 fetch_srgba_dxt3(const GLubyte *map,
338 GLint rowStride, GLint i, GLint j, GLfloat *texel)
339 {
340 GLubyte tex[4];
341 fetch_2d_texel_rgba_dxt3(rowStride, map, i, j, tex);
342 texel[RCOMP] = util_format_srgb_8unorm_to_linear_float(tex[RCOMP]);
343 texel[GCOMP] = util_format_srgb_8unorm_to_linear_float(tex[GCOMP]);
344 texel[BCOMP] = util_format_srgb_8unorm_to_linear_float(tex[BCOMP]);
345 texel[ACOMP] = UBYTE_TO_FLOAT(tex[ACOMP]);
346 }
347
348 static void
fetch_srgba_dxt5(const GLubyte * map,GLint rowStride,GLint i,GLint j,GLfloat * texel)349 fetch_srgba_dxt5(const GLubyte *map,
350 GLint rowStride, GLint i, GLint j, GLfloat *texel)
351 {
352 GLubyte tex[4];
353 fetch_2d_texel_rgba_dxt5(rowStride, map, i, j, tex);
354 texel[RCOMP] = util_format_srgb_8unorm_to_linear_float(tex[RCOMP]);
355 texel[GCOMP] = util_format_srgb_8unorm_to_linear_float(tex[GCOMP]);
356 texel[BCOMP] = util_format_srgb_8unorm_to_linear_float(tex[BCOMP]);
357 texel[ACOMP] = UBYTE_TO_FLOAT(tex[ACOMP]);
358 }
359
360
361
362 compressed_fetch_func
_mesa_get_dxt_fetch_func(mesa_format format)363 _mesa_get_dxt_fetch_func(mesa_format format)
364 {
365 switch (format) {
366 case MESA_FORMAT_RGB_DXT1:
367 return fetch_rgb_dxt1;
368 case MESA_FORMAT_RGBA_DXT1:
369 return fetch_rgba_dxt1;
370 case MESA_FORMAT_RGBA_DXT3:
371 return fetch_rgba_dxt3;
372 case MESA_FORMAT_RGBA_DXT5:
373 return fetch_rgba_dxt5;
374 case MESA_FORMAT_SRGB_DXT1:
375 return fetch_srgb_dxt1;
376 case MESA_FORMAT_SRGBA_DXT1:
377 return fetch_srgba_dxt1;
378 case MESA_FORMAT_SRGBA_DXT3:
379 return fetch_srgba_dxt3;
380 case MESA_FORMAT_SRGBA_DXT5:
381 return fetch_srgba_dxt5;
382 default:
383 return NULL;
384 }
385 }
386
387 extern void
_mesa_unpack_s3tc(uint8_t * dst_row,unsigned dst_stride,const uint8_t * src_row,unsigned src_stride,unsigned src_width,unsigned src_height,mesa_format format)388 _mesa_unpack_s3tc(uint8_t *dst_row,
389 unsigned dst_stride,
390 const uint8_t *src_row,
391 unsigned src_stride,
392 unsigned src_width,
393 unsigned src_height,
394 mesa_format format)
395 {
396 /* We treat sRGB formats as RGB, because we're unpacking to another sRGB
397 * format.
398 */
399 switch (format) {
400 case MESA_FORMAT_RGB_DXT1:
401 case MESA_FORMAT_SRGB_DXT1:
402 util_format_dxt1_rgb_unpack_rgba_8unorm(dst_row, dst_stride,
403 src_row, src_stride,
404 src_width, src_height);
405 break;
406
407 case MESA_FORMAT_RGBA_DXT1:
408 case MESA_FORMAT_SRGBA_DXT1:
409 util_format_dxt1_rgba_unpack_rgba_8unorm(dst_row, dst_stride,
410 src_row, src_stride,
411 src_width, src_height);
412 break;
413
414 case MESA_FORMAT_RGBA_DXT3:
415 case MESA_FORMAT_SRGBA_DXT3:
416 util_format_dxt3_rgba_unpack_rgba_8unorm(dst_row, dst_stride,
417 src_row, src_stride,
418 src_width, src_height);
419 break;
420
421 case MESA_FORMAT_RGBA_DXT5:
422 case MESA_FORMAT_SRGBA_DXT5:
423 util_format_dxt5_rgba_unpack_rgba_8unorm(dst_row, dst_stride,
424 src_row, src_stride,
425 src_width, src_height);
426 break;
427
428 default:
429 unreachable("unexpected format");
430 }
431 }
432