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 "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 _mesa_little_endian() ? MESA_FORMAT_R8G8B8A8_UNORM
125 : MESA_FORMAT_A8B8G8R8_UNORM,
126 rgbaRowStride, tempImageSlices,
127 srcWidth, srcHeight, srcDepth,
128 srcFormat, srcType, srcAddr,
129 srcPacking);
130 pixels = tempImage;
131 srcFormat = GL_RGBA;
132 }
133 else {
134 pixels = _mesa_image_address2d(srcPacking, srcAddr, srcWidth, srcHeight,
135 srcFormat, srcType, 0, 0);
136 }
137
138 dst = dstSlices[0];
139
140 tx_compress_dxtn(4, srcWidth, srcHeight, pixels,
141 GL_COMPRESSED_RGBA_S3TC_DXT1_EXT,
142 dst, dstRowStride);
143
144 free((void*) tempImage);
145
146 return GL_TRUE;
147 }
148
149
150 /**
151 * Store user's image in rgba_dxt3 format.
152 */
153 GLboolean
_mesa_texstore_rgba_dxt3(TEXSTORE_PARAMS)154 _mesa_texstore_rgba_dxt3(TEXSTORE_PARAMS)
155 {
156 const GLubyte *pixels;
157 GLubyte *dst;
158 const GLubyte *tempImage = NULL;
159
160 assert(dstFormat == MESA_FORMAT_RGBA_DXT3 ||
161 dstFormat == MESA_FORMAT_SRGBA_DXT3);
162
163 if (srcFormat != GL_RGBA ||
164 srcType != GL_UNSIGNED_BYTE ||
165 ctx->_ImageTransferState ||
166 ALIGN(srcPacking->RowLength, srcPacking->Alignment) != srcWidth ||
167 srcPacking->SwapBytes) {
168 /* convert image to RGBA/GLubyte */
169 GLubyte *tempImageSlices[1];
170 int rgbaRowStride = 4 * srcWidth * sizeof(GLubyte);
171 tempImage = malloc(srcWidth * srcHeight * 4 * sizeof(GLubyte));
172 if (!tempImage)
173 return GL_FALSE; /* out of memory */
174 tempImageSlices[0] = (GLubyte *) tempImage;
175 _mesa_texstore(ctx, dims,
176 baseInternalFormat,
177 _mesa_little_endian() ? MESA_FORMAT_R8G8B8A8_UNORM
178 : MESA_FORMAT_A8B8G8R8_UNORM,
179 rgbaRowStride, tempImageSlices,
180 srcWidth, srcHeight, srcDepth,
181 srcFormat, srcType, srcAddr,
182 srcPacking);
183 pixels = tempImage;
184 }
185 else {
186 pixels = _mesa_image_address2d(srcPacking, srcAddr, srcWidth, srcHeight,
187 srcFormat, srcType, 0, 0);
188 }
189
190 dst = dstSlices[0];
191
192 tx_compress_dxtn(4, srcWidth, srcHeight, pixels,
193 GL_COMPRESSED_RGBA_S3TC_DXT3_EXT,
194 dst, dstRowStride);
195
196 free((void *) tempImage);
197
198 return GL_TRUE;
199 }
200
201
202 /**
203 * Store user's image in rgba_dxt5 format.
204 */
205 GLboolean
_mesa_texstore_rgba_dxt5(TEXSTORE_PARAMS)206 _mesa_texstore_rgba_dxt5(TEXSTORE_PARAMS)
207 {
208 const GLubyte *pixels;
209 GLubyte *dst;
210 const GLubyte *tempImage = NULL;
211
212 assert(dstFormat == MESA_FORMAT_RGBA_DXT5 ||
213 dstFormat == MESA_FORMAT_SRGBA_DXT5);
214
215 if (srcFormat != GL_RGBA ||
216 srcType != GL_UNSIGNED_BYTE ||
217 ctx->_ImageTransferState ||
218 ALIGN(srcPacking->RowLength, srcPacking->Alignment) != srcWidth ||
219 srcPacking->SwapBytes) {
220 /* convert image to RGBA/GLubyte */
221 GLubyte *tempImageSlices[1];
222 int rgbaRowStride = 4 * srcWidth * sizeof(GLubyte);
223 tempImage = malloc(srcWidth * srcHeight * 4 * sizeof(GLubyte));
224 if (!tempImage)
225 return GL_FALSE; /* out of memory */
226 tempImageSlices[0] = (GLubyte *) tempImage;
227 _mesa_texstore(ctx, dims,
228 baseInternalFormat,
229 _mesa_little_endian() ? MESA_FORMAT_R8G8B8A8_UNORM
230 : MESA_FORMAT_A8B8G8R8_UNORM,
231 rgbaRowStride, tempImageSlices,
232 srcWidth, srcHeight, srcDepth,
233 srcFormat, srcType, srcAddr,
234 srcPacking);
235 pixels = tempImage;
236 }
237 else {
238 pixels = _mesa_image_address2d(srcPacking, srcAddr, srcWidth, srcHeight,
239 srcFormat, srcType, 0, 0);
240 }
241
242 dst = dstSlices[0];
243
244 tx_compress_dxtn(4, srcWidth, srcHeight, pixels,
245 GL_COMPRESSED_RGBA_S3TC_DXT5_EXT,
246 dst, dstRowStride);
247
248 free((void *) tempImage);
249
250 return GL_TRUE;
251 }
252
253
254 static void
fetch_rgb_dxt1(const GLubyte * map,GLint rowStride,GLint i,GLint j,GLfloat * texel)255 fetch_rgb_dxt1(const GLubyte *map,
256 GLint rowStride, GLint i, GLint j, GLfloat *texel)
257 {
258 GLubyte tex[4];
259 fetch_2d_texel_rgb_dxt1(rowStride, map, i, j, tex);
260 texel[RCOMP] = UBYTE_TO_FLOAT(tex[RCOMP]);
261 texel[GCOMP] = UBYTE_TO_FLOAT(tex[GCOMP]);
262 texel[BCOMP] = UBYTE_TO_FLOAT(tex[BCOMP]);
263 texel[ACOMP] = UBYTE_TO_FLOAT(tex[ACOMP]);
264 }
265
266 static void
fetch_rgba_dxt1(const GLubyte * map,GLint rowStride,GLint i,GLint j,GLfloat * texel)267 fetch_rgba_dxt1(const GLubyte *map,
268 GLint rowStride, GLint i, GLint j, GLfloat *texel)
269 {
270 GLubyte tex[4];
271 fetch_2d_texel_rgba_dxt1(rowStride, map, i, j, tex);
272 texel[RCOMP] = UBYTE_TO_FLOAT(tex[RCOMP]);
273 texel[GCOMP] = UBYTE_TO_FLOAT(tex[GCOMP]);
274 texel[BCOMP] = UBYTE_TO_FLOAT(tex[BCOMP]);
275 texel[ACOMP] = UBYTE_TO_FLOAT(tex[ACOMP]);
276 }
277
278 static void
fetch_rgba_dxt3(const GLubyte * map,GLint rowStride,GLint i,GLint j,GLfloat * texel)279 fetch_rgba_dxt3(const GLubyte *map,
280 GLint rowStride, GLint i, GLint j, GLfloat *texel)
281 {
282 GLubyte tex[4];
283 fetch_2d_texel_rgba_dxt3(rowStride, map, i, j, tex);
284 texel[RCOMP] = UBYTE_TO_FLOAT(tex[RCOMP]);
285 texel[GCOMP] = UBYTE_TO_FLOAT(tex[GCOMP]);
286 texel[BCOMP] = UBYTE_TO_FLOAT(tex[BCOMP]);
287 texel[ACOMP] = UBYTE_TO_FLOAT(tex[ACOMP]);
288 }
289
290 static void
fetch_rgba_dxt5(const GLubyte * map,GLint rowStride,GLint i,GLint j,GLfloat * texel)291 fetch_rgba_dxt5(const GLubyte *map,
292 GLint rowStride, GLint i, GLint j, GLfloat *texel)
293 {
294 GLubyte tex[4];
295 fetch_2d_texel_rgba_dxt5(rowStride, map, i, j, tex);
296 texel[RCOMP] = UBYTE_TO_FLOAT(tex[RCOMP]);
297 texel[GCOMP] = UBYTE_TO_FLOAT(tex[GCOMP]);
298 texel[BCOMP] = UBYTE_TO_FLOAT(tex[BCOMP]);
299 texel[ACOMP] = UBYTE_TO_FLOAT(tex[ACOMP]);
300 }
301
302
303 static void
fetch_srgb_dxt1(const GLubyte * map,GLint rowStride,GLint i,GLint j,GLfloat * texel)304 fetch_srgb_dxt1(const GLubyte *map,
305 GLint rowStride, GLint i, GLint j, GLfloat *texel)
306 {
307 GLubyte tex[4];
308 fetch_2d_texel_rgb_dxt1(rowStride, map, i, j, tex);
309 texel[RCOMP] = util_format_srgb_8unorm_to_linear_float(tex[RCOMP]);
310 texel[GCOMP] = util_format_srgb_8unorm_to_linear_float(tex[GCOMP]);
311 texel[BCOMP] = util_format_srgb_8unorm_to_linear_float(tex[BCOMP]);
312 texel[ACOMP] = UBYTE_TO_FLOAT(tex[ACOMP]);
313 }
314
315 static void
fetch_srgba_dxt1(const GLubyte * map,GLint rowStride,GLint i,GLint j,GLfloat * texel)316 fetch_srgba_dxt1(const GLubyte *map,
317 GLint rowStride, GLint i, GLint j, GLfloat *texel)
318 {
319 GLubyte tex[4];
320 fetch_2d_texel_rgba_dxt1(rowStride, map, i, j, tex);
321 texel[RCOMP] = util_format_srgb_8unorm_to_linear_float(tex[RCOMP]);
322 texel[GCOMP] = util_format_srgb_8unorm_to_linear_float(tex[GCOMP]);
323 texel[BCOMP] = util_format_srgb_8unorm_to_linear_float(tex[BCOMP]);
324 texel[ACOMP] = UBYTE_TO_FLOAT(tex[ACOMP]);
325 }
326
327 static void
fetch_srgba_dxt3(const GLubyte * map,GLint rowStride,GLint i,GLint j,GLfloat * texel)328 fetch_srgba_dxt3(const GLubyte *map,
329 GLint rowStride, GLint i, GLint j, GLfloat *texel)
330 {
331 GLubyte tex[4];
332 fetch_2d_texel_rgba_dxt3(rowStride, map, i, j, tex);
333 texel[RCOMP] = util_format_srgb_8unorm_to_linear_float(tex[RCOMP]);
334 texel[GCOMP] = util_format_srgb_8unorm_to_linear_float(tex[GCOMP]);
335 texel[BCOMP] = util_format_srgb_8unorm_to_linear_float(tex[BCOMP]);
336 texel[ACOMP] = UBYTE_TO_FLOAT(tex[ACOMP]);
337 }
338
339 static void
fetch_srgba_dxt5(const GLubyte * map,GLint rowStride,GLint i,GLint j,GLfloat * texel)340 fetch_srgba_dxt5(const GLubyte *map,
341 GLint rowStride, GLint i, GLint j, GLfloat *texel)
342 {
343 GLubyte tex[4];
344 fetch_2d_texel_rgba_dxt5(rowStride, map, i, j, tex);
345 texel[RCOMP] = util_format_srgb_8unorm_to_linear_float(tex[RCOMP]);
346 texel[GCOMP] = util_format_srgb_8unorm_to_linear_float(tex[GCOMP]);
347 texel[BCOMP] = util_format_srgb_8unorm_to_linear_float(tex[BCOMP]);
348 texel[ACOMP] = UBYTE_TO_FLOAT(tex[ACOMP]);
349 }
350
351
352
353 compressed_fetch_func
_mesa_get_dxt_fetch_func(mesa_format format)354 _mesa_get_dxt_fetch_func(mesa_format format)
355 {
356 switch (format) {
357 case MESA_FORMAT_RGB_DXT1:
358 return fetch_rgb_dxt1;
359 case MESA_FORMAT_RGBA_DXT1:
360 return fetch_rgba_dxt1;
361 case MESA_FORMAT_RGBA_DXT3:
362 return fetch_rgba_dxt3;
363 case MESA_FORMAT_RGBA_DXT5:
364 return fetch_rgba_dxt5;
365 case MESA_FORMAT_SRGB_DXT1:
366 return fetch_srgb_dxt1;
367 case MESA_FORMAT_SRGBA_DXT1:
368 return fetch_srgba_dxt1;
369 case MESA_FORMAT_SRGBA_DXT3:
370 return fetch_srgba_dxt3;
371 case MESA_FORMAT_SRGBA_DXT5:
372 return fetch_srgba_dxt5;
373 default:
374 return NULL;
375 }
376 }
377