xref: /aosp_15_r20/external/mesa3d/src/mesa/main/texcompress_s3tc.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
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