mesa: Add decoding functions for GL_COMPRESSED_SRGB8_ETC2
[mesa.git] / src / mesa / main / texcompress_etc.c
1 /*
2 * Copyright (C) 2011 LunarG, Inc.
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_etc.c
26 * GL_OES_compressed_ETC1_RGB8_texture support.
27 * Supported ETC2 texture formats are:
28 * GL_COMPRESSED_RGB8_ETC2
29 * GL_COMPRESSED_SRGB8_ETC2
30 */
31
32 #include <stdbool.h>
33 #include "mfeatures.h"
34 #include "texcompress.h"
35 #include "texcompress_etc.h"
36 #include "texstore.h"
37 #include "macros.h"
38 #include "swrast/s_context.h"
39 #include "format_unpack.h"
40
41 struct etc2_block {
42 int distance;
43 uint32_t pixel_indices;
44 const int *modifier_tables[2];
45 bool flipped;
46 bool is_ind_mode;
47 bool is_diff_mode;
48 bool is_t_mode;
49 bool is_h_mode;
50 bool is_planar_mode;
51 uint8_t base_colors[3][3];
52 uint8_t paint_colors[4][3];
53 };
54
55 static const int etc2_distance_table[8] = {
56 3, 6, 11, 16, 23, 32, 41, 64 };
57
58 /* define etc1_parse_block and etc. */
59 #define UINT8_TYPE GLubyte
60 #define TAG(x) x
61 #include "texcompress_etc_tmp.h"
62 #undef TAG
63 #undef UINT8_TYPE
64
65 GLboolean
66 _mesa_texstore_etc1_rgb8(TEXSTORE_PARAMS)
67 {
68 /* GL_ETC1_RGB8_OES is only valid in glCompressedTexImage2D */
69 ASSERT(0);
70
71 return GL_FALSE;
72 }
73
74 void
75 _mesa_fetch_texel_2d_f_etc1_rgb8(const struct swrast_texture_image *texImage,
76 GLint i, GLint j, GLint k, GLfloat *texel)
77 {
78 struct etc1_block block;
79 GLubyte dst[3];
80 const GLubyte *src;
81
82 src = (const GLubyte *) texImage->Map +
83 (((texImage->RowStride + 3) / 4) * (j / 4) + (i / 4)) * 8;
84
85 etc1_parse_block(&block, src);
86 etc1_fetch_texel(&block, i % 4, j % 4, dst);
87
88 texel[RCOMP] = UBYTE_TO_FLOAT(dst[0]);
89 texel[GCOMP] = UBYTE_TO_FLOAT(dst[1]);
90 texel[BCOMP] = UBYTE_TO_FLOAT(dst[2]);
91 texel[ACOMP] = 1.0f;
92 }
93
94 /**
95 * Decode texture data in format `MESA_FORMAT_ETC1_RGB8` to
96 * `MESA_FORMAT_ABGR8888`.
97 *
98 * The size of the source data must be a multiple of the ETC1 block size,
99 * which is 8, even if the texture image's dimensions are not aligned to 4.
100 * From the GL_OES_compressed_ETC1_RGB8_texture spec:
101 * The texture is described as a number of 4x4 pixel blocks. If the
102 * texture (or a particular mip-level) is smaller than 4 pixels in
103 * any dimension (such as a 2x2 or a 8x1 texture), the texture is
104 * found in the upper left part of the block(s), and the rest of the
105 * pixels are not used. For instance, a texture of size 4x2 will be
106 * placed in the upper half of a 4x4 block, and the lower half of the
107 * pixels in the block will not be accessed.
108 *
109 * \param src_width in pixels
110 * \param src_height in pixels
111 * \param dst_stride in bytes
112 */
113 void
114 _mesa_etc1_unpack_rgba8888(uint8_t *dst_row,
115 unsigned dst_stride,
116 const uint8_t *src_row,
117 unsigned src_stride,
118 unsigned src_width,
119 unsigned src_height)
120 {
121 etc1_unpack_rgba8888(dst_row, dst_stride,
122 src_row, src_stride,
123 src_width, src_height);
124 }
125
126 static uint8_t
127 etc2_base_color1_t_mode(const uint8_t *in, GLuint index)
128 {
129 uint8_t R1a = 0, x = 0;
130 /* base col 1 = extend_4to8bits( (R1a << 2) | R1b, G1, B1) */
131 switch(index) {
132 case 0:
133 R1a = (in[0] >> 3) & 0x3;
134 x = ((R1a << 2) | (in[0] & 0x3));
135 break;
136 case 1:
137 x = ((in[1] >> 4) & 0xf);
138 break;
139 case 2:
140 x = (in[1] & 0xf);
141 break;
142 default:
143 /* invalid index */
144 break;
145 }
146 return ((x << 4) | (x & 0xf));
147 }
148
149 static uint8_t
150 etc2_base_color2_t_mode(const uint8_t *in, GLuint index)
151 {
152 uint8_t x = 0;
153 /*extend 4to8bits(R2, G2, B2)*/
154 switch(index) {
155 case 0:
156 x = ((in[2] >> 4) & 0xf );
157 break;
158 case 1:
159 x = (in[2] & 0xf);
160 break;
161 case 2:
162 x = ((in[3] >> 4) & 0xf);
163 break;
164 default:
165 /* invalid index */
166 break;
167 }
168 return ((x << 4) | (x & 0xf));
169 }
170
171 static uint8_t
172 etc2_base_color1_h_mode(const uint8_t *in, GLuint index)
173 {
174 uint8_t x = 0;
175 /* base col 1 = extend 4to8bits(R1, (G1a << 1) | G1b, (B1a << 3) | B1b) */
176 switch(index) {
177 case 0:
178 x = ((in[0] >> 3) & 0xf);
179 break;
180 case 1:
181 x = (((in[0] & 0x7) << 1) | ((in[1] >> 4) & 0x1));
182 break;
183 case 2:
184 x = ((in[1] & 0x8) |
185 (((in[1] & 0x3) << 1) | ((in[2] >> 7) & 0x1)));
186 break;
187 default:
188 /* invalid index */
189 break;
190 }
191 return ((x << 4) | (x & 0xf));
192 }
193
194 static uint8_t
195 etc2_base_color2_h_mode(const uint8_t *in, GLuint index)
196 {
197 uint8_t x = 0;
198 /* base col 2 = extend 4to8bits(R2, G2, B2) */
199 switch(index) {
200 case 0:
201 x = ((in[2] >> 3) & 0xf );
202 break;
203 case 1:
204 x = (((in[2] & 0x7) << 1) | ((in[3] >> 7) & 0x1));
205 break;
206 case 2:
207 x = ((in[3] >> 3) & 0xf);
208 break;
209 default:
210 /* invalid index */
211 break;
212 }
213 return ((x << 4) | (x & 0xf));
214 }
215
216 static uint8_t
217 etc2_base_color_o_planar(const uint8_t *in, GLuint index)
218 {
219 GLuint tmp;
220 switch(index) {
221 case 0:
222 tmp = ((in[0] >> 1) & 0x3f); /* RO */
223 return ((tmp << 2) | (tmp >> 4));
224 case 1:
225 tmp = (((in[0] & 0x1) << 6) | /* GO1 */
226 ((in[1] >> 1) & 0x3f)); /* GO2 */
227 return ((tmp << 1) | (tmp >> 6));
228 case 2:
229 tmp = (((in[1] & 0x1) << 5) | /* BO1 */
230 (in[2] & 0x18) | /* BO2 */
231 (((in[2] & 0x3) << 1) | ((in[3] >> 7) & 0x1))); /* BO3 */
232 return ((tmp << 2) | (tmp >> 4));
233 default:
234 /* invalid index */
235 return 0;
236 }
237 }
238
239 static uint8_t
240 etc2_base_color_h_planar(const uint8_t *in, GLuint index)
241 {
242 GLuint tmp;
243 switch(index) {
244 case 0:
245 tmp = (((in[3] & 0x7c) >> 1) | /* RH1 */
246 (in[3] & 0x1)); /* RH2 */
247 return ((tmp << 2) | (tmp >> 4));
248 case 1:
249 tmp = (in[4] >> 1) & 0x7f; /* GH */
250 return ((tmp << 1) | (tmp >> 6));
251 case 2:
252 tmp = (((in[4] & 0x1) << 5) |
253 ((in[5] >> 3) & 0x1f)); /* BH */
254 return ((tmp << 2) | (tmp >> 4));
255 default:
256 /* invalid index */
257 return 0;
258 }
259 }
260
261 static uint8_t
262 etc2_base_color_v_planar(const uint8_t *in, GLuint index)
263 {
264 GLuint tmp;
265 switch(index) {
266 case 0:
267 tmp = (((in[5] & 0x7) << 0x3) |
268 ((in[6] >> 5) & 0x7)); /* RV */
269 return ((tmp << 2) | (tmp >> 4));
270 case 1:
271 tmp = (((in[6] & 0x1f) << 2) |
272 ((in[7] >> 6) & 0x3)); /* GV */
273 return ((tmp << 1) | (tmp >> 6));
274 case 2:
275 tmp = in[7] & 0x3f; /* BV */
276 return ((tmp << 2) | (tmp >> 4));
277 default:
278 /* invalid index */
279 return 0;
280 }
281 }
282
283 static uint8_t
284 etc2_clamp(int color)
285 {
286 /* CLAMP(color, 0, 255) */
287 return (uint8_t) CLAMP(color, 0, 255);
288 }
289
290 static void
291 etc2_rgb8_parse_block(struct etc2_block *block, const uint8_t *src)
292 {
293 unsigned i;
294 GLboolean diffbit = src[3] & 0x2;
295 static const int lookup[8] = { 0, 1, 2, 3, -4, -3, -2, -1 };
296
297 const int R_plus_dR = (src[0] >> 3) + lookup[src[0] & 0x7];
298 const int G_plus_dG = (src[1] >> 3) + lookup[src[1] & 0x7];
299 const int B_plus_dB = (src[2] >> 3) + lookup[src[2] & 0x7];
300
301 /* Reset the mode flags */
302 block->is_ind_mode = false;
303 block->is_diff_mode = false;
304 block->is_t_mode = false;
305 block->is_h_mode = false;
306 block->is_planar_mode = false;
307
308 if (!diffbit) {
309 /* individual mode */
310 block->is_ind_mode = true;
311
312 for (i = 0; i < 3; i++) {
313 /* Texture decode algorithm is same for individual mode in etc1
314 * & etc2.
315 */
316 block->base_colors[0][i] = etc1_base_color_ind_hi(src[i]);
317 block->base_colors[1][i] = etc1_base_color_ind_lo(src[i]);
318 }
319 }
320 else if (R_plus_dR < 0 || R_plus_dR > 31){
321 /* T mode */
322 block->is_t_mode = true;
323
324 for(i = 0; i < 3; i++) {
325 block->base_colors[0][i] = etc2_base_color1_t_mode(src, i);
326 block->base_colors[1][i] = etc2_base_color2_t_mode(src, i);
327 }
328 /* pick distance */
329 block->distance =
330 etc2_distance_table[(((src[3] >> 2) & 0x3) << 1) |
331 (src[3] & 0x1)];
332
333 for (i = 0; i < 3; i++) {
334 block->paint_colors[0][i] = etc2_clamp(block->base_colors[0][i]);
335 block->paint_colors[1][i] = etc2_clamp(block->base_colors[1][i] +
336 block->distance);
337 block->paint_colors[2][i] = etc2_clamp(block->base_colors[1][i]);
338 block->paint_colors[3][i] = etc2_clamp(block->base_colors[1][i] -
339 block->distance);
340 }
341 }
342 else if (G_plus_dG < 0 || G_plus_dG > 31){
343 /* H mode */
344 block->is_h_mode = true;
345 int base_color_1_value, base_color_2_value;
346
347 for(i = 0; i < 3; i++) {
348 block->base_colors[0][i] = etc2_base_color1_h_mode(src, i);
349 block->base_colors[1][i] = etc2_base_color2_h_mode(src, i);
350 }
351
352 base_color_1_value = (block->base_colors[0][0] << 16) +
353 (block->base_colors[0][1] << 8) +
354 block->base_colors[0][2];
355 base_color_2_value = (block->base_colors[1][0] << 16) +
356 (block->base_colors[1][1] << 8) +
357 block->base_colors[1][2];
358 /* pick distance */
359 block->distance =
360 etc2_distance_table[(src[3] & 0x4) |
361 ((src[3] & 0x1) << 1) |
362 (base_color_1_value >= base_color_2_value)];
363
364 for (i = 0; i < 3; i++) {
365 block->paint_colors[0][i] = etc2_clamp(block->base_colors[0][i] +
366 block->distance);
367 block->paint_colors[1][i] = etc2_clamp(block->base_colors[0][i] -
368 block->distance);
369 block->paint_colors[2][i] = etc2_clamp(block->base_colors[1][i] +
370 block->distance);
371 block->paint_colors[3][i] = etc2_clamp(block->base_colors[1][i] -
372 block->distance);
373 }
374 }
375 else if (B_plus_dB < 0 || B_plus_dB > 31){
376 /* Planar mode */
377 block->is_planar_mode = true;
378
379 for (i = 0; i < 3; i++) {
380 block->base_colors[0][i] = etc2_base_color_o_planar(src, i);
381 block->base_colors[1][i] = etc2_base_color_h_planar(src, i);
382 block->base_colors[2][i] = etc2_base_color_v_planar(src, i);
383 }
384 }
385 else if (diffbit) {
386 /* differential mode */
387 block->is_diff_mode = true;
388
389 for (i = 0; i < 3; i++) {
390 /* Texture decode algorithm is same for differential mode in etc1
391 * & etc2.
392 */
393 block->base_colors[0][i] = etc1_base_color_diff_hi(src[i]);
394 block->base_colors[1][i] = etc1_base_color_diff_lo(src[i]);
395 }
396 }
397
398 if (block->is_ind_mode || block->is_diff_mode) {
399 /* pick modifier tables. same for etc1 & etc2 textures */
400 block->modifier_tables[0] = etc1_modifier_tables[(src[3] >> 5) & 0x7];
401 block->modifier_tables[1] = etc1_modifier_tables[(src[3] >> 2) & 0x7];
402 block->flipped = (src[3] & 0x1);
403 }
404
405 block->pixel_indices =
406 (src[4] << 24) | (src[5] << 16) | (src[6] << 8) | src[7];
407 }
408
409 static void
410 etc2_rgb8_fetch_texel(const struct etc2_block *block,
411 int x, int y, uint8_t *dst)
412 {
413 const uint8_t *base_color;
414 int modifier, bit, idx, blk;
415
416 /* get pixel index */
417 bit = y + x * 4;
418 idx = ((block->pixel_indices >> (15 + bit)) & 0x2) |
419 ((block->pixel_indices >> (bit)) & 0x1);
420
421 if (block->is_ind_mode || block->is_diff_mode) {
422 /* Use pixel index and subblock to get the modifier */
423 blk = (block->flipped) ? (y >= 2) : (x >= 2);
424 base_color = block->base_colors[blk];
425 modifier = block->modifier_tables[blk][idx];
426
427 dst[0] = etc2_clamp(base_color[0] + modifier);
428 dst[1] = etc2_clamp(base_color[1] + modifier);
429 dst[2] = etc2_clamp(base_color[2] + modifier);
430 }
431 else if (block->is_t_mode || block->is_h_mode) {
432 /* Use pixel index to pick one of the paint colors */
433 dst[0] = block->paint_colors[idx][0];
434 dst[1] = block->paint_colors[idx][1];
435 dst[2] = block->paint_colors[idx][2];
436 }
437 else if (block->is_planar_mode) {
438 /* {R(x, y) = clamp255((x × (RH − RO) + y × (RV − RO) + 4 × RO + 2) >> 2)
439 * {G(x, y) = clamp255((x × (GH − GO) + y × (GV − GO) + 4 × GO + 2) >> 2)
440 * {B(x, y) = clamp255((x × (BH − BO) + y × (BV − BO) + 4 × BO + 2) >> 2)
441 */
442 int red, green, blue;
443 red = (x * (block->base_colors[1][0] - block->base_colors[0][0]) +
444 y * (block->base_colors[2][0] - block->base_colors[0][0]) +
445 4 * block->base_colors[0][0] + 2) >> 2;
446
447 green = (x * (block->base_colors[1][1] - block->base_colors[0][1]) +
448 y * (block->base_colors[2][1] - block->base_colors[0][1]) +
449 4 * block->base_colors[0][1] + 2) >> 2;
450
451 blue = (x * (block->base_colors[1][2] - block->base_colors[0][2]) +
452 y * (block->base_colors[2][2] - block->base_colors[0][2]) +
453 4 * block->base_colors[0][2] + 2) >> 2;
454
455 dst[0] = etc2_clamp(red);
456 dst[1] = etc2_clamp(green);
457 dst[2] = etc2_clamp(blue);
458 }
459 }
460
461 static void
462 etc2_unpack_rgb8(uint8_t *dst_row,
463 unsigned dst_stride,
464 const uint8_t *src_row,
465 unsigned src_stride,
466 unsigned width,
467 unsigned height)
468 {
469 const unsigned bw = 4, bh = 4, bs = 8, comps = 4;
470 struct etc2_block block;
471 unsigned x, y, i, j;
472
473 for (y = 0; y < height; y += bh) {
474 const uint8_t *src = src_row;
475
476 for (x = 0; x < width; x+= bw) {
477 etc2_rgb8_parse_block(&block, src);
478
479 for (j = 0; j < bh; j++) {
480 uint8_t *dst = dst_row + (y + j) * dst_stride + x * comps;
481 for (i = 0; i < bw; i++) {
482 etc2_rgb8_fetch_texel(&block, i, j, dst);
483 dst[3] = 255;
484 dst += comps;
485 }
486 }
487
488 src += bs;
489 }
490
491 src_row += src_stride;
492 }
493 }
494
495 static void
496 etc2_unpack_srgb8(uint8_t *dst_row,
497 unsigned dst_stride,
498 const uint8_t *src_row,
499 unsigned src_stride,
500 unsigned width,
501 unsigned height)
502 {
503 const unsigned bw = 4, bh = 4, bs = 8, comps = 4;
504 struct etc2_block block;
505 unsigned x, y, i, j;
506 uint8_t tmp;
507
508 for (y = 0; y < height; y += bh) {
509 const uint8_t *src = src_row;
510
511 for (x = 0; x < width; x+= bw) {
512 etc2_rgb8_parse_block(&block, src);
513
514 for (j = 0; j < bh; j++) {
515 uint8_t *dst = dst_row + (y + j) * dst_stride + x * comps;
516 for (i = 0; i < bw; i++) {
517 etc2_rgb8_fetch_texel(&block, i, j, dst);
518 /* Convert to MESA_FORMAT_SARGB8 */
519 tmp = dst[0];
520 dst[0] = dst[2];
521 dst[2] = tmp;
522 dst[3] = 255;
523
524 dst += comps;
525 }
526 }
527 src += bs;
528 }
529
530 src_row += src_stride;
531 }
532 }
533
534 /* ETC2 texture formats are valid in glCompressedTexImage2D and
535 * glCompressedTexSubImage2D functions */
536 GLboolean
537 _mesa_texstore_etc2_rgb8(TEXSTORE_PARAMS)
538 {
539 ASSERT(0);
540
541 return GL_FALSE;
542 }
543
544 GLboolean
545 _mesa_texstore_etc2_srgb8(TEXSTORE_PARAMS)
546 {
547 ASSERT(0);
548
549 return GL_FALSE;
550 }
551
552 void
553 _mesa_fetch_texel_2d_f_etc2_rgb8(const struct swrast_texture_image *texImage,
554 GLint i, GLint j, GLint k, GLfloat *texel)
555 {
556 struct etc2_block block;
557 uint8_t dst[3];
558 const uint8_t *src;
559
560 src = texImage->Map +
561 (((texImage->RowStride + 3) / 4) * (j / 4) + (i / 4)) * 8;
562
563 etc2_rgb8_parse_block(&block, src);
564 etc2_rgb8_fetch_texel(&block, i % 4, j % 4, dst);
565
566 texel[RCOMP] = UBYTE_TO_FLOAT(dst[0]);
567 texel[GCOMP] = UBYTE_TO_FLOAT(dst[1]);
568 texel[BCOMP] = UBYTE_TO_FLOAT(dst[2]);
569 texel[ACOMP] = 1.0f;
570 }
571
572 void
573 _mesa_fetch_texel_2d_f_etc2_srgb8(const struct swrast_texture_image *texImage,
574 GLint i, GLint j, GLint k, GLfloat *texel)
575 {
576 struct etc2_block block;
577 uint8_t dst[3];
578 const uint8_t *src;
579
580 src = texImage->Map +
581 (((texImage->RowStride + 3) / 4) * (j / 4) + (i / 4)) * 8;
582
583 etc2_rgb8_parse_block(&block, src);
584 etc2_rgb8_fetch_texel(&block, i % 4, j % 4, dst);
585
586 texel[RCOMP] = _mesa_nonlinear_to_linear(dst[0]);
587 texel[GCOMP] = _mesa_nonlinear_to_linear(dst[1]);
588 texel[BCOMP] = _mesa_nonlinear_to_linear(dst[2]);
589 texel[ACOMP] = 1.0f;
590 }
591
592 /**
593 * Decode texture data in any one of following formats:
594 * `MESA_FORMAT_ETC2_RGB8`
595 * `MESA_FORMAT_ETC2_SRGB8`
596 *
597 * The size of the source data must be a multiple of the ETC2 block size
598 * even if the texture image's dimensions are not aligned to 4.
599 *
600 * \param src_width in pixels
601 * \param src_height in pixels
602 * \param dst_stride in bytes
603 */
604
605 void
606 _mesa_unpack_etc2_format(uint8_t *dst_row,
607 unsigned dst_stride,
608 const uint8_t *src_row,
609 unsigned src_stride,
610 unsigned src_width,
611 unsigned src_height,
612 gl_format format)
613 {
614 if (format == MESA_FORMAT_ETC2_RGB8)
615 etc2_unpack_rgb8(dst_row, dst_stride,
616 src_row, src_stride,
617 src_width, src_height);
618 else if (format == MESA_FORMAT_ETC2_SRGB8)
619 etc2_unpack_srgb8(dst_row, dst_stride,
620 src_row, src_stride,
621 src_width, src_height);
622 }