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