1 //
2 // Copyright (c) 2013-2015 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6
7 // loadimage_etc.cpp: Decodes ETC and EAC encoded textures.
8
9 #include "image_util/loadimage.h"
10
11 #include "common/mathutil.h"
12
13 #include "image_util/imageformats.h"
14
15 namespace angle
16 {
17 namespace
18 {
19
20 using IntensityModifier = const int[4];
21
22 // Table 3.17.2 sorted according to table 3.17.3
23 // clang-format off
24 static IntensityModifier intensityModifierDefault[] =
25 {
26 { 2, 8, -2, -8 },
27 { 5, 17, -5, -17 },
28 { 9, 29, -9, -29 },
29 { 13, 42, -13, -42 },
30 { 18, 60, -18, -60 },
31 { 24, 80, -24, -80 },
32 { 33, 106, -33, -106 },
33 { 47, 183, -47, -183 },
34 };
35 // clang-format on
36
37 // Table C.12, intensity modifier for non opaque punchthrough alpha
38 // clang-format off
39 static IntensityModifier intensityModifierNonOpaque[] =
40 {
41 { 0, 8, 0, -8 },
42 { 0, 17, 0, -17 },
43 { 0, 29, 0, -29 },
44 { 0, 42, 0, -42 },
45 { 0, 60, 0, -60 },
46 { 0, 80, 0, -80 },
47 { 0, 106, 0, -106 },
48 { 0, 183, 0, -183 },
49 };
50 // clang-format on
51
52 static const int kNumPixelsInBlock = 16;
53
54 struct ETC2Block
55 {
56 // Decodes unsigned single or dual channel block to bytes
decodeAsSingleChannelangle::__anond465fb730111::ETC2Block57 void decodeAsSingleChannel(uint8_t *dest,
58 size_t x,
59 size_t y,
60 size_t w,
61 size_t h,
62 size_t destPixelStride,
63 size_t destRowPitch,
64 bool isSigned) const
65 {
66 for (size_t j = 0; j < 4 && (y + j) < h; j++)
67 {
68 uint8_t *row = dest + (j * destRowPitch);
69 for (size_t i = 0; i < 4 && (x + i) < w; i++)
70 {
71 uint8_t *pixel = row + (i * destPixelStride);
72 if (isSigned)
73 {
74 *pixel = clampSByte(getSingleChannel(i, j, isSigned));
75 }
76 else
77 {
78 *pixel = clampByte(getSingleChannel(i, j, isSigned));
79 }
80 }
81 }
82 }
83
84 // Decodes RGB block to rgba8
decodeAsRGBangle::__anond465fb730111::ETC2Block85 void decodeAsRGB(uint8_t *dest,
86 size_t x,
87 size_t y,
88 size_t w,
89 size_t h,
90 size_t destRowPitch,
91 const uint8_t alphaValues[4][4],
92 bool punchThroughAlpha) const
93 {
94 bool opaqueBit = u.idht.mode.idm.diffbit;
95 bool nonOpaquePunchThroughAlpha = punchThroughAlpha && !opaqueBit;
96 // Select mode
97 if (u.idht.mode.idm.diffbit || punchThroughAlpha)
98 {
99 const auto &block = u.idht.mode.idm.colors.diff;
100 int r = (block.R + block.dR);
101 int g = (block.G + block.dG);
102 int b = (block.B + block.dB);
103 if (r < 0 || r > 31)
104 {
105 decodeTBlock(dest, x, y, w, h, destRowPitch, alphaValues,
106 nonOpaquePunchThroughAlpha);
107 }
108 else if (g < 0 || g > 31)
109 {
110 decodeHBlock(dest, x, y, w, h, destRowPitch, alphaValues,
111 nonOpaquePunchThroughAlpha);
112 }
113 else if (b < 0 || b > 31)
114 {
115 decodePlanarBlock(dest, x, y, w, h, destRowPitch, alphaValues);
116 }
117 else
118 {
119 decodeDifferentialBlock(dest, x, y, w, h, destRowPitch, alphaValues,
120 nonOpaquePunchThroughAlpha);
121 }
122 }
123 else
124 {
125 decodeIndividualBlock(dest, x, y, w, h, destRowPitch, alphaValues,
126 nonOpaquePunchThroughAlpha);
127 }
128 }
129
130 // Transcodes RGB block to BC1
transcodeAsBC1angle::__anond465fb730111::ETC2Block131 void transcodeAsBC1(uint8_t *dest,
132 size_t x,
133 size_t y,
134 size_t w,
135 size_t h,
136 const uint8_t alphaValues[4][4],
137 bool punchThroughAlpha) const
138 {
139 bool opaqueBit = u.idht.mode.idm.diffbit;
140 bool nonOpaquePunchThroughAlpha = punchThroughAlpha && !opaqueBit;
141 // Select mode
142 if (u.idht.mode.idm.diffbit || punchThroughAlpha)
143 {
144 const auto &block = u.idht.mode.idm.colors.diff;
145 int r = (block.R + block.dR);
146 int g = (block.G + block.dG);
147 int b = (block.B + block.dB);
148 if (r < 0 || r > 31)
149 {
150 transcodeTBlockToBC1(dest, x, y, w, h, alphaValues, nonOpaquePunchThroughAlpha);
151 }
152 else if (g < 0 || g > 31)
153 {
154 transcodeHBlockToBC1(dest, x, y, w, h, alphaValues, nonOpaquePunchThroughAlpha);
155 }
156 else if (b < 0 || b > 31)
157 {
158 transcodePlanarBlockToBC1(dest, x, y, w, h, alphaValues);
159 }
160 else
161 {
162 transcodeDifferentialBlockToBC1(dest, x, y, w, h, alphaValues,
163 nonOpaquePunchThroughAlpha);
164 }
165 }
166 else
167 {
168 transcodeIndividualBlockToBC1(dest, x, y, w, h, alphaValues,
169 nonOpaquePunchThroughAlpha);
170 }
171 }
172
173 private:
174 union {
175 // Individual, differential, H and T modes
176 struct
177 {
178 union {
179 // Individual and differential modes
180 struct
181 {
182 union {
183 struct // Individual colors
184 {
185 unsigned char R2 : 4;
186 unsigned char R1 : 4;
187 unsigned char G2 : 4;
188 unsigned char G1 : 4;
189 unsigned char B2 : 4;
190 unsigned char B1 : 4;
191 } indiv;
192 struct // Differential colors
193 {
194 signed char dR : 3;
195 unsigned char R : 5;
196 signed char dG : 3;
197 unsigned char G : 5;
198 signed char dB : 3;
199 unsigned char B : 5;
200 } diff;
201 } colors;
202 bool flipbit : 1;
203 bool diffbit : 1;
204 unsigned char cw2 : 3;
205 unsigned char cw1 : 3;
206 } idm;
207 // T mode
208 struct
209 {
210 // Byte 1
211 unsigned char TR1b : 2;
212 unsigned char TdummyB : 1;
213 unsigned char TR1a : 2;
214 unsigned char TdummyA : 3;
215 // Byte 2
216 unsigned char TB1 : 4;
217 unsigned char TG1 : 4;
218 // Byte 3
219 unsigned char TG2 : 4;
220 unsigned char TR2 : 4;
221 // Byte 4
222 unsigned char Tdb : 1;
223 bool Tflipbit : 1;
224 unsigned char Tda : 2;
225 unsigned char TB2 : 4;
226 } tm;
227 // H mode
228 struct
229 {
230 // Byte 1
231 unsigned char HG1a : 3;
232 unsigned char HR1 : 4;
233 unsigned char HdummyA : 1;
234 // Byte 2
235 unsigned char HB1b : 2;
236 unsigned char HdummyC : 1;
237 unsigned char HB1a : 1;
238 unsigned char HG1b : 1;
239 unsigned char HdummyB : 3;
240 // Byte 3
241 unsigned char HG2a : 3;
242 unsigned char HR2 : 4;
243 unsigned char HB1c : 1;
244 // Byte 4
245 unsigned char Hdb : 1;
246 bool Hflipbit : 1;
247 unsigned char Hda : 1;
248 unsigned char HB2 : 4;
249 unsigned char HG2b : 1;
250 } hm;
251 } mode;
252 unsigned char pixelIndexMSB[2];
253 unsigned char pixelIndexLSB[2];
254 } idht;
255 // planar mode
256 struct
257 {
258 // Byte 1
259 unsigned char GO1 : 1;
260 unsigned char RO : 6;
261 unsigned char PdummyA : 1;
262 // Byte 2
263 unsigned char BO1 : 1;
264 unsigned char GO2 : 6;
265 unsigned char PdummyB : 1;
266 // Byte 3
267 unsigned char BO3a : 2;
268 unsigned char PdummyD : 1;
269 unsigned char BO2 : 2;
270 unsigned char PdummyC : 3;
271 // Byte 4
272 unsigned char RH2 : 1;
273 bool Pflipbit : 1;
274 unsigned char RH1 : 5;
275 unsigned char BO3b : 1;
276 // Byte 5
277 unsigned char BHa : 1;
278 unsigned char GH : 7;
279 // Byte 6
280 unsigned char RVa : 3;
281 unsigned char BHb : 5;
282 // Byte 7
283 unsigned char GVa : 5;
284 unsigned char RVb : 3;
285 // Byte 8
286 unsigned char BV : 6;
287 unsigned char GVb : 2;
288 } pblk;
289 // Single channel block
290 struct
291 {
292 union {
293 unsigned char us;
294 signed char s;
295 } base_codeword;
296 unsigned char table_index : 4;
297 unsigned char multiplier : 4;
298 unsigned char mc1 : 2;
299 unsigned char mb : 3;
300 unsigned char ma : 3;
301 unsigned char mf1 : 1;
302 unsigned char me : 3;
303 unsigned char md : 3;
304 unsigned char mc2 : 1;
305 unsigned char mh : 3;
306 unsigned char mg : 3;
307 unsigned char mf2 : 2;
308 unsigned char mk1 : 2;
309 unsigned char mj : 3;
310 unsigned char mi : 3;
311 unsigned char mn1 : 1;
312 unsigned char mm : 3;
313 unsigned char ml : 3;
314 unsigned char mk2 : 1;
315 unsigned char mp : 3;
316 unsigned char mo : 3;
317 unsigned char mn2 : 2;
318 } scblk;
319 } u;
320
clampByteangle::__anond465fb730111::ETC2Block321 static unsigned char clampByte(int value)
322 {
323 return static_cast<unsigned char>(gl::clamp(value, 0, 255));
324 }
325
clampSByteangle::__anond465fb730111::ETC2Block326 static signed char clampSByte(int value)
327 {
328 return static_cast<signed char>(gl::clamp(value, -128, 127));
329 }
330
createRGBAangle::__anond465fb730111::ETC2Block331 static R8G8B8A8 createRGBA(int red, int green, int blue, int alpha)
332 {
333 R8G8B8A8 rgba;
334 rgba.R = clampByte(red);
335 rgba.G = clampByte(green);
336 rgba.B = clampByte(blue);
337 rgba.A = clampByte(alpha);
338 return rgba;
339 }
340
createRGBAangle::__anond465fb730111::ETC2Block341 static R8G8B8A8 createRGBA(int red, int green, int blue)
342 {
343 return createRGBA(red, green, blue, 255);
344 }
345
extend_4to8bitsangle::__anond465fb730111::ETC2Block346 static int extend_4to8bits(int x) { return (x << 4) | x; }
extend_5to8bitsangle::__anond465fb730111::ETC2Block347 static int extend_5to8bits(int x) { return (x << 3) | (x >> 2); }
extend_6to8bitsangle::__anond465fb730111::ETC2Block348 static int extend_6to8bits(int x) { return (x << 2) | (x >> 4); }
extend_7to8bitsangle::__anond465fb730111::ETC2Block349 static int extend_7to8bits(int x) { return (x << 1) | (x >> 6); }
350
decodeIndividualBlockangle::__anond465fb730111::ETC2Block351 void decodeIndividualBlock(uint8_t *dest,
352 size_t x,
353 size_t y,
354 size_t w,
355 size_t h,
356 size_t destRowPitch,
357 const uint8_t alphaValues[4][4],
358 bool nonOpaquePunchThroughAlpha) const
359 {
360 const auto &block = u.idht.mode.idm.colors.indiv;
361 int r1 = extend_4to8bits(block.R1);
362 int g1 = extend_4to8bits(block.G1);
363 int b1 = extend_4to8bits(block.B1);
364 int r2 = extend_4to8bits(block.R2);
365 int g2 = extend_4to8bits(block.G2);
366 int b2 = extend_4to8bits(block.B2);
367 decodeIndividualOrDifferentialBlock(dest, x, y, w, h, destRowPitch, r1, g1, b1, r2, g2, b2,
368 alphaValues, nonOpaquePunchThroughAlpha);
369 }
370
decodeDifferentialBlockangle::__anond465fb730111::ETC2Block371 void decodeDifferentialBlock(uint8_t *dest,
372 size_t x,
373 size_t y,
374 size_t w,
375 size_t h,
376 size_t destRowPitch,
377 const uint8_t alphaValues[4][4],
378 bool nonOpaquePunchThroughAlpha) const
379 {
380 const auto &block = u.idht.mode.idm.colors.diff;
381 int b1 = extend_5to8bits(block.B);
382 int g1 = extend_5to8bits(block.G);
383 int r1 = extend_5to8bits(block.R);
384 int r2 = extend_5to8bits(block.R + block.dR);
385 int g2 = extend_5to8bits(block.G + block.dG);
386 int b2 = extend_5to8bits(block.B + block.dB);
387 decodeIndividualOrDifferentialBlock(dest, x, y, w, h, destRowPitch, r1, g1, b1, r2, g2, b2,
388 alphaValues, nonOpaquePunchThroughAlpha);
389 }
390
decodeIndividualOrDifferentialBlockangle::__anond465fb730111::ETC2Block391 void decodeIndividualOrDifferentialBlock(uint8_t *dest,
392 size_t x,
393 size_t y,
394 size_t w,
395 size_t h,
396 size_t destRowPitch,
397 int r1,
398 int g1,
399 int b1,
400 int r2,
401 int g2,
402 int b2,
403 const uint8_t alphaValues[4][4],
404 bool nonOpaquePunchThroughAlpha) const
405 {
406 const IntensityModifier *intensityModifier =
407 nonOpaquePunchThroughAlpha ? intensityModifierNonOpaque : intensityModifierDefault;
408
409 R8G8B8A8 subblockColors0[4];
410 R8G8B8A8 subblockColors1[4];
411 for (size_t modifierIdx = 0; modifierIdx < 4; modifierIdx++)
412 {
413 const int i1 = intensityModifier[u.idht.mode.idm.cw1][modifierIdx];
414 subblockColors0[modifierIdx] = createRGBA(r1 + i1, g1 + i1, b1 + i1);
415
416 const int i2 = intensityModifier[u.idht.mode.idm.cw2][modifierIdx];
417 subblockColors1[modifierIdx] = createRGBA(r2 + i2, g2 + i2, b2 + i2);
418 }
419
420 if (u.idht.mode.idm.flipbit)
421 {
422 uint8_t *curPixel = dest;
423 for (size_t j = 0; j < 2 && (y + j) < h; j++)
424 {
425 R8G8B8A8 *row = reinterpret_cast<R8G8B8A8 *>(curPixel);
426 for (size_t i = 0; i < 4 && (x + i) < w; i++)
427 {
428 row[i] = subblockColors0[getIndex(i, j)];
429 row[i].A = alphaValues[j][i];
430 }
431 curPixel += destRowPitch;
432 }
433 for (size_t j = 2; j < 4 && (y + j) < h; j++)
434 {
435 R8G8B8A8 *row = reinterpret_cast<R8G8B8A8 *>(curPixel);
436 for (size_t i = 0; i < 4 && (x + i) < w; i++)
437 {
438 row[i] = subblockColors1[getIndex(i, j)];
439 row[i].A = alphaValues[j][i];
440 }
441 curPixel += destRowPitch;
442 }
443 }
444 else
445 {
446 uint8_t *curPixel = dest;
447 for (size_t j = 0; j < 4 && (y + j) < h; j++)
448 {
449 R8G8B8A8 *row = reinterpret_cast<R8G8B8A8 *>(curPixel);
450 for (size_t i = 0; i < 2 && (x + i) < w; i++)
451 {
452 row[i] = subblockColors0[getIndex(i, j)];
453 row[i].A = alphaValues[j][i];
454 }
455 for (size_t i = 2; i < 4 && (x + i) < w; i++)
456 {
457 row[i] = subblockColors1[getIndex(i, j)];
458 row[i].A = alphaValues[j][i];
459 }
460 curPixel += destRowPitch;
461 }
462 }
463 if (nonOpaquePunchThroughAlpha)
464 {
465 decodePunchThroughAlphaBlock(dest, x, y, w, h, destRowPitch);
466 }
467 }
468
decodeTBlockangle::__anond465fb730111::ETC2Block469 void decodeTBlock(uint8_t *dest,
470 size_t x,
471 size_t y,
472 size_t w,
473 size_t h,
474 size_t destRowPitch,
475 const uint8_t alphaValues[4][4],
476 bool nonOpaquePunchThroughAlpha) const
477 {
478 // Table C.8, distance index for T and H modes
479 const auto &block = u.idht.mode.tm;
480
481 int r1 = extend_4to8bits(block.TR1a << 2 | block.TR1b);
482 int g1 = extend_4to8bits(block.TG1);
483 int b1 = extend_4to8bits(block.TB1);
484 int r2 = extend_4to8bits(block.TR2);
485 int g2 = extend_4to8bits(block.TG2);
486 int b2 = extend_4to8bits(block.TB2);
487
488 static int distance[8] = {3, 6, 11, 16, 23, 32, 41, 64};
489 const int d = distance[block.Tda << 1 | block.Tdb];
490
491 const R8G8B8A8 paintColors[4] = {
492 createRGBA(r1, g1, b1), createRGBA(r2 + d, g2 + d, b2 + d), createRGBA(r2, g2, b2),
493 createRGBA(r2 - d, g2 - d, b2 - d),
494 };
495
496 uint8_t *curPixel = dest;
497 for (size_t j = 0; j < 4 && (y + j) < h; j++)
498 {
499 R8G8B8A8 *row = reinterpret_cast<R8G8B8A8 *>(curPixel);
500 for (size_t i = 0; i < 4 && (x + i) < w; i++)
501 {
502 row[i] = paintColors[getIndex(i, j)];
503 row[i].A = alphaValues[j][i];
504 }
505 curPixel += destRowPitch;
506 }
507
508 if (nonOpaquePunchThroughAlpha)
509 {
510 decodePunchThroughAlphaBlock(dest, x, y, w, h, destRowPitch);
511 }
512 }
513
decodeHBlockangle::__anond465fb730111::ETC2Block514 void decodeHBlock(uint8_t *dest,
515 size_t x,
516 size_t y,
517 size_t w,
518 size_t h,
519 size_t destRowPitch,
520 const uint8_t alphaValues[4][4],
521 bool nonOpaquePunchThroughAlpha) const
522 {
523 // Table C.8, distance index for T and H modes
524 const auto &block = u.idht.mode.hm;
525
526 int r1 = extend_4to8bits(block.HR1);
527 int g1 = extend_4to8bits(block.HG1a << 1 | block.HG1b);
528 int b1 = extend_4to8bits(block.HB1a << 3 | block.HB1b << 1 | block.HB1c);
529 int r2 = extend_4to8bits(block.HR2);
530 int g2 = extend_4to8bits(block.HG2a << 1 | block.HG2b);
531 int b2 = extend_4to8bits(block.HB2);
532
533 static const int distance[8] = {3, 6, 11, 16, 23, 32, 41, 64};
534 const int orderingTrickBit =
535 ((r1 << 16 | g1 << 8 | b1) >= (r2 << 16 | g2 << 8 | b2) ? 1 : 0);
536 const int d = distance[(block.Hda << 2) | (block.Hdb << 1) | orderingTrickBit];
537
538 const R8G8B8A8 paintColors[4] = {
539 createRGBA(r1 + d, g1 + d, b1 + d), createRGBA(r1 - d, g1 - d, b1 - d),
540 createRGBA(r2 + d, g2 + d, b2 + d), createRGBA(r2 - d, g2 - d, b2 - d),
541 };
542
543 uint8_t *curPixel = dest;
544 for (size_t j = 0; j < 4 && (y + j) < h; j++)
545 {
546 R8G8B8A8 *row = reinterpret_cast<R8G8B8A8 *>(curPixel);
547 for (size_t i = 0; i < 4 && (x + i) < w; i++)
548 {
549 row[i] = paintColors[getIndex(i, j)];
550 row[i].A = alphaValues[j][i];
551 }
552 curPixel += destRowPitch;
553 }
554
555 if (nonOpaquePunchThroughAlpha)
556 {
557 decodePunchThroughAlphaBlock(dest, x, y, w, h, destRowPitch);
558 }
559 }
560
decodePlanarBlockangle::__anond465fb730111::ETC2Block561 void decodePlanarBlock(uint8_t *dest,
562 size_t x,
563 size_t y,
564 size_t w,
565 size_t h,
566 size_t pitch,
567 const uint8_t alphaValues[4][4]) const
568 {
569 int ro = extend_6to8bits(u.pblk.RO);
570 int go = extend_7to8bits(u.pblk.GO1 << 6 | u.pblk.GO2);
571 int bo =
572 extend_6to8bits(u.pblk.BO1 << 5 | u.pblk.BO2 << 3 | u.pblk.BO3a << 1 | u.pblk.BO3b);
573 int rh = extend_6to8bits(u.pblk.RH1 << 1 | u.pblk.RH2);
574 int gh = extend_7to8bits(u.pblk.GH);
575 int bh = extend_6to8bits(u.pblk.BHa << 5 | u.pblk.BHb);
576 int rv = extend_6to8bits(u.pblk.RVa << 3 | u.pblk.RVb);
577 int gv = extend_7to8bits(u.pblk.GVa << 2 | u.pblk.GVb);
578 int bv = extend_6to8bits(u.pblk.BV);
579
580 uint8_t *curPixel = dest;
581 for (size_t j = 0; j < 4 && (y + j) < h; j++)
582 {
583 R8G8B8A8 *row = reinterpret_cast<R8G8B8A8 *>(curPixel);
584
585 int ry = static_cast<int>(j) * (rv - ro) + 2;
586 int gy = static_cast<int>(j) * (gv - go) + 2;
587 int by = static_cast<int>(j) * (bv - bo) + 2;
588 for (size_t i = 0; i < 4 && (x + i) < w; i++)
589 {
590 row[i] = createRGBA(((static_cast<int>(i) * (rh - ro) + ry) >> 2) + ro,
591 ((static_cast<int>(i) * (gh - go) + gy) >> 2) + go,
592 ((static_cast<int>(i) * (bh - bo) + by) >> 2) + bo,
593 alphaValues[j][i]);
594 }
595 curPixel += pitch;
596 }
597 }
598
599 // Index for individual, differential, H and T modes
getIndexangle::__anond465fb730111::ETC2Block600 size_t getIndex(size_t x, size_t y) const
601 {
602 size_t bitIndex = x * 4 + y;
603 size_t bitOffset = bitIndex & 7;
604 size_t lsb = (u.idht.pixelIndexLSB[1 - (bitIndex >> 3)] >> bitOffset) & 1;
605 size_t msb = (u.idht.pixelIndexMSB[1 - (bitIndex >> 3)] >> bitOffset) & 1;
606 return (msb << 1) | lsb;
607 }
608
decodePunchThroughAlphaBlockangle::__anond465fb730111::ETC2Block609 void decodePunchThroughAlphaBlock(uint8_t *dest,
610 size_t x,
611 size_t y,
612 size_t w,
613 size_t h,
614 size_t destRowPitch) const
615 {
616 uint8_t *curPixel = dest;
617 for (size_t j = 0; j < 4 && (y + j) < h; j++)
618 {
619 R8G8B8A8 *row = reinterpret_cast<R8G8B8A8 *>(curPixel);
620 for (size_t i = 0; i < 4 && (x + i) < w; i++)
621 {
622 if (getIndex(i, j) == 2) // msb == 1 && lsb == 0
623 {
624 row[i] = createRGBA(0, 0, 0, 0);
625 }
626 }
627 curPixel += destRowPitch;
628 }
629 }
630
RGB8ToRGB565angle::__anond465fb730111::ETC2Block631 uint16_t RGB8ToRGB565(const R8G8B8A8 &rgba) const
632 {
633 return (static_cast<uint16_t>(rgba.R >> 3) << 11) |
634 (static_cast<uint16_t>(rgba.G >> 2) << 5) |
635 (static_cast<uint16_t>(rgba.B >> 3) << 0);
636 }
637
matchBC1Bitsangle::__anond465fb730111::ETC2Block638 uint32_t matchBC1Bits(const int *pixelIndices,
639 const int *pixelIndexCounts,
640 const R8G8B8A8 *subblockColors,
641 size_t numColors,
642 const R8G8B8A8 &minColor,
643 const R8G8B8A8 &maxColor,
644 bool nonOpaquePunchThroughAlpha) const
645 {
646 // Project each pixel on the (maxColor, minColor) line to decide which
647 // BC1 code to assign to it.
648
649 uint8_t decodedColors[2][3] = {{maxColor.R, maxColor.G, maxColor.B},
650 {minColor.R, minColor.G, minColor.B}};
651
652 int direction[3];
653 for (int ch = 0; ch < 3; ch++)
654 {
655 direction[ch] = decodedColors[0][ch] - decodedColors[1][ch];
656 }
657
658 int stops[2];
659 for (int i = 0; i < 2; i++)
660 {
661 stops[i] = decodedColors[i][0] * direction[0] + decodedColors[i][1] * direction[1] +
662 decodedColors[i][2] * direction[2];
663 }
664
665 ASSERT(numColors <= kNumPixelsInBlock);
666
667 int encodedColors[kNumPixelsInBlock];
668 if (nonOpaquePunchThroughAlpha)
669 {
670 for (size_t i = 0; i < numColors; i++)
671 {
672 const int count = pixelIndexCounts[i];
673 if (count > 0)
674 {
675 // In non-opaque mode, 3 is for tranparent pixels.
676
677 if (0 == subblockColors[i].A)
678 {
679 encodedColors[i] = 3;
680 }
681 else
682 {
683 const R8G8B8A8 &pixel = subblockColors[i];
684 const int dot = pixel.R * direction[0] + pixel.G * direction[1] +
685 pixel.B * direction[2];
686 const int factor = gl::clamp(
687 static_cast<int>(
688 (static_cast<float>(dot - stops[1]) / (stops[0] - stops[1])) * 2 +
689 0.5f),
690 0, 2);
691 switch (factor)
692 {
693 case 0:
694 encodedColors[i] = 0;
695 break;
696 case 1:
697 encodedColors[i] = 2;
698 break;
699 case 2:
700 default:
701 encodedColors[i] = 1;
702 break;
703 }
704 }
705 }
706 }
707 }
708 else
709 {
710 for (size_t i = 0; i < numColors; i++)
711 {
712 const int count = pixelIndexCounts[i];
713 if (count > 0)
714 {
715 // In opaque mode, the code is from 0 to 3.
716
717 const R8G8B8A8 &pixel = subblockColors[i];
718 const int dot =
719 pixel.R * direction[0] + pixel.G * direction[1] + pixel.B * direction[2];
720 const int factor = gl::clamp(
721 static_cast<int>(
722 (static_cast<float>(dot - stops[1]) / (stops[0] - stops[1])) * 3 +
723 0.5f),
724 0, 3);
725 switch (factor)
726 {
727 case 0:
728 encodedColors[i] = 1;
729 break;
730 case 1:
731 encodedColors[i] = 3;
732 break;
733 case 2:
734 encodedColors[i] = 2;
735 break;
736 case 3:
737 default:
738 encodedColors[i] = 0;
739 break;
740 }
741 }
742 }
743 }
744
745 uint32_t bits = 0;
746 for (int i = kNumPixelsInBlock - 1; i >= 0; i--)
747 {
748 bits <<= 2;
749 bits |= encodedColors[pixelIndices[i]];
750 }
751
752 return bits;
753 }
754
packBC1angle::__anond465fb730111::ETC2Block755 void packBC1(void *bc1,
756 const int *pixelIndices,
757 const int *pixelIndexCounts,
758 const R8G8B8A8 *subblockColors,
759 size_t numColors,
760 int minColorIndex,
761 int maxColorIndex,
762 bool nonOpaquePunchThroughAlpha) const
763 {
764 const R8G8B8A8 &minColor = subblockColors[minColorIndex];
765 const R8G8B8A8 &maxColor = subblockColors[maxColorIndex];
766
767 uint32_t bits;
768 uint16_t max16 = RGB8ToRGB565(maxColor);
769 uint16_t min16 = RGB8ToRGB565(minColor);
770 if (max16 != min16)
771 {
772 // Find the best BC1 code for each pixel
773 bits = matchBC1Bits(pixelIndices, pixelIndexCounts, subblockColors, numColors, minColor,
774 maxColor, nonOpaquePunchThroughAlpha);
775 }
776 else
777 {
778 // Same colors, BC1 index 0 is the color in both opaque and transparent mode
779 bits = 0;
780 // BC1 index 3 is transparent
781 if (nonOpaquePunchThroughAlpha)
782 {
783 for (int i = 0; i < kNumPixelsInBlock; i++)
784 {
785 if (0 == subblockColors[pixelIndices[i]].A)
786 {
787 bits |= (3 << (i * 2));
788 }
789 }
790 }
791 }
792
793 if (max16 < min16)
794 {
795 std::swap(max16, min16);
796
797 uint32_t xorMask = 0;
798 if (nonOpaquePunchThroughAlpha)
799 {
800 // In transparent mode switching the colors is doing the
801 // following code swap: 0 <-> 1. 0xA selects the second bit of
802 // each code, bits >> 1 selects the first bit of the code when
803 // the seconds bit is set (case 2 and 3). We invert all the
804 // non-selected bits, that is the first bit when the code is
805 // 0 or 1.
806 xorMask = ~((bits >> 1) | 0xAAAAAAAA);
807 }
808 else
809 {
810 // In opaque mode switching the two colors is doing the
811 // following code swaps: 0 <-> 1 and 2 <-> 3. This is
812 // equivalent to flipping the first bit of each code
813 // (5 = 0b0101)
814 xorMask = 0x55555555;
815 }
816 bits ^= xorMask;
817 }
818
819 struct BC1Block
820 {
821 uint16_t color0;
822 uint16_t color1;
823 uint32_t bits;
824 };
825
826 // Encode the opaqueness in the order of the two BC1 colors
827 BC1Block *dest = reinterpret_cast<BC1Block *>(bc1);
828 if (nonOpaquePunchThroughAlpha)
829 {
830 dest->color0 = min16;
831 dest->color1 = max16;
832 }
833 else
834 {
835 dest->color0 = max16;
836 dest->color1 = min16;
837 }
838 dest->bits = bits;
839 }
840
transcodeIndividualBlockToBC1angle::__anond465fb730111::ETC2Block841 void transcodeIndividualBlockToBC1(uint8_t *dest,
842 size_t x,
843 size_t y,
844 size_t w,
845 size_t h,
846 const uint8_t alphaValues[4][4],
847 bool nonOpaquePunchThroughAlpha) const
848 {
849 const auto &block = u.idht.mode.idm.colors.indiv;
850 int r1 = extend_4to8bits(block.R1);
851 int g1 = extend_4to8bits(block.G1);
852 int b1 = extend_4to8bits(block.B1);
853 int r2 = extend_4to8bits(block.R2);
854 int g2 = extend_4to8bits(block.G2);
855 int b2 = extend_4to8bits(block.B2);
856 transcodeIndividualOrDifferentialBlockToBC1(dest, x, y, w, h, r1, g1, b1, r2, g2, b2,
857 alphaValues, nonOpaquePunchThroughAlpha);
858 }
859
transcodeDifferentialBlockToBC1angle::__anond465fb730111::ETC2Block860 void transcodeDifferentialBlockToBC1(uint8_t *dest,
861 size_t x,
862 size_t y,
863 size_t w,
864 size_t h,
865 const uint8_t alphaValues[4][4],
866 bool nonOpaquePunchThroughAlpha) const
867 {
868 const auto &block = u.idht.mode.idm.colors.diff;
869 int b1 = extend_5to8bits(block.B);
870 int g1 = extend_5to8bits(block.G);
871 int r1 = extend_5to8bits(block.R);
872 int r2 = extend_5to8bits(block.R + block.dR);
873 int g2 = extend_5to8bits(block.G + block.dG);
874 int b2 = extend_5to8bits(block.B + block.dB);
875 transcodeIndividualOrDifferentialBlockToBC1(dest, x, y, w, h, r1, g1, b1, r2, g2, b2,
876 alphaValues, nonOpaquePunchThroughAlpha);
877 }
878
extractPixelIndicesangle::__anond465fb730111::ETC2Block879 void extractPixelIndices(int *pixelIndices,
880 int *pixelIndicesCounts,
881 size_t x,
882 size_t y,
883 size_t w,
884 size_t h,
885 bool flipbit,
886 size_t subblockIdx) const
887 {
888 size_t dxBegin = 0;
889 size_t dxEnd = 4;
890 size_t dyBegin = subblockIdx * 2;
891 size_t dyEnd = dyBegin + 2;
892 if (!flipbit)
893 {
894 std::swap(dxBegin, dyBegin);
895 std::swap(dxEnd, dyEnd);
896 }
897
898 for (size_t j = dyBegin; j < dyEnd; j++)
899 {
900 int *row = &pixelIndices[j * 4];
901 for (size_t i = dxBegin; i < dxEnd; i++)
902 {
903 const size_t pixelIndex = subblockIdx * 4 + getIndex(i, j);
904 row[i] = static_cast<int>(pixelIndex);
905 pixelIndicesCounts[pixelIndex]++;
906 }
907 }
908 }
909
selectEndPointPCAangle::__anond465fb730111::ETC2Block910 void selectEndPointPCA(const int *pixelIndexCounts,
911 const R8G8B8A8 *subblockColors,
912 size_t numColors,
913 int *minColorIndex,
914 int *maxColorIndex) const
915 {
916 // determine color distribution
917 int mu[3], min[3], max[3];
918 for (int ch = 0; ch < 3; ch++)
919 {
920 int muv = 0;
921 int minv = 255;
922 int maxv = 0;
923 for (size_t i = 0; i < numColors; i++)
924 {
925 const int count = pixelIndexCounts[i];
926 if (count > 0)
927 {
928 const auto &pixel = subblockColors[i];
929 if (pixel.A > 0)
930 {
931 // Non-transparent pixels
932 muv += (&pixel.R)[ch] * count;
933 minv = std::min<int>(minv, (&pixel.R)[ch]);
934 maxv = std::max<int>(maxv, (&pixel.R)[ch]);
935 }
936 }
937 }
938
939 mu[ch] = (muv + kNumPixelsInBlock / 2) / kNumPixelsInBlock;
940 min[ch] = minv;
941 max[ch] = maxv;
942 }
943
944 // determine covariance matrix
945 int cov[6] = {0, 0, 0, 0, 0, 0};
946 for (size_t i = 0; i < numColors; i++)
947 {
948 const int count = pixelIndexCounts[i];
949 if (count > 0)
950 {
951 const auto &pixel = subblockColors[i];
952 if (pixel.A > 0)
953 {
954 int r = pixel.R - mu[0];
955 int g = pixel.G - mu[1];
956 int b = pixel.B - mu[2];
957
958 cov[0] += r * r * count;
959 cov[1] += r * g * count;
960 cov[2] += r * b * count;
961 cov[3] += g * g * count;
962 cov[4] += g * b * count;
963 cov[5] += b * b * count;
964 }
965 }
966 }
967
968 // Power iteration algorithm to get the eigenvalues and eigenvector
969
970 // Starts with diagonal vector
971 float vfr = static_cast<float>(max[0] - min[0]);
972 float vfg = static_cast<float>(max[1] - min[1]);
973 float vfb = static_cast<float>(max[2] - min[2]);
974 float eigenvalue;
975
976 static const size_t kPowerIterations = 4;
977 for (size_t i = 0; i < kPowerIterations; i++)
978 {
979 float r = vfr * cov[0] + vfg * cov[1] + vfb * cov[2];
980 float g = vfr * cov[1] + vfg * cov[3] + vfb * cov[4];
981 float b = vfr * cov[2] + vfg * cov[4] + vfb * cov[5];
982
983 vfr = r;
984 vfg = g;
985 vfb = b;
986
987 eigenvalue = sqrt(r * r + g * g + b * b);
988 if (eigenvalue > 0)
989 {
990 float invNorm = 1.0f / eigenvalue;
991 vfr *= invNorm;
992 vfg *= invNorm;
993 vfb *= invNorm;
994 }
995 }
996
997 int vr, vg, vb;
998
999 static const float kDefaultLuminanceThreshold = 4.0f * 255;
1000 static const float kQuantizeRange = 512.0f;
1001 if (eigenvalue < kDefaultLuminanceThreshold) // too small, default to luminance
1002 {
1003 // Luminance weights defined by ITU-R Recommendation BT.601, scaled by 1000
1004 vr = 299;
1005 vg = 587;
1006 vb = 114;
1007 }
1008 else
1009 {
1010 // From the eigenvalue and eigenvector, choose the axis to project
1011 // colors on. When projecting colors we want to do integer computations
1012 // for speed, so we normalize the eigenvector to the [0, 512] range.
1013 float magn = std::max(std::max(std::abs(vfr), std::abs(vfg)), std::abs(vfb));
1014 magn = kQuantizeRange / magn;
1015 vr = static_cast<int>(vfr * magn);
1016 vg = static_cast<int>(vfg * magn);
1017 vb = static_cast<int>(vfb * magn);
1018 }
1019
1020 // Pick colors at extreme points
1021 int minD = INT_MAX;
1022 int maxD = 0;
1023 size_t minIndex = 0;
1024 size_t maxIndex = 0;
1025 for (size_t i = 0; i < numColors; i++)
1026 {
1027 const int count = pixelIndexCounts[i];
1028 if (count > 0)
1029 {
1030 const auto &pixel = subblockColors[i];
1031 if (pixel.A > 0)
1032 {
1033 int dot = pixel.R * vr + pixel.G * vg + pixel.B * vb;
1034 if (dot < minD)
1035 {
1036 minD = dot;
1037 minIndex = i;
1038 }
1039 if (dot > maxD)
1040 {
1041 maxD = dot;
1042 maxIndex = i;
1043 }
1044 }
1045 }
1046 }
1047
1048 *minColorIndex = static_cast<int>(minIndex);
1049 *maxColorIndex = static_cast<int>(maxIndex);
1050 }
1051
transcodeIndividualOrDifferentialBlockToBC1angle::__anond465fb730111::ETC2Block1052 void transcodeIndividualOrDifferentialBlockToBC1(uint8_t *dest,
1053 size_t x,
1054 size_t y,
1055 size_t w,
1056 size_t h,
1057 int r1,
1058 int g1,
1059 int b1,
1060 int r2,
1061 int g2,
1062 int b2,
1063 const uint8_t alphaValues[4][4],
1064 bool nonOpaquePunchThroughAlpha) const
1065 {
1066 // A BC1 block has 2 endpoints, pixels is encoded as linear
1067 // interpolations of them. A ETC1/ETC2 individual or differential block
1068 // has 2 subblocks. Each subblock has one color and a modifier. We
1069 // select axis by principal component analysis (PCA) to use as
1070 // our two BC1 endpoints and then map pixels to BC1 by projecting on the
1071 // line between the two endpoints and choosing the right fraction.
1072
1073 // The goal of this algorithm is make it faster than decode ETC to RGBs
1074 // and then encode to BC. To achieve this, we only extract subblock
1075 // colors, pixel indices, and counts of each pixel indices from ETC.
1076 // With those information, we can only encode used subblock colors
1077 // to BC1, and copy the bits to the right pixels.
1078 // Fully decode and encode need to process 16 RGBA pixels. With this
1079 // algorithm, it's 8 pixels at maximum for a individual or
1080 // differential block. Saves us bandwidth and computations.
1081
1082 static const size_t kNumColors = 8;
1083
1084 const IntensityModifier *intensityModifier =
1085 nonOpaquePunchThroughAlpha ? intensityModifierNonOpaque : intensityModifierDefault;
1086
1087 // Compute the colors that pixels can have in each subblock both for
1088 // the decoding of the RGBA data and BC1 encoding
1089 R8G8B8A8 subblockColors[kNumColors];
1090 for (size_t modifierIdx = 0; modifierIdx < 4; modifierIdx++)
1091 {
1092 if (nonOpaquePunchThroughAlpha && (modifierIdx == 2))
1093 {
1094 // In ETC opaque punch through formats, individual and
1095 // differential blocks take index 2 as transparent pixel.
1096 // Thus we don't need to compute its color, just assign it
1097 // as black.
1098 subblockColors[modifierIdx] = createRGBA(0, 0, 0, 0);
1099 subblockColors[4 + modifierIdx] = createRGBA(0, 0, 0, 0);
1100 }
1101 else
1102 {
1103 const int i1 = intensityModifier[u.idht.mode.idm.cw1][modifierIdx];
1104 subblockColors[modifierIdx] = createRGBA(r1 + i1, g1 + i1, b1 + i1);
1105
1106 const int i2 = intensityModifier[u.idht.mode.idm.cw2][modifierIdx];
1107 subblockColors[4 + modifierIdx] = createRGBA(r2 + i2, g2 + i2, b2 + i2);
1108 }
1109 }
1110
1111 int pixelIndices[kNumPixelsInBlock];
1112 int pixelIndexCounts[kNumColors] = {0};
1113 // Extract pixel indices from a ETC block.
1114 for (size_t blockIdx = 0; blockIdx < 2; blockIdx++)
1115 {
1116 extractPixelIndices(pixelIndices, pixelIndexCounts, x, y, w, h, u.idht.mode.idm.flipbit,
1117 blockIdx);
1118 }
1119
1120 int minColorIndex, maxColorIndex;
1121 selectEndPointPCA(pixelIndexCounts, subblockColors, kNumColors, &minColorIndex,
1122 &maxColorIndex);
1123
1124 packBC1(dest, pixelIndices, pixelIndexCounts, subblockColors, kNumColors, minColorIndex,
1125 maxColorIndex, nonOpaquePunchThroughAlpha);
1126 }
1127
transcodeTBlockToBC1angle::__anond465fb730111::ETC2Block1128 void transcodeTBlockToBC1(uint8_t *dest,
1129 size_t x,
1130 size_t y,
1131 size_t w,
1132 size_t h,
1133 const uint8_t alphaValues[4][4],
1134 bool nonOpaquePunchThroughAlpha) const
1135 {
1136 static const size_t kNumColors = 4;
1137
1138 // Table C.8, distance index for T and H modes
1139 const auto &block = u.idht.mode.tm;
1140
1141 int r1 = extend_4to8bits(block.TR1a << 2 | block.TR1b);
1142 int g1 = extend_4to8bits(block.TG1);
1143 int b1 = extend_4to8bits(block.TB1);
1144 int r2 = extend_4to8bits(block.TR2);
1145 int g2 = extend_4to8bits(block.TG2);
1146 int b2 = extend_4to8bits(block.TB2);
1147
1148 static int distance[8] = {3, 6, 11, 16, 23, 32, 41, 64};
1149 const int d = distance[block.Tda << 1 | block.Tdb];
1150
1151 // In ETC opaque punch through formats, index == 2 means transparent pixel.
1152 // Thus we don't need to compute its color, just assign it as black.
1153 const R8G8B8A8 paintColors[kNumColors] = {
1154 createRGBA(r1, g1, b1), createRGBA(r2 + d, g2 + d, b2 + d),
1155 nonOpaquePunchThroughAlpha ? createRGBA(0, 0, 0, 0) : createRGBA(r2, g2, b2),
1156 createRGBA(r2 - d, g2 - d, b2 - d),
1157 };
1158
1159 int pixelIndices[kNumPixelsInBlock];
1160 int pixelIndexCounts[kNumColors] = {0};
1161 for (size_t j = 0; j < 4; j++)
1162 {
1163 int *row = &pixelIndices[j * 4];
1164 for (size_t i = 0; i < 4; i++)
1165 {
1166 const size_t pixelIndex = getIndex(i, j);
1167 row[i] = static_cast<int>(pixelIndex);
1168 pixelIndexCounts[pixelIndex]++;
1169 }
1170 }
1171
1172 int minColorIndex, maxColorIndex;
1173 selectEndPointPCA(pixelIndexCounts, paintColors, kNumColors, &minColorIndex,
1174 &maxColorIndex);
1175
1176 packBC1(dest, pixelIndices, pixelIndexCounts, paintColors, kNumColors, minColorIndex,
1177 maxColorIndex, nonOpaquePunchThroughAlpha);
1178 }
1179
transcodeHBlockToBC1angle::__anond465fb730111::ETC2Block1180 void transcodeHBlockToBC1(uint8_t *dest,
1181 size_t x,
1182 size_t y,
1183 size_t w,
1184 size_t h,
1185 const uint8_t alphaValues[4][4],
1186 bool nonOpaquePunchThroughAlpha) const
1187 {
1188 static const size_t kNumColors = 4;
1189
1190 // Table C.8, distance index for T and H modes
1191 const auto &block = u.idht.mode.hm;
1192
1193 int r1 = extend_4to8bits(block.HR1);
1194 int g1 = extend_4to8bits(block.HG1a << 1 | block.HG1b);
1195 int b1 = extend_4to8bits(block.HB1a << 3 | block.HB1b << 1 | block.HB1c);
1196 int r2 = extend_4to8bits(block.HR2);
1197 int g2 = extend_4to8bits(block.HG2a << 1 | block.HG2b);
1198 int b2 = extend_4to8bits(block.HB2);
1199
1200 static const int distance[8] = {3, 6, 11, 16, 23, 32, 41, 64};
1201 const int orderingTrickBit =
1202 ((r1 << 16 | g1 << 8 | b1) >= (r2 << 16 | g2 << 8 | b2) ? 1 : 0);
1203 const int d = distance[(block.Hda << 2) | (block.Hdb << 1) | orderingTrickBit];
1204
1205 // In ETC opaque punch through formats, index == 2 means transparent pixel.
1206 // Thus we don't need to compute its color, just assign it as black.
1207 const R8G8B8A8 paintColors[kNumColors] = {
1208 createRGBA(r1 + d, g1 + d, b1 + d), createRGBA(r1 - d, g1 - d, b1 - d),
1209 nonOpaquePunchThroughAlpha ? createRGBA(0, 0, 0, 0)
1210 : createRGBA(r2 + d, g2 + d, b2 + d),
1211 createRGBA(r2 - d, g2 - d, b2 - d),
1212 };
1213
1214 int pixelIndices[kNumPixelsInBlock];
1215 int pixelIndexCounts[kNumColors] = {0};
1216 for (size_t j = 0; j < 4; j++)
1217 {
1218 int *row = &pixelIndices[j * 4];
1219 for (size_t i = 0; i < 4; i++)
1220 {
1221 const size_t pixelIndex = getIndex(i, j);
1222 row[i] = static_cast<int>(pixelIndex);
1223 pixelIndexCounts[pixelIndex]++;
1224 }
1225 }
1226
1227 int minColorIndex, maxColorIndex;
1228 selectEndPointPCA(pixelIndexCounts, paintColors, kNumColors, &minColorIndex,
1229 &maxColorIndex);
1230
1231 packBC1(dest, pixelIndices, pixelIndexCounts, paintColors, kNumColors, minColorIndex,
1232 maxColorIndex, nonOpaquePunchThroughAlpha);
1233 }
1234
transcodePlanarBlockToBC1angle::__anond465fb730111::ETC2Block1235 void transcodePlanarBlockToBC1(uint8_t *dest,
1236 size_t x,
1237 size_t y,
1238 size_t w,
1239 size_t h,
1240 const uint8_t alphaValues[4][4]) const
1241 {
1242 static const size_t kNumColors = kNumPixelsInBlock;
1243
1244 R8G8B8A8 rgbaBlock[kNumColors];
1245 decodePlanarBlock(reinterpret_cast<uint8_t *>(rgbaBlock), x, y, w, h, sizeof(R8G8B8A8) * 4,
1246 alphaValues);
1247
1248 // Planar block doesn't have a color table, fill indices as full
1249 int pixelIndices[kNumPixelsInBlock] = {0, 1, 2, 3, 4, 5, 6, 7,
1250 8, 9, 10, 11, 12, 13, 14, 15};
1251 int pixelIndexCounts[kNumColors] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
1252
1253 int minColorIndex, maxColorIndex;
1254 selectEndPointPCA(pixelIndexCounts, rgbaBlock, kNumColors, &minColorIndex, &maxColorIndex);
1255
1256 packBC1(dest, pixelIndices, pixelIndexCounts, rgbaBlock, kNumColors, minColorIndex,
1257 maxColorIndex, false);
1258 }
1259
1260 // Single channel utility functions
getSingleChannelangle::__anond465fb730111::ETC2Block1261 int getSingleChannel(size_t x, size_t y, bool isSigned) const
1262 {
1263 int codeword = isSigned ? u.scblk.base_codeword.s : u.scblk.base_codeword.us;
1264 return codeword + getSingleChannelModifier(x, y) * u.scblk.multiplier;
1265 }
1266
getSingleChannelIndexangle::__anond465fb730111::ETC2Block1267 int getSingleChannelIndex(size_t x, size_t y) const
1268 {
1269 ASSERT(x < 4 && y < 4);
1270
1271 // clang-format off
1272 switch (x * 4 + y)
1273 {
1274 case 0: return u.scblk.ma;
1275 case 1: return u.scblk.mb;
1276 case 2: return u.scblk.mc1 << 1 | u.scblk.mc2;
1277 case 3: return u.scblk.md;
1278 case 4: return u.scblk.me;
1279 case 5: return u.scblk.mf1 << 2 | u.scblk.mf2;
1280 case 6: return u.scblk.mg;
1281 case 7: return u.scblk.mh;
1282 case 8: return u.scblk.mi;
1283 case 9: return u.scblk.mj;
1284 case 10: return u.scblk.mk1 << 1 | u.scblk.mk2;
1285 case 11: return u.scblk.ml;
1286 case 12: return u.scblk.mm;
1287 case 13: return u.scblk.mn1 << 2 | u.scblk.mn2;
1288 case 14: return u.scblk.mo;
1289 case 15: return u.scblk.mp;
1290 default: UNREACHABLE(); return 0;
1291 }
1292 // clang-format on
1293 }
1294
getSingleChannelModifierangle::__anond465fb730111::ETC2Block1295 int getSingleChannelModifier(size_t x, size_t y) const
1296 {
1297 // clang-format off
1298 static const int modifierTable[16][8] =
1299 {
1300 { -3, -6, -9, -15, 2, 5, 8, 14 },
1301 { -3, -7, -10, -13, 2, 6, 9, 12 },
1302 { -2, -5, -8, -13, 1, 4, 7, 12 },
1303 { -2, -4, -6, -13, 1, 3, 5, 12 },
1304 { -3, -6, -8, -12, 2, 5, 7, 11 },
1305 { -3, -7, -9, -11, 2, 6, 8, 10 },
1306 { -4, -7, -8, -11, 3, 6, 7, 10 },
1307 { -3, -5, -8, -11, 2, 4, 7, 10 },
1308 { -2, -6, -8, -10, 1, 5, 7, 9 },
1309 { -2, -5, -8, -10, 1, 4, 7, 9 },
1310 { -2, -4, -8, -10, 1, 3, 7, 9 },
1311 { -2, -5, -7, -10, 1, 4, 6, 9 },
1312 { -3, -4, -7, -10, 2, 3, 6, 9 },
1313 { -1, -2, -3, -10, 0, 1, 2, 9 },
1314 { -4, -6, -8, -9, 3, 5, 7, 8 },
1315 { -3, -5, -7, -9, 2, 4, 6, 8 }
1316 };
1317 // clang-format on
1318
1319 return modifierTable[u.scblk.table_index][getSingleChannelIndex(x, y)];
1320 }
1321 };
1322
1323 // clang-format off
1324 static const uint8_t DefaultETCAlphaValues[4][4] =
1325 {
1326 { 255, 255, 255, 255 },
1327 { 255, 255, 255, 255 },
1328 { 255, 255, 255, 255 },
1329 { 255, 255, 255, 255 },
1330 };
1331 // clang-format on
1332
LoadR11EACToR8(size_t width,size_t height,size_t depth,const uint8_t * input,size_t inputRowPitch,size_t inputDepthPitch,uint8_t * output,size_t outputRowPitch,size_t outputDepthPitch,bool isSigned)1333 void LoadR11EACToR8(size_t width,
1334 size_t height,
1335 size_t depth,
1336 const uint8_t *input,
1337 size_t inputRowPitch,
1338 size_t inputDepthPitch,
1339 uint8_t *output,
1340 size_t outputRowPitch,
1341 size_t outputDepthPitch,
1342 bool isSigned)
1343 {
1344 for (size_t z = 0; z < depth; z++)
1345 {
1346 for (size_t y = 0; y < height; y += 4)
1347 {
1348 const ETC2Block *sourceRow =
1349 priv::OffsetDataPointer<ETC2Block>(input, y / 4, z, inputRowPitch, inputDepthPitch);
1350 uint8_t *destRow =
1351 priv::OffsetDataPointer<uint8_t>(output, y, z, outputRowPitch, outputDepthPitch);
1352
1353 for (size_t x = 0; x < width; x += 4)
1354 {
1355 const ETC2Block *sourceBlock = sourceRow + (x / 4);
1356 uint8_t *destPixels = destRow + x;
1357
1358 sourceBlock->decodeAsSingleChannel(destPixels, x, y, width, height, 1,
1359 outputRowPitch, isSigned);
1360 }
1361 }
1362 }
1363 }
1364
LoadRG11EACToRG8(size_t width,size_t height,size_t depth,const uint8_t * input,size_t inputRowPitch,size_t inputDepthPitch,uint8_t * output,size_t outputRowPitch,size_t outputDepthPitch,bool isSigned)1365 void LoadRG11EACToRG8(size_t width,
1366 size_t height,
1367 size_t depth,
1368 const uint8_t *input,
1369 size_t inputRowPitch,
1370 size_t inputDepthPitch,
1371 uint8_t *output,
1372 size_t outputRowPitch,
1373 size_t outputDepthPitch,
1374 bool isSigned)
1375 {
1376 for (size_t z = 0; z < depth; z++)
1377 {
1378 for (size_t y = 0; y < height; y += 4)
1379 {
1380 const ETC2Block *sourceRow =
1381 priv::OffsetDataPointer<ETC2Block>(input, y / 4, z, inputRowPitch, inputDepthPitch);
1382 uint8_t *destRow =
1383 priv::OffsetDataPointer<uint8_t>(output, y, z, outputRowPitch, outputDepthPitch);
1384
1385 for (size_t x = 0; x < width; x += 4)
1386 {
1387 uint8_t *destPixelsRed = destRow + (x * 2);
1388 const ETC2Block *sourceBlockRed = sourceRow + (x / 2);
1389 sourceBlockRed->decodeAsSingleChannel(destPixelsRed, x, y, width, height, 2,
1390 outputRowPitch, isSigned);
1391
1392 uint8_t *destPixelsGreen = destPixelsRed + 1;
1393 const ETC2Block *sourceBlockGreen = sourceBlockRed + 1;
1394 sourceBlockGreen->decodeAsSingleChannel(destPixelsGreen, x, y, width, height, 2,
1395 outputRowPitch, isSigned);
1396 }
1397 }
1398 }
1399 }
1400
LoadETC2RGB8ToRGBA8(size_t width,size_t height,size_t depth,const uint8_t * input,size_t inputRowPitch,size_t inputDepthPitch,uint8_t * output,size_t outputRowPitch,size_t outputDepthPitch,bool punchthroughAlpha)1401 void LoadETC2RGB8ToRGBA8(size_t width,
1402 size_t height,
1403 size_t depth,
1404 const uint8_t *input,
1405 size_t inputRowPitch,
1406 size_t inputDepthPitch,
1407 uint8_t *output,
1408 size_t outputRowPitch,
1409 size_t outputDepthPitch,
1410 bool punchthroughAlpha)
1411 {
1412 for (size_t z = 0; z < depth; z++)
1413 {
1414 for (size_t y = 0; y < height; y += 4)
1415 {
1416 const ETC2Block *sourceRow =
1417 priv::OffsetDataPointer<ETC2Block>(input, y / 4, z, inputRowPitch, inputDepthPitch);
1418 uint8_t *destRow =
1419 priv::OffsetDataPointer<uint8_t>(output, y, z, outputRowPitch, outputDepthPitch);
1420
1421 for (size_t x = 0; x < width; x += 4)
1422 {
1423 const ETC2Block *sourceBlock = sourceRow + (x / 4);
1424 uint8_t *destPixels = destRow + (x * 4);
1425
1426 sourceBlock->decodeAsRGB(destPixels, x, y, width, height, outputRowPitch,
1427 DefaultETCAlphaValues, punchthroughAlpha);
1428 }
1429 }
1430 }
1431 }
1432
LoadETC2RGB8ToBC1(size_t width,size_t height,size_t depth,const uint8_t * input,size_t inputRowPitch,size_t inputDepthPitch,uint8_t * output,size_t outputRowPitch,size_t outputDepthPitch,bool punchthroughAlpha)1433 void LoadETC2RGB8ToBC1(size_t width,
1434 size_t height,
1435 size_t depth,
1436 const uint8_t *input,
1437 size_t inputRowPitch,
1438 size_t inputDepthPitch,
1439 uint8_t *output,
1440 size_t outputRowPitch,
1441 size_t outputDepthPitch,
1442 bool punchthroughAlpha)
1443 {
1444 for (size_t z = 0; z < depth; z++)
1445 {
1446 for (size_t y = 0; y < height; y += 4)
1447 {
1448 const ETC2Block *sourceRow =
1449 priv::OffsetDataPointer<ETC2Block>(input, y / 4, z, inputRowPitch, inputDepthPitch);
1450 uint8_t *destRow = priv::OffsetDataPointer<uint8_t>(output, y / 4, z, outputRowPitch,
1451 outputDepthPitch);
1452
1453 for (size_t x = 0; x < width; x += 4)
1454 {
1455 const ETC2Block *sourceBlock = sourceRow + (x / 4);
1456 uint8_t *destPixels = destRow + (x * 2);
1457
1458 sourceBlock->transcodeAsBC1(destPixels, x, y, width, height, DefaultETCAlphaValues,
1459 punchthroughAlpha);
1460 }
1461 }
1462 }
1463 }
1464
LoadETC2RGBA8ToRGBA8(size_t width,size_t height,size_t depth,const uint8_t * input,size_t inputRowPitch,size_t inputDepthPitch,uint8_t * output,size_t outputRowPitch,size_t outputDepthPitch,bool srgb)1465 void LoadETC2RGBA8ToRGBA8(size_t width,
1466 size_t height,
1467 size_t depth,
1468 const uint8_t *input,
1469 size_t inputRowPitch,
1470 size_t inputDepthPitch,
1471 uint8_t *output,
1472 size_t outputRowPitch,
1473 size_t outputDepthPitch,
1474 bool srgb)
1475 {
1476 uint8_t decodedAlphaValues[4][4];
1477
1478 for (size_t z = 0; z < depth; z++)
1479 {
1480 for (size_t y = 0; y < height; y += 4)
1481 {
1482 const ETC2Block *sourceRow =
1483 priv::OffsetDataPointer<ETC2Block>(input, y / 4, z, inputRowPitch, inputDepthPitch);
1484 uint8_t *destRow =
1485 priv::OffsetDataPointer<uint8_t>(output, y, z, outputRowPitch, outputDepthPitch);
1486
1487 for (size_t x = 0; x < width; x += 4)
1488 {
1489 const ETC2Block *sourceBlockAlpha = sourceRow + (x / 2);
1490 sourceBlockAlpha->decodeAsSingleChannel(
1491 reinterpret_cast<uint8_t *>(decodedAlphaValues), x, y, width, height, 1, 4,
1492 false);
1493
1494 uint8_t *destPixels = destRow + (x * 4);
1495 const ETC2Block *sourceBlockRGB = sourceBlockAlpha + 1;
1496 sourceBlockRGB->decodeAsRGB(destPixels, x, y, width, height, outputRowPitch,
1497 decodedAlphaValues, false);
1498 }
1499 }
1500 }
1501 }
1502
1503 } // anonymous namespace
1504
LoadETC1RGB8ToRGBA8(size_t width,size_t height,size_t depth,const uint8_t * input,size_t inputRowPitch,size_t inputDepthPitch,uint8_t * output,size_t outputRowPitch,size_t outputDepthPitch)1505 void LoadETC1RGB8ToRGBA8(size_t width,
1506 size_t height,
1507 size_t depth,
1508 const uint8_t *input,
1509 size_t inputRowPitch,
1510 size_t inputDepthPitch,
1511 uint8_t *output,
1512 size_t outputRowPitch,
1513 size_t outputDepthPitch)
1514 {
1515 LoadETC2RGB8ToRGBA8(width, height, depth, input, inputRowPitch, inputDepthPitch, output,
1516 outputRowPitch, outputDepthPitch, false);
1517 }
1518
LoadETC1RGB8ToBC1(size_t width,size_t height,size_t depth,const uint8_t * input,size_t inputRowPitch,size_t inputDepthPitch,uint8_t * output,size_t outputRowPitch,size_t outputDepthPitch)1519 void LoadETC1RGB8ToBC1(size_t width,
1520 size_t height,
1521 size_t depth,
1522 const uint8_t *input,
1523 size_t inputRowPitch,
1524 size_t inputDepthPitch,
1525 uint8_t *output,
1526 size_t outputRowPitch,
1527 size_t outputDepthPitch)
1528 {
1529 LoadETC2RGB8ToBC1(width, height, depth, input, inputRowPitch, inputDepthPitch, output,
1530 outputRowPitch, outputDepthPitch, false);
1531 }
1532
LoadEACR11ToR8(size_t width,size_t height,size_t depth,const uint8_t * input,size_t inputRowPitch,size_t inputDepthPitch,uint8_t * output,size_t outputRowPitch,size_t outputDepthPitch)1533 void LoadEACR11ToR8(size_t width,
1534 size_t height,
1535 size_t depth,
1536 const uint8_t *input,
1537 size_t inputRowPitch,
1538 size_t inputDepthPitch,
1539 uint8_t *output,
1540 size_t outputRowPitch,
1541 size_t outputDepthPitch)
1542 {
1543 LoadR11EACToR8(width, height, depth, input, inputRowPitch, inputDepthPitch, output,
1544 outputRowPitch, outputDepthPitch, false);
1545 }
1546
LoadEACR11SToR8(size_t width,size_t height,size_t depth,const uint8_t * input,size_t inputRowPitch,size_t inputDepthPitch,uint8_t * output,size_t outputRowPitch,size_t outputDepthPitch)1547 void LoadEACR11SToR8(size_t width,
1548 size_t height,
1549 size_t depth,
1550 const uint8_t *input,
1551 size_t inputRowPitch,
1552 size_t inputDepthPitch,
1553 uint8_t *output,
1554 size_t outputRowPitch,
1555 size_t outputDepthPitch)
1556 {
1557 LoadR11EACToR8(width, height, depth, input, inputRowPitch, inputDepthPitch, output,
1558 outputRowPitch, outputDepthPitch, true);
1559 }
1560
LoadEACRG11ToRG8(size_t width,size_t height,size_t depth,const uint8_t * input,size_t inputRowPitch,size_t inputDepthPitch,uint8_t * output,size_t outputRowPitch,size_t outputDepthPitch)1561 void LoadEACRG11ToRG8(size_t width,
1562 size_t height,
1563 size_t depth,
1564 const uint8_t *input,
1565 size_t inputRowPitch,
1566 size_t inputDepthPitch,
1567 uint8_t *output,
1568 size_t outputRowPitch,
1569 size_t outputDepthPitch)
1570 {
1571 LoadRG11EACToRG8(width, height, depth, input, inputRowPitch, inputDepthPitch, output,
1572 outputRowPitch, outputDepthPitch, false);
1573 }
1574
LoadEACRG11SToRG8(size_t width,size_t height,size_t depth,const uint8_t * input,size_t inputRowPitch,size_t inputDepthPitch,uint8_t * output,size_t outputRowPitch,size_t outputDepthPitch)1575 void LoadEACRG11SToRG8(size_t width,
1576 size_t height,
1577 size_t depth,
1578 const uint8_t *input,
1579 size_t inputRowPitch,
1580 size_t inputDepthPitch,
1581 uint8_t *output,
1582 size_t outputRowPitch,
1583 size_t outputDepthPitch)
1584 {
1585 LoadRG11EACToRG8(width, height, depth, input, inputRowPitch, inputDepthPitch, output,
1586 outputRowPitch, outputDepthPitch, true);
1587 }
1588
LoadETC2RGB8ToRGBA8(size_t width,size_t height,size_t depth,const uint8_t * input,size_t inputRowPitch,size_t inputDepthPitch,uint8_t * output,size_t outputRowPitch,size_t outputDepthPitch)1589 void LoadETC2RGB8ToRGBA8(size_t width,
1590 size_t height,
1591 size_t depth,
1592 const uint8_t *input,
1593 size_t inputRowPitch,
1594 size_t inputDepthPitch,
1595 uint8_t *output,
1596 size_t outputRowPitch,
1597 size_t outputDepthPitch)
1598 {
1599 LoadETC2RGB8ToRGBA8(width, height, depth, input, inputRowPitch, inputDepthPitch, output,
1600 outputRowPitch, outputDepthPitch, false);
1601 }
1602
LoadETC2RGB8ToBC1(size_t width,size_t height,size_t depth,const uint8_t * input,size_t inputRowPitch,size_t inputDepthPitch,uint8_t * output,size_t outputRowPitch,size_t outputDepthPitch)1603 void LoadETC2RGB8ToBC1(size_t width,
1604 size_t height,
1605 size_t depth,
1606 const uint8_t *input,
1607 size_t inputRowPitch,
1608 size_t inputDepthPitch,
1609 uint8_t *output,
1610 size_t outputRowPitch,
1611 size_t outputDepthPitch)
1612 {
1613 LoadETC2RGB8ToBC1(width, height, depth, input, inputRowPitch, inputDepthPitch, output,
1614 outputRowPitch, outputDepthPitch, false);
1615 }
1616
LoadETC2SRGB8ToRGBA8(size_t width,size_t height,size_t depth,const uint8_t * input,size_t inputRowPitch,size_t inputDepthPitch,uint8_t * output,size_t outputRowPitch,size_t outputDepthPitch)1617 void LoadETC2SRGB8ToRGBA8(size_t width,
1618 size_t height,
1619 size_t depth,
1620 const uint8_t *input,
1621 size_t inputRowPitch,
1622 size_t inputDepthPitch,
1623 uint8_t *output,
1624 size_t outputRowPitch,
1625 size_t outputDepthPitch)
1626 {
1627 LoadETC2RGB8ToRGBA8(width, height, depth, input, inputRowPitch, inputDepthPitch, output,
1628 outputRowPitch, outputDepthPitch, false);
1629 }
1630
LoadETC2SRGB8ToBC1(size_t width,size_t height,size_t depth,const uint8_t * input,size_t inputRowPitch,size_t inputDepthPitch,uint8_t * output,size_t outputRowPitch,size_t outputDepthPitch)1631 void LoadETC2SRGB8ToBC1(size_t width,
1632 size_t height,
1633 size_t depth,
1634 const uint8_t *input,
1635 size_t inputRowPitch,
1636 size_t inputDepthPitch,
1637 uint8_t *output,
1638 size_t outputRowPitch,
1639 size_t outputDepthPitch)
1640 {
1641 LoadETC2RGB8ToBC1(width, height, depth, input, inputRowPitch, inputDepthPitch, output,
1642 outputRowPitch, outputDepthPitch, false);
1643 }
1644
LoadETC2RGB8A1ToRGBA8(size_t width,size_t height,size_t depth,const uint8_t * input,size_t inputRowPitch,size_t inputDepthPitch,uint8_t * output,size_t outputRowPitch,size_t outputDepthPitch)1645 void LoadETC2RGB8A1ToRGBA8(size_t width,
1646 size_t height,
1647 size_t depth,
1648 const uint8_t *input,
1649 size_t inputRowPitch,
1650 size_t inputDepthPitch,
1651 uint8_t *output,
1652 size_t outputRowPitch,
1653 size_t outputDepthPitch)
1654 {
1655 LoadETC2RGB8ToRGBA8(width, height, depth, input, inputRowPitch, inputDepthPitch, output,
1656 outputRowPitch, outputDepthPitch, true);
1657 }
1658
LoadETC2RGB8A1ToBC1(size_t width,size_t height,size_t depth,const uint8_t * input,size_t inputRowPitch,size_t inputDepthPitch,uint8_t * output,size_t outputRowPitch,size_t outputDepthPitch)1659 void LoadETC2RGB8A1ToBC1(size_t width,
1660 size_t height,
1661 size_t depth,
1662 const uint8_t *input,
1663 size_t inputRowPitch,
1664 size_t inputDepthPitch,
1665 uint8_t *output,
1666 size_t outputRowPitch,
1667 size_t outputDepthPitch)
1668 {
1669 LoadETC2RGB8ToBC1(width, height, depth, input, inputRowPitch, inputDepthPitch, output,
1670 outputRowPitch, outputDepthPitch, true);
1671 }
1672
LoadETC2SRGB8A1ToRGBA8(size_t width,size_t height,size_t depth,const uint8_t * input,size_t inputRowPitch,size_t inputDepthPitch,uint8_t * output,size_t outputRowPitch,size_t outputDepthPitch)1673 void LoadETC2SRGB8A1ToRGBA8(size_t width,
1674 size_t height,
1675 size_t depth,
1676 const uint8_t *input,
1677 size_t inputRowPitch,
1678 size_t inputDepthPitch,
1679 uint8_t *output,
1680 size_t outputRowPitch,
1681 size_t outputDepthPitch)
1682 {
1683 LoadETC2RGB8ToRGBA8(width, height, depth, input, inputRowPitch, inputDepthPitch, output,
1684 outputRowPitch, outputDepthPitch, true);
1685 }
1686
LoadETC2SRGB8A1ToBC1(size_t width,size_t height,size_t depth,const uint8_t * input,size_t inputRowPitch,size_t inputDepthPitch,uint8_t * output,size_t outputRowPitch,size_t outputDepthPitch)1687 void LoadETC2SRGB8A1ToBC1(size_t width,
1688 size_t height,
1689 size_t depth,
1690 const uint8_t *input,
1691 size_t inputRowPitch,
1692 size_t inputDepthPitch,
1693 uint8_t *output,
1694 size_t outputRowPitch,
1695 size_t outputDepthPitch)
1696 {
1697 LoadETC2RGB8ToBC1(width, height, depth, input, inputRowPitch, inputDepthPitch, output,
1698 outputRowPitch, outputDepthPitch, true);
1699 }
1700
LoadETC2RGBA8ToRGBA8(size_t width,size_t height,size_t depth,const uint8_t * input,size_t inputRowPitch,size_t inputDepthPitch,uint8_t * output,size_t outputRowPitch,size_t outputDepthPitch)1701 void LoadETC2RGBA8ToRGBA8(size_t width,
1702 size_t height,
1703 size_t depth,
1704 const uint8_t *input,
1705 size_t inputRowPitch,
1706 size_t inputDepthPitch,
1707 uint8_t *output,
1708 size_t outputRowPitch,
1709 size_t outputDepthPitch)
1710 {
1711 LoadETC2RGBA8ToRGBA8(width, height, depth, input, inputRowPitch, inputDepthPitch, output,
1712 outputRowPitch, outputDepthPitch, false);
1713 }
1714
LoadETC2SRGBA8ToSRGBA8(size_t width,size_t height,size_t depth,const uint8_t * input,size_t inputRowPitch,size_t inputDepthPitch,uint8_t * output,size_t outputRowPitch,size_t outputDepthPitch)1715 void LoadETC2SRGBA8ToSRGBA8(size_t width,
1716 size_t height,
1717 size_t depth,
1718 const uint8_t *input,
1719 size_t inputRowPitch,
1720 size_t inputDepthPitch,
1721 uint8_t *output,
1722 size_t outputRowPitch,
1723 size_t outputDepthPitch)
1724 {
1725 LoadETC2RGBA8ToRGBA8(width, height, depth, input, inputRowPitch, inputDepthPitch, output,
1726 outputRowPitch, outputDepthPitch, true);
1727 }
1728
1729 } // namespace angle
1730