1 /*
2  * Copyright (C) 2014 Intel Corporation
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21  * DEALINGS IN THE SOFTWARE.
22  */
23 
24 /**
25  * \file texcompress_bptc.c
26  * GL_ARB_texture_compression_bptc support.
27  */
28 
29 #include <stdbool.h>
30 #include "texcompress.h"
31 #include "texcompress_bptc.h"
32 #include "texcompress_bptc_tmp.h"
33 #include "texstore.h"
34 #include "image.h"
35 #include "mtypes.h"
36 
37 static void
fetch_bptc_rgb_float(const GLubyte * map,GLint rowStride,GLint i,GLint j,GLfloat * texel,bool is_signed)38 fetch_bptc_rgb_float(const GLubyte *map,
39                      GLint rowStride, GLint i, GLint j,
40                      GLfloat *texel,
41                      bool is_signed)
42 {
43    const GLubyte *block;
44 
45    block = map + (((rowStride + 3) / 4) * (j / 4) + (i / 4)) * 16;
46 
47    fetch_rgb_float_from_block(block, texel, (i % 4) + (j % 4) * 4, is_signed);
48 }
49 
50 static void
fetch_bptc_rgb_signed_float(const GLubyte * map,GLint rowStride,GLint i,GLint j,GLfloat * texel)51 fetch_bptc_rgb_signed_float(const GLubyte *map,
52                             GLint rowStride, GLint i, GLint j,
53                             GLfloat *texel)
54 {
55    fetch_bptc_rgb_float(map, rowStride, i, j, texel, true);
56 }
57 
58 static void
fetch_bptc_rgb_unsigned_float(const GLubyte * map,GLint rowStride,GLint i,GLint j,GLfloat * texel)59 fetch_bptc_rgb_unsigned_float(const GLubyte *map,
60                               GLint rowStride, GLint i, GLint j,
61                               GLfloat *texel)
62 {
63    fetch_bptc_rgb_float(map, rowStride, i, j, texel, false);
64 }
65 
66 static void
fetch_bptc_rgba_unorm_bytes(const GLubyte * map,GLint rowStride,GLint i,GLint j,GLubyte * texel)67 fetch_bptc_rgba_unorm_bytes(const GLubyte *map,
68                             GLint rowStride, GLint i, GLint j,
69                             GLubyte *texel)
70 {
71    const GLubyte *block;
72 
73    block = map + (((rowStride + 3) / 4) * (j / 4) + (i / 4)) * 16;
74 
75    fetch_rgba_unorm_from_block(block, texel, (i % 4) + (j % 4) * 4);
76 }
77 
78 static void
fetch_bptc_rgba_unorm(const GLubyte * map,GLint rowStride,GLint i,GLint j,GLfloat * texel)79 fetch_bptc_rgba_unorm(const GLubyte *map,
80                       GLint rowStride, GLint i, GLint j,
81                       GLfloat *texel)
82 {
83    GLubyte texel_bytes[4];
84 
85    fetch_bptc_rgba_unorm_bytes(map, rowStride, i, j, texel_bytes);
86 
87    texel[RCOMP] = UBYTE_TO_FLOAT(texel_bytes[0]);
88    texel[GCOMP] = UBYTE_TO_FLOAT(texel_bytes[1]);
89    texel[BCOMP] = UBYTE_TO_FLOAT(texel_bytes[2]);
90    texel[ACOMP] = UBYTE_TO_FLOAT(texel_bytes[3]);
91 }
92 
93 static void
fetch_bptc_srgb_alpha_unorm(const GLubyte * map,GLint rowStride,GLint i,GLint j,GLfloat * texel)94 fetch_bptc_srgb_alpha_unorm(const GLubyte *map,
95                             GLint rowStride, GLint i, GLint j,
96                             GLfloat *texel)
97 {
98    GLubyte texel_bytes[4];
99 
100    fetch_bptc_rgba_unorm_bytes(map, rowStride, i, j, texel_bytes);
101 
102    texel[RCOMP] = util_format_srgb_8unorm_to_linear_float(texel_bytes[0]);
103    texel[GCOMP] = util_format_srgb_8unorm_to_linear_float(texel_bytes[1]);
104    texel[BCOMP] = util_format_srgb_8unorm_to_linear_float(texel_bytes[2]);
105    texel[ACOMP] = UBYTE_TO_FLOAT(texel_bytes[3]);
106 }
107 
108 compressed_fetch_func
_mesa_get_bptc_fetch_func(mesa_format format)109 _mesa_get_bptc_fetch_func(mesa_format format)
110 {
111    switch (format) {
112    case MESA_FORMAT_BPTC_RGBA_UNORM:
113       return fetch_bptc_rgba_unorm;
114    case MESA_FORMAT_BPTC_SRGB_ALPHA_UNORM:
115       return fetch_bptc_srgb_alpha_unorm;
116    case MESA_FORMAT_BPTC_RGB_SIGNED_FLOAT:
117       return fetch_bptc_rgb_signed_float;
118    case MESA_FORMAT_BPTC_RGB_UNSIGNED_FLOAT:
119       return fetch_bptc_rgb_unsigned_float;
120    default:
121       return NULL;
122    }
123 }
124 
125 GLboolean
_mesa_texstore_bptc_rgba_unorm(TEXSTORE_PARAMS)126 _mesa_texstore_bptc_rgba_unorm(TEXSTORE_PARAMS)
127 {
128    const GLubyte *pixels;
129    const GLubyte *tempImage = NULL;
130    int rowstride;
131 
132    if (srcFormat != GL_RGBA ||
133        srcType != GL_UNSIGNED_BYTE ||
134        ctx->_ImageTransferState ||
135        srcPacking->SwapBytes) {
136       /* convert image to RGBA/ubyte */
137       GLubyte *tempImageSlices[1];
138       int rgbaRowStride = 4 * srcWidth * sizeof(GLubyte);
139       tempImage = malloc(srcWidth * srcHeight * 4 * sizeof(GLubyte));
140       if (!tempImage)
141          return GL_FALSE; /* out of memory */
142       tempImageSlices[0] = (GLubyte *) tempImage;
143       _mesa_texstore(ctx, dims,
144                      baseInternalFormat,
145 #if UTIL_ARCH_LITTLE_ENDIAN
146                      MESA_FORMAT_R8G8B8A8_UNORM,
147 #else
148                      MESA_FORMAT_A8B8G8R8_UNORM,
149 #endif
150                      rgbaRowStride, tempImageSlices,
151                      srcWidth, srcHeight, srcDepth,
152                      srcFormat, srcType, srcAddr,
153                      srcPacking);
154 
155       pixels = tempImage;
156       rowstride = srcWidth * 4;
157    } else {
158       pixels = _mesa_image_address2d(srcPacking, srcAddr, srcWidth, srcHeight,
159                                      srcFormat, srcType, 0, 0);
160       rowstride = _mesa_image_row_stride(srcPacking, srcWidth,
161                                          srcFormat, srcType);
162    }
163 
164    compress_rgba_unorm(srcWidth, srcHeight,
165                        pixels, rowstride,
166                        dstSlices[0], dstRowStride);
167 
168    free((void *) tempImage);
169 
170    return GL_TRUE;
171 }
172 
173 static GLboolean
texstore_bptc_rgb_float(TEXSTORE_PARAMS,bool is_signed)174 texstore_bptc_rgb_float(TEXSTORE_PARAMS,
175                         bool is_signed)
176 {
177    const float *pixels;
178    const float *tempImage = NULL;
179    int rowstride;
180 
181    if (srcFormat != GL_RGB ||
182        srcType != GL_FLOAT ||
183        ctx->_ImageTransferState ||
184        srcPacking->SwapBytes) {
185       /* convert image to RGB/float */
186       GLfloat *tempImageSlices[1];
187       int rgbRowStride = 3 * srcWidth * sizeof(GLfloat);
188       tempImage = malloc(srcWidth * srcHeight * 3 * sizeof(GLfloat));
189       if (!tempImage)
190          return GL_FALSE; /* out of memory */
191       tempImageSlices[0] = (GLfloat *) tempImage;
192       _mesa_texstore(ctx, dims,
193                      baseInternalFormat,
194                      MESA_FORMAT_RGB_FLOAT32,
195                      rgbRowStride, (GLubyte **)tempImageSlices,
196                      srcWidth, srcHeight, srcDepth,
197                      srcFormat, srcType, srcAddr,
198                      srcPacking);
199 
200       pixels = tempImage;
201       rowstride = srcWidth * sizeof(float) * 3;
202    } else {
203       pixels = _mesa_image_address2d(srcPacking, srcAddr, srcWidth, srcHeight,
204                                      srcFormat, srcType, 0, 0);
205       rowstride = _mesa_image_row_stride(srcPacking, srcWidth,
206                                          srcFormat, srcType);
207    }
208 
209    compress_rgb_float(srcWidth, srcHeight,
210                       pixels, rowstride,
211                       dstSlices[0], dstRowStride,
212                       is_signed);
213 
214    free((void *) tempImage);
215 
216    return GL_TRUE;
217 }
218 
219 GLboolean
_mesa_texstore_bptc_rgb_signed_float(TEXSTORE_PARAMS)220 _mesa_texstore_bptc_rgb_signed_float(TEXSTORE_PARAMS)
221 {
222    assert(dstFormat == MESA_FORMAT_BPTC_RGB_SIGNED_FLOAT);
223 
224    return texstore_bptc_rgb_float(ctx, dims, baseInternalFormat,
225                                   dstFormat, dstRowStride, dstSlices,
226                                   srcWidth, srcHeight, srcDepth,
227                                   srcFormat, srcType,
228                                   srcAddr, srcPacking,
229                                   true /* signed */);
230 }
231 
232 GLboolean
_mesa_texstore_bptc_rgb_unsigned_float(TEXSTORE_PARAMS)233 _mesa_texstore_bptc_rgb_unsigned_float(TEXSTORE_PARAMS)
234 {
235    assert(dstFormat == MESA_FORMAT_BPTC_RGB_UNSIGNED_FLOAT);
236 
237    return texstore_bptc_rgb_float(ctx, dims, baseInternalFormat,
238                                   dstFormat, dstRowStride, dstSlices,
239                                   srcWidth, srcHeight, srcDepth,
240                                   srcFormat, srcType,
241                                   srcAddr, srcPacking,
242                                   false /* unsigned */);
243 }
244