rgtc: shared the compressor code between signed/unsigned
[mesa.git] / src / mesa / main / texcompress_rgtc.c
1 /*
2 * Copyright (C) 2011 Red Hat Inc.
3 *
4 * block compression parts are:
5 * Copyright (C) 2004 Roland Scheidegger All Rights Reserved.
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 (including the next
15 * paragraph) shall be included in all copies or substantial portions of the
16 * Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24 * DEALINGS IN THE SOFTWARE.
25 *
26 * Author:
27 * Dave Airlie
28 */
29
30 /**
31 * \file texcompress_rgtc.c
32 * GL_EXT_texture_compression_rgtc support.
33 */
34
35
36 #include "glheader.h"
37 #include "imports.h"
38 #include "colormac.h"
39 #include "image.h"
40 #include "macros.h"
41 #include "mfeatures.h"
42 #include "mipmap.h"
43 #include "texcompress.h"
44 #include "texcompress_rgtc.h"
45 #include "texstore.h"
46
47 #define RGTC_DEBUG 0
48
49 static void unsigned_encode_rgtc_chan(GLubyte *blkaddr, GLubyte srccolors[4][4],
50 GLint numxpixels, GLint numypixels);
51 static void signed_encode_rgtc_chan(GLbyte *blkaddr, GLbyte srccolors[4][4],
52 GLint numxpixels, GLint numypixels);
53
54 static void extractsrc_u( GLubyte srcpixels[4][4], const GLchan *srcaddr,
55 GLint srcRowStride, GLint numxpixels, GLint numypixels, GLint comps)
56 {
57 GLubyte i, j;
58 const GLchan *curaddr;
59 for (j = 0; j < numypixels; j++) {
60 curaddr = srcaddr + j * srcRowStride * comps;
61 for (i = 0; i < numxpixels; i++) {
62 srcpixels[j][i] = *curaddr / (CHAN_MAX / 255);
63 curaddr += comps;
64 }
65 }
66 }
67
68 static void extractsrc_s( GLbyte srcpixels[4][4], const GLfloat *srcaddr,
69 GLint srcRowStride, GLint numxpixels, GLint numypixels, GLint comps)
70 {
71 GLubyte i, j;
72 const GLfloat *curaddr;
73 for (j = 0; j < numypixels; j++) {
74 curaddr = srcaddr + j * srcRowStride * comps;
75 for (i = 0; i < numxpixels; i++) {
76 srcpixels[j][i] = FLOAT_TO_BYTE_TEX(*curaddr);
77 curaddr += comps;
78 }
79 }
80 }
81
82
83 GLboolean
84 _mesa_texstore_red_rgtc1(TEXSTORE_PARAMS)
85 {
86 GLubyte *dst;
87 const GLint texWidth = dstRowStride * 4 / 8; /* a bit of a hack */
88 const GLchan *tempImage = NULL;
89 int i, j;
90 int numxpixels, numypixels;
91 const GLchan *srcaddr;
92 GLubyte srcpixels[4][4];
93 GLubyte *blkaddr;
94 GLint dstRowDiff;
95 ASSERT(dstFormat == MESA_FORMAT_RED_RGTC1);
96 ASSERT(dstXoffset % 4 == 0);
97 ASSERT(dstYoffset % 4 == 0);
98 ASSERT(dstZoffset % 4 == 0);
99 (void) dstZoffset;
100 (void) dstImageOffsets;
101
102
103 tempImage = _mesa_make_temp_chan_image(ctx, dims,
104 baseInternalFormat,
105 _mesa_get_format_base_format(dstFormat),
106 srcWidth, srcHeight, srcDepth,
107 srcFormat, srcType, srcAddr,
108 srcPacking);
109 if (!tempImage)
110 return GL_FALSE; /* out of memory */
111
112 dst = _mesa_compressed_image_address(dstXoffset, dstYoffset, 0,
113 dstFormat,
114 texWidth, (GLubyte *) dstAddr);
115
116 blkaddr = dst;
117 dstRowDiff = dstRowStride >= (srcWidth * 4) ? dstRowStride - (((srcWidth + 3) & ~3) * 4) : 0;
118 for (j = 0; j < srcHeight; j+=4) {
119 if (srcHeight > j + 3) numypixels = 4;
120 else numypixels = srcHeight - j;
121 srcaddr = tempImage + j * srcWidth;
122 for (i = 0; i < srcWidth; i += 4) {
123 if (srcWidth > i + 3) numxpixels = 4;
124 else numxpixels = srcWidth - i;
125 extractsrc_u(srcpixels, srcaddr, srcWidth, numxpixels, numypixels, 1);
126 unsigned_encode_rgtc_chan(blkaddr, srcpixels, numxpixels, numypixels);
127 srcaddr += numxpixels;
128 blkaddr += 8;
129 }
130 blkaddr += dstRowDiff;
131 }
132 if (tempImage)
133 free((void *) tempImage);
134
135 return GL_TRUE;
136 }
137
138 GLboolean
139 _mesa_texstore_signed_red_rgtc1(TEXSTORE_PARAMS)
140 {
141 GLbyte *dst;
142 const GLint texWidth = dstRowStride * 4 / 8; /* a bit of a hack */
143 const GLfloat *tempImage = NULL;
144 int i, j;
145 int numxpixels, numypixels;
146 const GLfloat *srcaddr;
147 GLbyte srcpixels[4][4];
148 GLbyte *blkaddr;
149 GLint dstRowDiff;
150 ASSERT(dstFormat == MESA_FORMAT_SIGNED_RED_RGTC1);
151 ASSERT(dstXoffset % 4 == 0);
152 ASSERT(dstYoffset % 4 == 0);
153 ASSERT(dstZoffset % 4 == 0);
154 (void) dstZoffset;
155 (void) dstImageOffsets;
156
157 tempImage = _mesa_make_temp_float_image(ctx, dims,
158 baseInternalFormat,
159 _mesa_get_format_base_format(dstFormat),
160 srcWidth, srcHeight, srcDepth,
161 srcFormat, srcType, srcAddr,
162 srcPacking, 0x0);
163 if (!tempImage)
164 return GL_FALSE; /* out of memory */
165
166 dst = (GLbyte *)_mesa_compressed_image_address(dstXoffset, dstYoffset, 0,
167 dstFormat,
168 texWidth, (GLubyte *) dstAddr);
169
170 blkaddr = dst;
171 dstRowDiff = dstRowStride >= (srcWidth * 4) ? dstRowStride - (((srcWidth + 3) & ~3) * 4) : 0;
172 for (j = 0; j < srcHeight; j+=4) {
173 if (srcHeight > j + 3) numypixels = 4;
174 else numypixels = srcHeight - j;
175 srcaddr = tempImage + j * srcWidth;
176 for (i = 0; i < srcWidth; i += 4) {
177 if (srcWidth > i + 3) numxpixels = 4;
178 else numxpixels = srcWidth - i;
179 extractsrc_s(srcpixels, srcaddr, srcWidth, numxpixels, numypixels, 1);
180 signed_encode_rgtc_chan(blkaddr, srcpixels, numxpixels, numypixels);
181 srcaddr += numxpixels;
182 blkaddr += 8;
183 }
184 blkaddr += dstRowDiff;
185 }
186 if (tempImage)
187 free((void *) tempImage);
188
189 return GL_TRUE;
190 }
191
192 GLboolean
193 _mesa_texstore_rg_rgtc2(TEXSTORE_PARAMS)
194 {
195 GLubyte *dst;
196 const GLint texWidth = dstRowStride * 4 / 16; /* a bit of a hack */
197 const GLchan *tempImage = NULL;
198 int i, j;
199 int numxpixels, numypixels;
200 const GLchan *srcaddr;
201 GLubyte srcpixels[4][4];
202 GLubyte *blkaddr;
203 GLint dstRowDiff;
204
205 ASSERT(dstFormat == MESA_FORMAT_RG_RGTC2);
206 ASSERT(dstXoffset % 4 == 0);
207 ASSERT(dstYoffset % 4 == 0);
208 ASSERT(dstZoffset % 4 == 0);
209 (void) dstZoffset;
210 (void) dstImageOffsets;
211
212 tempImage = _mesa_make_temp_chan_image(ctx, dims,
213 baseInternalFormat,
214 _mesa_get_format_base_format(dstFormat),
215 srcWidth, srcHeight, srcDepth,
216 srcFormat, srcType, srcAddr,
217 srcPacking);
218 if (!tempImage)
219 return GL_FALSE; /* out of memory */
220
221 dst = _mesa_compressed_image_address(dstXoffset, dstYoffset, 0,
222 dstFormat,
223 texWidth, (GLubyte *) dstAddr);
224
225 blkaddr = dst;
226 dstRowDiff = dstRowStride >= (srcWidth * 8) ? dstRowStride - (((srcWidth + 7) & ~7) * 8) : 0;
227 for (j = 0; j < srcHeight; j+=4) {
228 if (srcHeight > j + 3) numypixels = 4;
229 else numypixels = srcHeight - j;
230 srcaddr = tempImage + j * srcWidth * 2;
231 for (i = 0; i < srcWidth; i += 4) {
232 if (srcWidth > i + 3) numxpixels = 4;
233 else numxpixels = srcWidth - i;
234 extractsrc_u(srcpixels, srcaddr, srcWidth, numxpixels, numypixels, 2);
235 unsigned_encode_rgtc_chan(blkaddr, srcpixels, numxpixels, numypixels);
236
237 blkaddr += 8;
238 extractsrc_u(srcpixels, (GLchan *)srcaddr + 1, srcWidth, numxpixels, numypixels, 2);
239 unsigned_encode_rgtc_chan(blkaddr, srcpixels, numxpixels, numypixels);
240
241 blkaddr += 8;
242
243 srcaddr += numxpixels * 2;
244 }
245 blkaddr += dstRowDiff;
246 }
247 if (tempImage)
248 free((void *) tempImage);
249
250 return GL_TRUE;
251 }
252
253 GLboolean
254 _mesa_texstore_signed_rg_rgtc2(TEXSTORE_PARAMS)
255 {
256 GLbyte *dst;
257 const GLint texWidth = dstRowStride * 4 / 16; /* a bit of a hack */
258 const GLfloat *tempImage = NULL;
259 int i, j;
260 int numxpixels, numypixels;
261 const GLfloat *srcaddr;
262 GLbyte srcpixels[4][4];
263 GLbyte *blkaddr;
264 GLint dstRowDiff;
265
266 ASSERT(dstFormat == MESA_FORMAT_SIGNED_RG_RGTC2);
267 ASSERT(dstXoffset % 4 == 0);
268 ASSERT(dstYoffset % 4 == 0);
269 ASSERT(dstZoffset % 4 == 0);
270 (void) dstZoffset;
271 (void) dstImageOffsets;
272
273 tempImage = _mesa_make_temp_float_image(ctx, dims,
274 baseInternalFormat,
275 _mesa_get_format_base_format(dstFormat),
276 srcWidth, srcHeight, srcDepth,
277 srcFormat, srcType, srcAddr,
278 srcPacking, 0x0);
279 if (!tempImage)
280 return GL_FALSE; /* out of memory */
281
282 dst = (GLbyte *)_mesa_compressed_image_address(dstXoffset, dstYoffset, 0,
283 dstFormat,
284 texWidth, (GLubyte *) dstAddr);
285
286 blkaddr = dst;
287 dstRowDiff = dstRowStride >= (srcWidth * 8) ? dstRowStride - (((srcWidth + 7) & ~7) * 8) : 0;
288 for (j = 0; j < srcHeight; j += 4) {
289 if (srcHeight > j + 3) numypixels = 4;
290 else numypixels = srcHeight - j;
291 srcaddr = tempImage + j * srcWidth * 2;
292 for (i = 0; i < srcWidth; i += 4) {
293 if (srcWidth > i + 3) numxpixels = 4;
294 else numxpixels = srcWidth - i;
295
296 extractsrc_s(srcpixels, srcaddr, srcWidth, numxpixels, numypixels, 2);
297 signed_encode_rgtc_chan(blkaddr, srcpixels, numxpixels, numypixels);
298 blkaddr += 8;
299
300 extractsrc_s(srcpixels, srcaddr + 1, srcWidth, numxpixels, numypixels, 2);
301 signed_encode_rgtc_chan(blkaddr, srcpixels, numxpixels, numypixels);
302 blkaddr += 8;
303
304 srcaddr += numxpixels * 2;
305
306 }
307 blkaddr += dstRowDiff;
308 }
309 if (tempImage)
310 free((void *) tempImage);
311
312 return GL_TRUE;
313 }
314
315 static void _fetch_texel_rgtc_u(GLint srcRowStride, const GLubyte *pixdata,
316 GLint i, GLint j, GLchan *value, int comps)
317 {
318 GLchan decode;
319 const GLubyte *blksrc = (pixdata + ((srcRowStride + 3) / 4 * (j / 4) + (i / 4)) * 8 * comps);
320 const GLubyte alpha0 = blksrc[0];
321 const GLubyte alpha1 = blksrc[1];
322 const GLubyte bit_pos = ((j&3) * 4 + (i&3)) * 3;
323 const GLubyte acodelow = blksrc[2 + bit_pos / 8];
324 const GLubyte acodehigh = blksrc[3 + bit_pos / 8];
325 const GLubyte code = (acodelow >> (bit_pos & 0x7) |
326 (acodehigh << (8 - (bit_pos & 0x7)))) & 0x7;
327
328 if (code == 0)
329 decode = UBYTE_TO_CHAN( alpha0 );
330 else if (code == 1)
331 decode = UBYTE_TO_CHAN( alpha1 );
332 else if (alpha0 > alpha1)
333 decode = UBYTE_TO_CHAN( ((alpha0 * (8 - code) + (alpha1 * (code - 1))) / 7) );
334 else if (code < 6)
335 decode = UBYTE_TO_CHAN( ((alpha0 * (6 - code) + (alpha1 * (code - 1))) / 5) );
336 else if (code == 6)
337 decode = 0;
338 else
339 decode = CHAN_MAX;
340
341 *value = decode;
342 }
343
344
345 static void _fetch_texel_rgtc_s(GLint srcRowStride, const GLbyte *pixdata,
346 GLint i, GLint j, GLbyte *value, int comps)
347 {
348 GLbyte decode;
349 const GLbyte *blksrc = (pixdata + ((srcRowStride + 3) / 4 * (j / 4) + (i / 4)) * 8 * comps);
350 const GLbyte alpha0 = blksrc[0];
351 const GLbyte alpha1 = blksrc[1];
352 const GLbyte bit_pos = ((j&3) * 4 + (i&3)) * 3;
353 const GLbyte acodelow = blksrc[2 + bit_pos / 8];
354 const GLbyte acodehigh = blksrc[3 + bit_pos / 8];
355 const GLbyte code = (acodelow >> (bit_pos & 0x7) |
356 (acodehigh << (8 - (bit_pos & 0x7)))) & 0x7;
357
358 if (code == 0)
359 decode = alpha0;
360 else if (code == 1)
361 decode = alpha1;
362 else if (alpha0 > alpha1)
363 decode = ((alpha0 * (8 - code) + (alpha1 * (code - 1))) / 7);
364 else if (code < 6)
365 decode = ((alpha0 * (6 - code) + (alpha1 * (code - 1))) / 5);
366 else if (code == 6)
367 decode = -128;
368 else
369 decode = 127;
370
371 *value = decode;
372 }
373
374 void
375 _mesa_fetch_texel_2d_f_red_rgtc1(const struct gl_texture_image *texImage,
376 GLint i, GLint j, GLint k, GLfloat *texel)
377 {
378 GLchan red;
379 _fetch_texel_rgtc_u(texImage->RowStride, (GLubyte *)(texImage->Data),
380 i, j, &red, 1);
381 texel[RCOMP] = CHAN_TO_FLOAT(red);
382 texel[GCOMP] = 0.0;
383 texel[BCOMP] = 0.0;
384 texel[ACOMP] = 1.0;
385 }
386
387 void
388 _mesa_fetch_texel_2d_f_signed_red_rgtc1(const struct gl_texture_image *texImage,
389 GLint i, GLint j, GLint k, GLfloat *texel)
390 {
391 GLbyte red;
392 _fetch_texel_rgtc_s(texImage->RowStride, (GLbyte *)(texImage->Data),
393 i, j, &red, 1);
394 texel[RCOMP] = BYTE_TO_FLOAT_TEX(red);
395 texel[GCOMP] = 0.0;
396 texel[BCOMP] = 0.0;
397 texel[ACOMP] = 1.0;
398 }
399
400 void
401 _mesa_fetch_texel_2d_f_rg_rgtc2(const struct gl_texture_image *texImage,
402 GLint i, GLint j, GLint k, GLfloat *texel)
403 {
404 GLchan red, green;
405 _fetch_texel_rgtc_u(texImage->RowStride, (GLubyte *)(texImage->Data),
406 i, j, &red, 2);
407 _fetch_texel_rgtc_u(texImage->RowStride, (GLubyte *)(texImage->Data) + 8,
408 i, j, &green, 2);
409 texel[RCOMP] = CHAN_TO_FLOAT(red);
410 texel[GCOMP] = CHAN_TO_FLOAT(green);
411 texel[BCOMP] = 0.0;
412 texel[ACOMP] = 1.0;
413 }
414
415 void
416 _mesa_fetch_texel_2d_f_signed_rg_rgtc2(const struct gl_texture_image *texImage,
417 GLint i, GLint j, GLint k, GLfloat *texel)
418 {
419 GLbyte red, green;
420 _fetch_texel_rgtc_s(texImage->RowStride, (GLbyte *)(texImage->Data),
421 i, j, &red, 2);
422 _fetch_texel_rgtc_s(texImage->RowStride, (GLbyte *)(texImage->Data) + 8,
423 i, j, &green, 2);
424 texel[RCOMP] = BYTE_TO_FLOAT_TEX(red);
425 texel[GCOMP] = BYTE_TO_FLOAT_TEX(green);
426 texel[BCOMP] = 0.0;
427 texel[ACOMP] = 1.0;
428 }
429
430 #define TAG(x) unsigned_##x
431
432 #define TYPE GLubyte
433 #define T_MIN 0
434 #define T_MAX 0xff
435
436 #include "texcompress_rgtc_tmp.h"
437
438 #undef TAG
439 #undef TYPE
440 #undef T_MIN
441 #undef T_MAX
442
443 #define TAG(x) signed_##x
444 #define TYPE GLbyte
445 #define T_MIN (GLbyte)-127
446 #define T_MAX (GLbyte)127
447
448 #include "texcompress_rgtc_tmp.h"
449
450 #undef TAG
451 #undef TYPE
452 #undef T_MIN
453 #undef T_MAX