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
34 #include "image.h"
35 #include "macros.h"
36 #include "mtypes.h"
37 #include "texcompress.h"
38 #include "texcompress_s3tc.h"
39 #include "texcompress_s3tc_tmp.h"
40 #include "texstore.h"
41 #include "format_unpack.h"
42 #include "util/format_srgb.h"
43
44
45 /**
46 * Store user's image in rgb_dxt1 format.
47 */
48 GLboolean
_mesa_texstore_rgb_dxt1(TEXSTORE_PARAMS)49 _mesa_texstore_rgb_dxt1(TEXSTORE_PARAMS)
50 {
51 const GLubyte *pixels;
52 GLubyte *dst;
53 const GLubyte *tempImage = NULL;
54
55 assert(dstFormat == MESA_FORMAT_RGB_DXT1 ||
56 dstFormat == MESA_FORMAT_SRGB_DXT1);
57
58 if (srcFormat != GL_RGB ||
59 srcType != GL_UNSIGNED_BYTE ||
60 ctx->_ImageTransferState ||
61 ALIGN(srcPacking->RowLength, srcPacking->Alignment) != srcWidth ||
62 srcPacking->SwapBytes) {
63 /* convert image to RGB/GLubyte */
64 GLubyte *tempImageSlices[1];
65 int rgbRowStride = 3 * srcWidth * sizeof(GLubyte);
66 tempImage = malloc(srcWidth * srcHeight * 3 * sizeof(GLubyte));
67 if (!tempImage)
68 return GL_FALSE; /* out of memory */
69 tempImageSlices[0] = (GLubyte *) tempImage;
70 _mesa_texstore(ctx, dims,
71 baseInternalFormat,
72 MESA_FORMAT_RGB_UNORM8,
73 rgbRowStride, tempImageSlices,
74 srcWidth, srcHeight, srcDepth,
75 srcFormat, srcType, srcAddr,
76 srcPacking);
77 pixels = tempImage;
78 srcFormat = GL_RGB;
79 }
80 else {
81 pixels = _mesa_image_address2d(srcPacking, srcAddr, srcWidth, srcHeight,
82 srcFormat, srcType, 0, 0);
83 }
84
85 dst = dstSlices[0];
86
87 tx_compress_dxtn(3, srcWidth, srcHeight, pixels,
88 GL_COMPRESSED_RGB_S3TC_DXT1_EXT,
89 dst, dstRowStride);
90
91 free((void *) tempImage);
92
93 return GL_TRUE;
94 }
95
96
97 /**
98 * Store user's image in rgba_dxt1 format.
99 */
100 GLboolean
_mesa_texstore_rgba_dxt1(TEXSTORE_PARAMS)101 _mesa_texstore_rgba_dxt1(TEXSTORE_PARAMS)
102 {
103 const GLubyte *pixels;
104 GLubyte *dst;
105 const GLubyte *tempImage = NULL;
106
107 assert(dstFormat == MESA_FORMAT_RGBA_DXT1 ||
108 dstFormat == MESA_FORMAT_SRGBA_DXT1);
109
110 if (srcFormat != GL_RGBA ||
111 srcType != GL_UNSIGNED_BYTE ||
112 ctx->_ImageTransferState ||
113 ALIGN(srcPacking->RowLength, srcPacking->Alignment) != srcWidth ||
114 srcPacking->SwapBytes) {
115 /* convert image to RGBA/GLubyte */
116 GLubyte *tempImageSlices[1];
117 int rgbaRowStride = 4 * srcWidth * sizeof(GLubyte);
118 tempImage = malloc(srcWidth * srcHeight * 4 * sizeof(GLubyte));
119 if (!tempImage)
120 return GL_FALSE; /* out of memory */
121 tempImageSlices[0] = (GLubyte *) tempImage;
122 _mesa_texstore(ctx, dims,
123 baseInternalFormat,
124 #if UTIL_ARCH_LITTLE_ENDIAN
125 MESA_FORMAT_R8G8B8A8_UNORM,
126 #else
127 MESA_FORMAT_A8B8G8R8_UNORM,
128 #endif
129 rgbaRowStride, tempImageSlices,
130 srcWidth, srcHeight, srcDepth,
131 srcFormat, srcType, srcAddr,
132 srcPacking);
133 pixels = tempImage;
134 srcFormat = GL_RGBA;
135 }
136 else {
137 pixels = _mesa_image_address2d(srcPacking, srcAddr, srcWidth, srcHeight,
138 srcFormat, srcType, 0, 0);
139 }
140
141 dst = dstSlices[0];
142
143 tx_compress_dxtn(4, srcWidth, srcHeight, pixels,
144 GL_COMPRESSED_RGBA_S3TC_DXT1_EXT,
145 dst, dstRowStride);
146
147 free((void*) tempImage);
148
149 return GL_TRUE;
150 }
151
152
153 /**
154 * Store user's image in rgba_dxt3 format.
155 */
156 GLboolean
_mesa_texstore_rgba_dxt3(TEXSTORE_PARAMS)157 _mesa_texstore_rgba_dxt3(TEXSTORE_PARAMS)
158 {
159 const GLubyte *pixels;
160 GLubyte *dst;
161 const GLubyte *tempImage = NULL;
162
163 assert(dstFormat == MESA_FORMAT_RGBA_DXT3 ||
164 dstFormat == MESA_FORMAT_SRGBA_DXT3);
165
166 if (srcFormat != GL_RGBA ||
167 srcType != GL_UNSIGNED_BYTE ||
168 ctx->_ImageTransferState ||
169 ALIGN(srcPacking->RowLength, srcPacking->Alignment) != srcWidth ||
170 srcPacking->SwapBytes) {
171 /* convert image to RGBA/GLubyte */
172 GLubyte *tempImageSlices[1];
173 int rgbaRowStride = 4 * srcWidth * sizeof(GLubyte);
174 tempImage = malloc(srcWidth * srcHeight * 4 * sizeof(GLubyte));
175 if (!tempImage)
176 return GL_FALSE; /* out of memory */
177 tempImageSlices[0] = (GLubyte *) tempImage;
178 _mesa_texstore(ctx, dims,
179 baseInternalFormat,
180 #if UTIL_ARCH_LITTLE_ENDIAN
181 MESA_FORMAT_R8G8B8A8_UNORM,
182 #else
183 MESA_FORMAT_A8B8G8R8_UNORM,
184 #endif
185 rgbaRowStride, tempImageSlices,
186 srcWidth, srcHeight, srcDepth,
187 srcFormat, srcType, srcAddr,
188 srcPacking);
189 pixels = tempImage;
190 }
191 else {
192 pixels = _mesa_image_address2d(srcPacking, srcAddr, srcWidth, srcHeight,
193 srcFormat, srcType, 0, 0);
194 }
195
196 dst = dstSlices[0];
197
198 tx_compress_dxtn(4, srcWidth, srcHeight, pixels,
199 GL_COMPRESSED_RGBA_S3TC_DXT3_EXT,
200 dst, dstRowStride);
201
202 free((void *) tempImage);
203
204 return GL_TRUE;
205 }
206
207
208 /**
209 * Store user's image in rgba_dxt5 format.
210 */
211 GLboolean
_mesa_texstore_rgba_dxt5(TEXSTORE_PARAMS)212 _mesa_texstore_rgba_dxt5(TEXSTORE_PARAMS)
213 {
214 const GLubyte *pixels;
215 GLubyte *dst;
216 const GLubyte *tempImage = NULL;
217
218 assert(dstFormat == MESA_FORMAT_RGBA_DXT5 ||
219 dstFormat == MESA_FORMAT_SRGBA_DXT5);
220
221 if (srcFormat != GL_RGBA ||
222 srcType != GL_UNSIGNED_BYTE ||
223 ctx->_ImageTransferState ||
224 ALIGN(srcPacking->RowLength, srcPacking->Alignment) != srcWidth ||
225 srcPacking->SwapBytes) {
226 /* convert image to RGBA/GLubyte */
227 GLubyte *tempImageSlices[1];
228 int rgbaRowStride = 4 * srcWidth * sizeof(GLubyte);
229 tempImage = malloc(srcWidth * srcHeight * 4 * sizeof(GLubyte));
230 if (!tempImage)
231 return GL_FALSE; /* out of memory */
232 tempImageSlices[0] = (GLubyte *) tempImage;
233 _mesa_texstore(ctx, dims,
234 baseInternalFormat,
235 #if UTIL_ARCH_LITTLE_ENDIAN
236 MESA_FORMAT_R8G8B8A8_UNORM,
237 #else
238 MESA_FORMAT_A8B8G8R8_UNORM,
239 #endif
240 rgbaRowStride, tempImageSlices,
241 srcWidth, srcHeight, srcDepth,
242 srcFormat, srcType, srcAddr,
243 srcPacking);
244 pixels = tempImage;
245 }
246 else {
247 pixels = _mesa_image_address2d(srcPacking, srcAddr, srcWidth, srcHeight,
248 srcFormat, srcType, 0, 0);
249 }
250
251 dst = dstSlices[0];
252
253 tx_compress_dxtn(4, srcWidth, srcHeight, pixels,
254 GL_COMPRESSED_RGBA_S3TC_DXT5_EXT,
255 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