1 //
2 // Copyright 2013 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 <type_traits>
12 #include "common/mathutil.h"
13
14 #include "image_util/imageformats.h"
15
16 namespace angle
17 {
18 namespace
19 {
20
21 using IntensityModifier = const int[4];
22
23 // Table 3.17.2 sorted according to table 3.17.3
24 // clang-format off
25 static IntensityModifier intensityModifierDefault[] =
26 {
27 { 2, 8, -2, -8 },
28 { 5, 17, -5, -17 },
29 { 9, 29, -9, -29 },
30 { 13, 42, -13, -42 },
31 { 18, 60, -18, -60 },
32 { 24, 80, -24, -80 },
33 { 33, 106, -33, -106 },
34 { 47, 183, -47, -183 },
35 };
36 // clang-format on
37
38 // Table C.12, intensity modifier for non opaque punchthrough alpha
39 // clang-format off
40 static IntensityModifier intensityModifierNonOpaque[] =
41 {
42 { 0, 8, 0, -8 },
43 { 0, 17, 0, -17 },
44 { 0, 29, 0, -29 },
45 { 0, 42, 0, -42 },
46 { 0, 60, 0, -60 },
47 { 0, 80, 0, -80 },
48 { 0, 106, 0, -106 },
49 { 0, 183, 0, -183 },
50 };
51 // clang-format on
52
53 static const int kNumPixelsInBlock = 16;
54
55 struct ETC2Block
56 {
57 // Decodes unsigned single or dual channel ETC2 block to 8-bit color
decodeAsSingleETC2Channelangle::__anon4a5303920111::ETC2Block58 void decodeAsSingleETC2Channel(uint8_t *dest,
59 size_t x,
60 size_t y,
61 size_t w,
62 size_t h,
63 size_t destPixelStride,
64 size_t destRowPitch,
65 bool isSigned) const
66 {
67 for (size_t j = 0; j < 4 && (y + j) < h; j++)
68 {
69 uint8_t *row = dest + (j * destRowPitch);
70 for (size_t i = 0; i < 4 && (x + i) < w; i++)
71 {
72 uint8_t *pixel = row + (i * destPixelStride);
73 if (isSigned)
74 {
75 *pixel = clampSByte(getSingleETC2Channel(i, j, isSigned));
76 }
77 else
78 {
79 *pixel = clampByte(getSingleETC2Channel(i, j, isSigned));
80 }
81 }
82 }
83 }
84
85 // Transcodes block to BC4
86 // For simplicity, R11 alpha use the same formula as Alpha8 to decode,
87 // the result R8 may have some precision issue like multiplier == 0 case.
transcodeAsBC4angle::__anon4a5303920111::ETC2Block88 void transcodeAsBC4(uint8_t *dest, size_t x, size_t y, size_t w, size_t h, bool isSigned) const
89 {
90 static constexpr int kIndexMap[] = {1, 7, 6, 5, 4, 3, 2, 0};
91 int alpha[16];
92 size_t k = 0;
93 int minAlpha = std::numeric_limits<int>::max();
94 int maxAlpha = std::numeric_limits<int>::min();
95 for (size_t j = 0; j < 4; j++)
96 {
97 for (size_t i = 0; i < 4; i++)
98 {
99 if (isSigned)
100 {
101 alpha[k] = clampSByte(getSingleETC2Channel(i, j, isSigned));
102 }
103 else
104 {
105 alpha[k] = clampByte(getSingleETC2Channel(i, j, isSigned));
106 }
107 minAlpha = std::min(minAlpha, alpha[k]);
108 maxAlpha = std::max(maxAlpha, alpha[k]);
109 k++;
110 }
111 }
112 uint64_t *result = (uint64_t *)dest;
113 *result = (maxAlpha & 0xff) | ((minAlpha & 0xff) << 8);
114 if (minAlpha != maxAlpha)
115 {
116 float dist = static_cast<float>(maxAlpha - minAlpha);
117 for (size_t i = 0; i < 16; i++)
118 {
119 int ind = int(roundf((alpha[i] - minAlpha) / dist * 7.0f));
120 // 0 : maxAlpha
121 // 1 : minAlpha
122 // 2 : 6/7*maxAlpha + 1/7*minAlpha;
123 // 3 : 5/7*maxAlpha + 2/7*minAlpha;
124 // 4 : 4/7*maxAlpha + 3/7*minAlpha;
125 // 5 : 3/7*maxAlpha + 4/7*minAlpha;
126 // 6 : 2/7*maxAlpha + 5/7*minAlpha;
127 // 7 : 1/7*maxAlpha + 6/7*minAlpha;
128 // so the mapping is
129 // 0 -> 1
130 // 1 -> 7
131 // 2 -> 6
132 // 3 -> 5
133 // 4 -> 4
134 // 5 -> 3
135 // 6 -> 2
136 // 7 -> 0
137 *result |= ((uint64_t)kIndexMap[ind]) << ((3 * i) + 16);
138 }
139 }
140 }
141
142 // Decodes unsigned single or dual channel EAC block to 16-bit color
decodeAsSingleEACChannelangle::__anon4a5303920111::ETC2Block143 void decodeAsSingleEACChannel(uint16_t *dest,
144 size_t x,
145 size_t y,
146 size_t w,
147 size_t h,
148 size_t destPixelStride,
149 size_t destRowPitch,
150 bool isSigned,
151 bool isFloat) const
152 {
153 for (size_t j = 0; j < 4 && (y + j) < h; j++)
154 {
155 uint16_t *row = reinterpret_cast<uint16_t *>(reinterpret_cast<uint8_t *>(dest) +
156 (j * destRowPitch));
157 for (size_t i = 0; i < 4 && (x + i) < w; i++)
158 {
159 uint16_t *pixel = row + (i * destPixelStride);
160 if (isSigned)
161 {
162 int16_t tempPixel =
163 renormalizeEAC<int16_t>(getSingleEACChannel(i, j, isSigned));
164 *pixel =
165 isFloat ? gl::float32ToFloat16(float(gl::normalize(tempPixel))) : tempPixel;
166 }
167 else
168 {
169 uint16_t tempPixel =
170 renormalizeEAC<uint16_t>(getSingleEACChannel(i, j, isSigned));
171 *pixel =
172 isFloat ? gl::float32ToFloat16(float(gl::normalize(tempPixel))) : tempPixel;
173 }
174 }
175 }
176 }
177
178 // Decodes RGB block to rgba8
decodeAsRGBangle::__anon4a5303920111::ETC2Block179 void decodeAsRGB(uint8_t *dest,
180 size_t x,
181 size_t y,
182 size_t w,
183 size_t h,
184 size_t destRowPitch,
185 const uint8_t alphaValues[4][4],
186 bool punchThroughAlpha) const
187 {
188 bool opaqueBit = u.idht.mode.idm.diffbit;
189 bool nonOpaquePunchThroughAlpha = punchThroughAlpha && !opaqueBit;
190 // Select mode
191 if (u.idht.mode.idm.diffbit || punchThroughAlpha)
192 {
193 const auto &block = u.idht.mode.idm.colors.diff;
194 int r = (block.R + block.dR);
195 int g = (block.G + block.dG);
196 int b = (block.B + block.dB);
197 if (r < 0 || r > 31)
198 {
199 decodeTBlock(dest, x, y, w, h, destRowPitch, alphaValues,
200 nonOpaquePunchThroughAlpha);
201 }
202 else if (g < 0 || g > 31)
203 {
204 decodeHBlock(dest, x, y, w, h, destRowPitch, alphaValues,
205 nonOpaquePunchThroughAlpha);
206 }
207 else if (b < 0 || b > 31)
208 {
209 decodePlanarBlock(dest, x, y, w, h, destRowPitch, alphaValues);
210 }
211 else
212 {
213 decodeDifferentialBlock(dest, x, y, w, h, destRowPitch, alphaValues,
214 nonOpaquePunchThroughAlpha);
215 }
216 }
217 else
218 {
219 decodeIndividualBlock(dest, x, y, w, h, destRowPitch, alphaValues,
220 nonOpaquePunchThroughAlpha);
221 }
222 }
223
224 // Transcodes RGB block to BC1
transcodeAsBC1angle::__anon4a5303920111::ETC2Block225 void transcodeAsBC1(uint8_t *dest,
226 size_t x,
227 size_t y,
228 size_t w,
229 size_t h,
230 const uint8_t alphaValues[4][4],
231 bool punchThroughAlpha) const
232 {
233 bool opaqueBit = u.idht.mode.idm.diffbit;
234 bool nonOpaquePunchThroughAlpha = punchThroughAlpha && !opaqueBit;
235 // Select mode
236 if (u.idht.mode.idm.diffbit || punchThroughAlpha)
237 {
238 const auto &block = u.idht.mode.idm.colors.diff;
239 int r = (block.R + block.dR);
240 int g = (block.G + block.dG);
241 int b = (block.B + block.dB);
242 if (r < 0 || r > 31)
243 {
244 transcodeTBlockToBC1(dest, x, y, w, h, alphaValues, nonOpaquePunchThroughAlpha);
245 }
246 else if (g < 0 || g > 31)
247 {
248 transcodeHBlockToBC1(dest, x, y, w, h, alphaValues, nonOpaquePunchThroughAlpha);
249 }
250 else if (b < 0 || b > 31)
251 {
252 transcodePlanarBlockToBC1(dest, x, y, w, h, alphaValues);
253 }
254 else
255 {
256 transcodeDifferentialBlockToBC1(dest, x, y, w, h, alphaValues,
257 nonOpaquePunchThroughAlpha);
258 }
259 }
260 else
261 {
262 transcodeIndividualBlockToBC1(dest, x, y, w, h, alphaValues,
263 nonOpaquePunchThroughAlpha);
264 }
265 }
266
267 private:
268 union
269 {
270 // Individual, differential, H and T modes
271 struct
272 {
273 union
274 {
275 // Individual and differential modes
276 struct
277 {
278 union
279 {
280 struct // Individual colors
281 {
282 unsigned char R2 : 4;
283 unsigned char R1 : 4;
284 unsigned char G2 : 4;
285 unsigned char G1 : 4;
286 unsigned char B2 : 4;
287 unsigned char B1 : 4;
288 } indiv;
289 struct // Differential colors
290 {
291 signed char dR : 3;
292 unsigned char R : 5;
293 signed char dG : 3;
294 unsigned char G : 5;
295 signed char dB : 3;
296 unsigned char B : 5;
297 } diff;
298 } colors;
299 bool flipbit : 1;
300 bool diffbit : 1;
301 unsigned char cw2 : 3;
302 unsigned char cw1 : 3;
303 } idm;
304 // T mode
305 struct
306 {
307 // Byte 1
308 unsigned char TR1b : 2;
309 unsigned char TunusedB : 1;
310 unsigned char TR1a : 2;
311 unsigned char TunusedA : 3;
312 // Byte 2
313 unsigned char TB1 : 4;
314 unsigned char TG1 : 4;
315 // Byte 3
316 unsigned char TG2 : 4;
317 unsigned char TR2 : 4;
318 // Byte 4
319 unsigned char Tdb : 1;
320 bool Tflipbit : 1;
321 unsigned char Tda : 2;
322 unsigned char TB2 : 4;
323 } tm;
324 // H mode
325 struct
326 {
327 // Byte 1
328 unsigned char HG1a : 3;
329 unsigned char HR1 : 4;
330 unsigned char HunusedA : 1;
331 // Byte 2
332 unsigned char HB1b : 2;
333 unsigned char HunusedC : 1;
334 unsigned char HB1a : 1;
335 unsigned char HG1b : 1;
336 unsigned char HunusedB : 3;
337 // Byte 3
338 unsigned char HG2a : 3;
339 unsigned char HR2 : 4;
340 unsigned char HB1c : 1;
341 // Byte 4
342 unsigned char Hdb : 1;
343 bool Hflipbit : 1;
344 unsigned char Hda : 1;
345 unsigned char HB2 : 4;
346 unsigned char HG2b : 1;
347 } hm;
348 } mode;
349 unsigned char pixelIndexMSB[2];
350 unsigned char pixelIndexLSB[2];
351 } idht;
352 // planar mode
353 struct
354 {
355 // Byte 1
356 unsigned char GO1 : 1;
357 unsigned char RO : 6;
358 unsigned char PunusedA : 1;
359 // Byte 2
360 unsigned char BO1 : 1;
361 unsigned char GO2 : 6;
362 unsigned char PunusedB : 1;
363 // Byte 3
364 unsigned char BO3a : 2;
365 unsigned char PunusedD : 1;
366 unsigned char BO2 : 2;
367 unsigned char PunusedC : 3;
368 // Byte 4
369 unsigned char RH2 : 1;
370 bool Pflipbit : 1;
371 unsigned char RH1 : 5;
372 unsigned char BO3b : 1;
373 // Byte 5
374 unsigned char BHa : 1;
375 unsigned char GH : 7;
376 // Byte 6
377 unsigned char RVa : 3;
378 unsigned char BHb : 5;
379 // Byte 7
380 unsigned char GVa : 5;
381 unsigned char RVb : 3;
382 // Byte 8
383 unsigned char BV : 6;
384 unsigned char GVb : 2;
385 } pblk;
386 // Single channel block
387 struct
388 {
389 union
390 {
391 unsigned char us;
392 signed char s;
393 } base_codeword;
394 unsigned char table_index : 4;
395 unsigned char multiplier : 4;
396 unsigned char mc1 : 2;
397 unsigned char mb : 3;
398 unsigned char ma : 3;
399 unsigned char mf1 : 1;
400 unsigned char me : 3;
401 unsigned char md : 3;
402 unsigned char mc2 : 1;
403 unsigned char mh : 3;
404 unsigned char mg : 3;
405 unsigned char mf2 : 2;
406 unsigned char mk1 : 2;
407 unsigned char mj : 3;
408 unsigned char mi : 3;
409 unsigned char mn1 : 1;
410 unsigned char mm : 3;
411 unsigned char ml : 3;
412 unsigned char mk2 : 1;
413 unsigned char mp : 3;
414 unsigned char mo : 3;
415 unsigned char mn2 : 2;
416 } scblk;
417 } u;
418
clampByteangle::__anon4a5303920111::ETC2Block419 static unsigned char clampByte(int value)
420 {
421 return static_cast<unsigned char>(gl::clamp(value, 0, 255));
422 }
423
clampSByteangle::__anon4a5303920111::ETC2Block424 static signed char clampSByte(int value)
425 {
426 return static_cast<signed char>(gl::clamp(value, -128, 127));
427 }
428
429 template <typename T>
renormalizeEACangle::__anon4a5303920111::ETC2Block430 static T renormalizeEAC(int value)
431 {
432 int upper = 0;
433 int lower = 0;
434 int shift = 0;
435
436 if (std::is_same<T, int16_t>::value)
437 {
438 // The spec states that -1024 invalid and should be clamped to -1023
439 upper = 1023;
440 lower = -1023;
441 shift = 5;
442 }
443 else if (std::is_same<T, uint16_t>::value)
444 {
445 upper = 2047;
446 lower = 0;
447 shift = 5;
448 }
449 else
450 {
451 // We currently only support renormalizing int16_t or uint16_t
452 UNREACHABLE();
453 }
454
455 return static_cast<T>(gl::clamp(value, lower, upper)) << shift;
456 }
457
createRGBAangle::__anon4a5303920111::ETC2Block458 static R8G8B8A8 createRGBA(int red, int green, int blue, int alpha)
459 {
460 R8G8B8A8 rgba;
461 rgba.R = clampByte(red);
462 rgba.G = clampByte(green);
463 rgba.B = clampByte(blue);
464 rgba.A = clampByte(alpha);
465 return rgba;
466 }
467
createRGBAangle::__anon4a5303920111::ETC2Block468 static R8G8B8A8 createRGBA(int red, int green, int blue)
469 {
470 return createRGBA(red, green, blue, 255);
471 }
472
extend_4to8bitsangle::__anon4a5303920111::ETC2Block473 static int extend_4to8bits(int x) { return (x << 4) | x; }
extend_5to8bitsangle::__anon4a5303920111::ETC2Block474 static int extend_5to8bits(int x) { return (x << 3) | (x >> 2); }
extend_6to8bitsangle::__anon4a5303920111::ETC2Block475 static int extend_6to8bits(int x) { return (x << 2) | (x >> 4); }
extend_7to8bitsangle::__anon4a5303920111::ETC2Block476 static int extend_7to8bits(int x) { return (x << 1) | (x >> 6); }
477
decodeIndividualBlockangle::__anon4a5303920111::ETC2Block478 void decodeIndividualBlock(uint8_t *dest,
479 size_t x,
480 size_t y,
481 size_t w,
482 size_t h,
483 size_t destRowPitch,
484 const uint8_t alphaValues[4][4],
485 bool nonOpaquePunchThroughAlpha) const
486 {
487 const auto &block = u.idht.mode.idm.colors.indiv;
488 int r1 = extend_4to8bits(block.R1);
489 int g1 = extend_4to8bits(block.G1);
490 int b1 = extend_4to8bits(block.B1);
491 int r2 = extend_4to8bits(block.R2);
492 int g2 = extend_4to8bits(block.G2);
493 int b2 = extend_4to8bits(block.B2);
494 decodeIndividualOrDifferentialBlock(dest, x, y, w, h, destRowPitch, r1, g1, b1, r2, g2, b2,
495 alphaValues, nonOpaquePunchThroughAlpha);
496 }
497
decodeDifferentialBlockangle::__anon4a5303920111::ETC2Block498 void decodeDifferentialBlock(uint8_t *dest,
499 size_t x,
500 size_t y,
501 size_t w,
502 size_t h,
503 size_t destRowPitch,
504 const uint8_t alphaValues[4][4],
505 bool nonOpaquePunchThroughAlpha) const
506 {
507 const auto &block = u.idht.mode.idm.colors.diff;
508 int b1 = extend_5to8bits(block.B);
509 int g1 = extend_5to8bits(block.G);
510 int r1 = extend_5to8bits(block.R);
511 int r2 = extend_5to8bits(block.R + block.dR);
512 int g2 = extend_5to8bits(block.G + block.dG);
513 int b2 = extend_5to8bits(block.B + block.dB);
514 decodeIndividualOrDifferentialBlock(dest, x, y, w, h, destRowPitch, r1, g1, b1, r2, g2, b2,
515 alphaValues, nonOpaquePunchThroughAlpha);
516 }
517
decodeIndividualOrDifferentialBlockangle::__anon4a5303920111::ETC2Block518 void decodeIndividualOrDifferentialBlock(uint8_t *dest,
519 size_t x,
520 size_t y,
521 size_t w,
522 size_t h,
523 size_t destRowPitch,
524 int r1,
525 int g1,
526 int b1,
527 int r2,
528 int g2,
529 int b2,
530 const uint8_t alphaValues[4][4],
531 bool nonOpaquePunchThroughAlpha) const
532 {
533 const IntensityModifier *intensityModifier =
534 nonOpaquePunchThroughAlpha ? intensityModifierNonOpaque : intensityModifierDefault;
535
536 R8G8B8A8 subblockColors0[4];
537 R8G8B8A8 subblockColors1[4];
538 for (size_t modifierIdx = 0; modifierIdx < 4; modifierIdx++)
539 {
540 const int i1 = intensityModifier[u.idht.mode.idm.cw1][modifierIdx];
541 subblockColors0[modifierIdx] = createRGBA(r1 + i1, g1 + i1, b1 + i1);
542
543 const int i2 = intensityModifier[u.idht.mode.idm.cw2][modifierIdx];
544 subblockColors1[modifierIdx] = createRGBA(r2 + i2, g2 + i2, b2 + i2);
545 }
546
547 if (u.idht.mode.idm.flipbit)
548 {
549 uint8_t *curPixel = dest;
550 for (size_t j = 0; j < 2 && (y + j) < h; j++)
551 {
552 R8G8B8A8 *row = reinterpret_cast<R8G8B8A8 *>(curPixel);
553 for (size_t i = 0; i < 4 && (x + i) < w; i++)
554 {
555 row[i] = subblockColors0[getIndex(i, j)];
556 row[i].A = alphaValues[j][i];
557 }
558 curPixel += destRowPitch;
559 }
560 for (size_t j = 2; j < 4 && (y + j) < h; j++)
561 {
562 R8G8B8A8 *row = reinterpret_cast<R8G8B8A8 *>(curPixel);
563 for (size_t i = 0; i < 4 && (x + i) < w; i++)
564 {
565 row[i] = subblockColors1[getIndex(i, j)];
566 row[i].A = alphaValues[j][i];
567 }
568 curPixel += destRowPitch;
569 }
570 }
571 else
572 {
573 uint8_t *curPixel = dest;
574 for (size_t j = 0; j < 4 && (y + j) < h; j++)
575 {
576 R8G8B8A8 *row = reinterpret_cast<R8G8B8A8 *>(curPixel);
577 for (size_t i = 0; i < 2 && (x + i) < w; i++)
578 {
579 row[i] = subblockColors0[getIndex(i, j)];
580 row[i].A = alphaValues[j][i];
581 }
582 for (size_t i = 2; i < 4 && (x + i) < w; i++)
583 {
584 row[i] = subblockColors1[getIndex(i, j)];
585 row[i].A = alphaValues[j][i];
586 }
587 curPixel += destRowPitch;
588 }
589 }
590 if (nonOpaquePunchThroughAlpha)
591 {
592 decodePunchThroughAlphaBlock(dest, x, y, w, h, destRowPitch);
593 }
594 }
595
decodeTBlockangle::__anon4a5303920111::ETC2Block596 void decodeTBlock(uint8_t *dest,
597 size_t x,
598 size_t y,
599 size_t w,
600 size_t h,
601 size_t destRowPitch,
602 const uint8_t alphaValues[4][4],
603 bool nonOpaquePunchThroughAlpha) const
604 {
605 // Table C.8, distance index for T and H modes
606 const auto &block = u.idht.mode.tm;
607
608 int r1 = extend_4to8bits(block.TR1a << 2 | block.TR1b);
609 int g1 = extend_4to8bits(block.TG1);
610 int b1 = extend_4to8bits(block.TB1);
611 int r2 = extend_4to8bits(block.TR2);
612 int g2 = extend_4to8bits(block.TG2);
613 int b2 = extend_4to8bits(block.TB2);
614
615 static int distance[8] = {3, 6, 11, 16, 23, 32, 41, 64};
616 const int d = distance[block.Tda << 1 | block.Tdb];
617
618 const R8G8B8A8 paintColors[4] = {
619 createRGBA(r1, g1, b1),
620 createRGBA(r2 + d, g2 + d, b2 + d),
621 createRGBA(r2, g2, b2),
622 createRGBA(r2 - d, g2 - d, b2 - d),
623 };
624
625 uint8_t *curPixel = dest;
626 for (size_t j = 0; j < 4 && (y + j) < h; j++)
627 {
628 R8G8B8A8 *row = reinterpret_cast<R8G8B8A8 *>(curPixel);
629 for (size_t i = 0; i < 4 && (x + i) < w; i++)
630 {
631 row[i] = paintColors[getIndex(i, j)];
632 row[i].A = alphaValues[j][i];
633 }
634 curPixel += destRowPitch;
635 }
636
637 if (nonOpaquePunchThroughAlpha)
638 {
639 decodePunchThroughAlphaBlock(dest, x, y, w, h, destRowPitch);
640 }
641 }
642
decodeHBlockangle::__anon4a5303920111::ETC2Block643 void decodeHBlock(uint8_t *dest,
644 size_t x,
645 size_t y,
646 size_t w,
647 size_t h,
648 size_t destRowPitch,
649 const uint8_t alphaValues[4][4],
650 bool nonOpaquePunchThroughAlpha) const
651 {
652 // Table C.8, distance index for T and H modes
653 const auto &block = u.idht.mode.hm;
654
655 int r1 = extend_4to8bits(block.HR1);
656 int g1 = extend_4to8bits(block.HG1a << 1 | block.HG1b);
657 int b1 = extend_4to8bits(block.HB1a << 3 | block.HB1b << 1 | block.HB1c);
658 int r2 = extend_4to8bits(block.HR2);
659 int g2 = extend_4to8bits(block.HG2a << 1 | block.HG2b);
660 int b2 = extend_4to8bits(block.HB2);
661
662 static const int distance[8] = {3, 6, 11, 16, 23, 32, 41, 64};
663 const int orderingTrickBit =
664 ((r1 << 16 | g1 << 8 | b1) >= (r2 << 16 | g2 << 8 | b2) ? 1 : 0);
665 const int d = distance[(block.Hda << 2) | (block.Hdb << 1) | orderingTrickBit];
666
667 const R8G8B8A8 paintColors[4] = {
668 createRGBA(r1 + d, g1 + d, b1 + d),
669 createRGBA(r1 - d, g1 - d, b1 - d),
670 createRGBA(r2 + d, g2 + d, b2 + d),
671 createRGBA(r2 - d, g2 - d, b2 - d),
672 };
673
674 uint8_t *curPixel = dest;
675 for (size_t j = 0; j < 4 && (y + j) < h; j++)
676 {
677 R8G8B8A8 *row = reinterpret_cast<R8G8B8A8 *>(curPixel);
678 for (size_t i = 0; i < 4 && (x + i) < w; i++)
679 {
680 row[i] = paintColors[getIndex(i, j)];
681 row[i].A = alphaValues[j][i];
682 }
683 curPixel += destRowPitch;
684 }
685
686 if (nonOpaquePunchThroughAlpha)
687 {
688 decodePunchThroughAlphaBlock(dest, x, y, w, h, destRowPitch);
689 }
690 }
691
decodePlanarBlockangle::__anon4a5303920111::ETC2Block692 void decodePlanarBlock(uint8_t *dest,
693 size_t x,
694 size_t y,
695 size_t w,
696 size_t h,
697 size_t pitch,
698 const uint8_t alphaValues[4][4]) const
699 {
700 int ro = extend_6to8bits(u.pblk.RO);
701 int go = extend_7to8bits(u.pblk.GO1 << 6 | u.pblk.GO2);
702 int bo =
703 extend_6to8bits(u.pblk.BO1 << 5 | u.pblk.BO2 << 3 | u.pblk.BO3a << 1 | u.pblk.BO3b);
704 int rh = extend_6to8bits(u.pblk.RH1 << 1 | u.pblk.RH2);
705 int gh = extend_7to8bits(u.pblk.GH);
706 int bh = extend_6to8bits(u.pblk.BHa << 5 | u.pblk.BHb);
707 int rv = extend_6to8bits(u.pblk.RVa << 3 | u.pblk.RVb);
708 int gv = extend_7to8bits(u.pblk.GVa << 2 | u.pblk.GVb);
709 int bv = extend_6to8bits(u.pblk.BV);
710
711 uint8_t *curPixel = dest;
712 for (size_t j = 0; j < 4 && (y + j) < h; j++)
713 {
714 R8G8B8A8 *row = reinterpret_cast<R8G8B8A8 *>(curPixel);
715
716 int ry = static_cast<int>(j) * (rv - ro) + 2;
717 int gy = static_cast<int>(j) * (gv - go) + 2;
718 int by = static_cast<int>(j) * (bv - bo) + 2;
719 for (size_t i = 0; i < 4 && (x + i) < w; i++)
720 {
721 row[i] = createRGBA(((static_cast<int>(i) * (rh - ro) + ry) >> 2) + ro,
722 ((static_cast<int>(i) * (gh - go) + gy) >> 2) + go,
723 ((static_cast<int>(i) * (bh - bo) + by) >> 2) + bo,
724 alphaValues[j][i]);
725 }
726 curPixel += pitch;
727 }
728 }
729
730 // Index for individual, differential, H and T modes
getIndexangle::__anon4a5303920111::ETC2Block731 size_t getIndex(size_t x, size_t y) const
732 {
733 size_t bitIndex = x * 4 + y;
734 size_t bitOffset = bitIndex & 7;
735 size_t lsb = (u.idht.pixelIndexLSB[1 - (bitIndex >> 3)] >> bitOffset) & 1;
736 size_t msb = (u.idht.pixelIndexMSB[1 - (bitIndex >> 3)] >> bitOffset) & 1;
737 return (msb << 1) | lsb;
738 }
739
decodePunchThroughAlphaBlockangle::__anon4a5303920111::ETC2Block740 void decodePunchThroughAlphaBlock(uint8_t *dest,
741 size_t x,
742 size_t y,
743 size_t w,
744 size_t h,
745 size_t destRowPitch) const
746 {
747 uint8_t *curPixel = dest;
748 for (size_t j = 0; j < 4 && (y + j) < h; j++)
749 {
750 R8G8B8A8 *row = reinterpret_cast<R8G8B8A8 *>(curPixel);
751 for (size_t i = 0; i < 4 && (x + i) < w; i++)
752 {
753 if (getIndex(i, j) == 2) // msb == 1 && lsb == 0
754 {
755 row[i] = createRGBA(0, 0, 0, 0);
756 }
757 }
758 curPixel += destRowPitch;
759 }
760 }
761
RGB8ToRGB565angle::__anon4a5303920111::ETC2Block762 uint16_t RGB8ToRGB565(const R8G8B8A8 &rgba) const
763 {
764 return (static_cast<uint16_t>(rgba.R >> 3) << 11) |
765 (static_cast<uint16_t>(rgba.G >> 2) << 5) |
766 (static_cast<uint16_t>(rgba.B >> 3) << 0);
767 }
768
matchBC1Bitsangle::__anon4a5303920111::ETC2Block769 uint32_t matchBC1Bits(const int *pixelIndices,
770 const int *pixelIndexCounts,
771 const R8G8B8A8 *subblockColors,
772 size_t numColors,
773 const R8G8B8A8 &minColor,
774 const R8G8B8A8 &maxColor,
775 bool nonOpaquePunchThroughAlpha) const
776 {
777 // Project each pixel on the (maxColor, minColor) line to decide which
778 // BC1 code to assign to it.
779
780 uint8_t decodedColors[2][3] = {{maxColor.R, maxColor.G, maxColor.B},
781 {minColor.R, minColor.G, minColor.B}};
782
783 int direction[3];
784 for (int ch = 0; ch < 3; ch++)
785 {
786 direction[ch] = decodedColors[0][ch] - decodedColors[1][ch];
787 }
788
789 int stops[2];
790 for (int i = 0; i < 2; i++)
791 {
792 stops[i] = decodedColors[i][0] * direction[0] + decodedColors[i][1] * direction[1] +
793 decodedColors[i][2] * direction[2];
794 }
795
796 ASSERT(numColors <= kNumPixelsInBlock);
797
798 int encodedColors[kNumPixelsInBlock];
799 if (nonOpaquePunchThroughAlpha)
800 {
801 for (size_t i = 0; i < numColors; i++)
802 {
803 const int count = pixelIndexCounts[i];
804 if (count > 0)
805 {
806 // In non-opaque mode, 3 is for tranparent pixels.
807
808 if (0 == subblockColors[i].A)
809 {
810 encodedColors[i] = 3;
811 }
812 else
813 {
814 const R8G8B8A8 &pixel = subblockColors[i];
815 const int dot = pixel.R * direction[0] + pixel.G * direction[1] +
816 pixel.B * direction[2];
817 const int factor = gl::clamp(
818 static_cast<int>(
819 (static_cast<float>(dot - stops[1]) / (stops[0] - stops[1])) * 2 +
820 0.5f),
821 0, 2);
822 switch (factor)
823 {
824 case 0:
825 encodedColors[i] = 0;
826 break;
827 case 1:
828 encodedColors[i] = 2;
829 break;
830 case 2:
831 default:
832 encodedColors[i] = 1;
833 break;
834 }
835 }
836 }
837 }
838 }
839 else
840 {
841 for (size_t i = 0; i < numColors; i++)
842 {
843 const int count = pixelIndexCounts[i];
844 if (count > 0)
845 {
846 // In opaque mode, the code is from 0 to 3.
847
848 const R8G8B8A8 &pixel = subblockColors[i];
849 const int dot =
850 pixel.R * direction[0] + pixel.G * direction[1] + pixel.B * direction[2];
851 const int factor = gl::clamp(
852 static_cast<int>(
853 (static_cast<float>(dot - stops[1]) / (stops[0] - stops[1])) * 3 +
854 0.5f),
855 0, 3);
856 switch (factor)
857 {
858 case 0:
859 encodedColors[i] = 1;
860 break;
861 case 1:
862 encodedColors[i] = 3;
863 break;
864 case 2:
865 encodedColors[i] = 2;
866 break;
867 case 3:
868 default:
869 encodedColors[i] = 0;
870 break;
871 }
872 }
873 }
874 }
875
876 uint32_t bits = 0;
877 for (int i = kNumPixelsInBlock - 1; i >= 0; i--)
878 {
879 bits <<= 2;
880 bits |= encodedColors[pixelIndices[i]];
881 }
882
883 return bits;
884 }
885
packBC1angle::__anon4a5303920111::ETC2Block886 void packBC1(void *bc1,
887 const int *pixelIndices,
888 const int *pixelIndexCounts,
889 const R8G8B8A8 *subblockColors,
890 size_t numColors,
891 int minColorIndex,
892 int maxColorIndex,
893 bool nonOpaquePunchThroughAlpha) const
894 {
895 const R8G8B8A8 &minColor = subblockColors[minColorIndex];
896 const R8G8B8A8 &maxColor = subblockColors[maxColorIndex];
897
898 uint32_t bits;
899 uint16_t max16 = RGB8ToRGB565(maxColor);
900 uint16_t min16 = RGB8ToRGB565(minColor);
901 if (max16 != min16)
902 {
903 // Find the best BC1 code for each pixel
904 bits = matchBC1Bits(pixelIndices, pixelIndexCounts, subblockColors, numColors, minColor,
905 maxColor, nonOpaquePunchThroughAlpha);
906 }
907 else
908 {
909 // Same colors, BC1 index 0 is the color in both opaque and transparent mode
910 bits = 0;
911 // BC1 index 3 is transparent
912 if (nonOpaquePunchThroughAlpha)
913 {
914 for (int i = 0; i < kNumPixelsInBlock; i++)
915 {
916 if (0 == subblockColors[pixelIndices[i]].A)
917 {
918 bits |= (3 << (i * 2));
919 }
920 }
921 }
922 }
923
924 if (max16 < min16)
925 {
926 std::swap(max16, min16);
927
928 uint32_t xorMask = 0;
929 if (nonOpaquePunchThroughAlpha)
930 {
931 // In transparent mode switching the colors is doing the
932 // following code swap: 0 <-> 1. 0xA selects the second bit of
933 // each code, bits >> 1 selects the first bit of the code when
934 // the seconds bit is set (case 2 and 3). We invert all the
935 // non-selected bits, that is the first bit when the code is
936 // 0 or 1.
937 xorMask = ~((bits >> 1) | 0xAAAAAAAA);
938 }
939 else
940 {
941 // In opaque mode switching the two colors is doing the
942 // following code swaps: 0 <-> 1 and 2 <-> 3. This is
943 // equivalent to flipping the first bit of each code
944 // (5 = 0b0101)
945 xorMask = 0x55555555;
946 }
947 bits ^= xorMask;
948 }
949
950 struct BC1Block
951 {
952 uint16_t color0;
953 uint16_t color1;
954 uint32_t bits;
955 };
956
957 // Encode the opaqueness in the order of the two BC1 colors
958 BC1Block *dest = reinterpret_cast<BC1Block *>(bc1);
959 if (nonOpaquePunchThroughAlpha)
960 {
961 dest->color0 = min16;
962 dest->color1 = max16;
963 }
964 else
965 {
966 dest->color0 = max16;
967 dest->color1 = min16;
968 }
969 dest->bits = bits;
970 }
971
transcodeIndividualBlockToBC1angle::__anon4a5303920111::ETC2Block972 void transcodeIndividualBlockToBC1(uint8_t *dest,
973 size_t x,
974 size_t y,
975 size_t w,
976 size_t h,
977 const uint8_t alphaValues[4][4],
978 bool nonOpaquePunchThroughAlpha) const
979 {
980 const auto &block = u.idht.mode.idm.colors.indiv;
981 int r1 = extend_4to8bits(block.R1);
982 int g1 = extend_4to8bits(block.G1);
983 int b1 = extend_4to8bits(block.B1);
984 int r2 = extend_4to8bits(block.R2);
985 int g2 = extend_4to8bits(block.G2);
986 int b2 = extend_4to8bits(block.B2);
987 transcodeIndividualOrDifferentialBlockToBC1(dest, x, y, w, h, r1, g1, b1, r2, g2, b2,
988 alphaValues, nonOpaquePunchThroughAlpha);
989 }
990
transcodeDifferentialBlockToBC1angle::__anon4a5303920111::ETC2Block991 void transcodeDifferentialBlockToBC1(uint8_t *dest,
992 size_t x,
993 size_t y,
994 size_t w,
995 size_t h,
996 const uint8_t alphaValues[4][4],
997 bool nonOpaquePunchThroughAlpha) const
998 {
999 const auto &block = u.idht.mode.idm.colors.diff;
1000 int b1 = extend_5to8bits(block.B);
1001 int g1 = extend_5to8bits(block.G);
1002 int r1 = extend_5to8bits(block.R);
1003 int r2 = extend_5to8bits(block.R + block.dR);
1004 int g2 = extend_5to8bits(block.G + block.dG);
1005 int b2 = extend_5to8bits(block.B + block.dB);
1006 transcodeIndividualOrDifferentialBlockToBC1(dest, x, y, w, h, r1, g1, b1, r2, g2, b2,
1007 alphaValues, nonOpaquePunchThroughAlpha);
1008 }
1009
extractPixelIndicesangle::__anon4a5303920111::ETC2Block1010 void extractPixelIndices(int *pixelIndices,
1011 int *pixelIndicesCounts,
1012 size_t x,
1013 size_t y,
1014 size_t w,
1015 size_t h,
1016 bool flipbit,
1017 size_t subblockIdx) const
1018 {
1019 size_t dxBegin = 0;
1020 size_t dxEnd = 4;
1021 size_t dyBegin = subblockIdx * 2;
1022 size_t dyEnd = dyBegin + 2;
1023 if (!flipbit)
1024 {
1025 std::swap(dxBegin, dyBegin);
1026 std::swap(dxEnd, dyEnd);
1027 }
1028
1029 for (size_t j = dyBegin; j < dyEnd; j++)
1030 {
1031 int *row = &pixelIndices[j * 4];
1032 for (size_t i = dxBegin; i < dxEnd; i++)
1033 {
1034 const size_t pixelIndex = subblockIdx * 4 + getIndex(i, j);
1035 row[i] = static_cast<int>(pixelIndex);
1036 pixelIndicesCounts[pixelIndex]++;
1037 }
1038 }
1039 }
1040
selectEndPointPCAangle::__anon4a5303920111::ETC2Block1041 void selectEndPointPCA(const int *pixelIndexCounts,
1042 const R8G8B8A8 *subblockColors,
1043 size_t numColors,
1044 int *minColorIndex,
1045 int *maxColorIndex) const
1046 {
1047 // determine color distribution
1048 int mu[3], min[3], max[3];
1049 for (int ch = 0; ch < 3; ch++)
1050 {
1051 int muv = 0;
1052 int minv = 255;
1053 int maxv = 0;
1054 for (size_t i = 0; i < numColors; i++)
1055 {
1056 const int count = pixelIndexCounts[i];
1057 if (count > 0)
1058 {
1059 const auto &pixel = subblockColors[i];
1060 if (pixel.A > 0)
1061 {
1062 // Non-transparent pixels
1063 muv += (&pixel.R)[ch] * count;
1064 minv = std::min<int>(minv, (&pixel.R)[ch]);
1065 maxv = std::max<int>(maxv, (&pixel.R)[ch]);
1066 }
1067 }
1068 }
1069
1070 mu[ch] = (muv + kNumPixelsInBlock / 2) / kNumPixelsInBlock;
1071 min[ch] = minv;
1072 max[ch] = maxv;
1073 }
1074
1075 // determine covariance matrix
1076 int cov[6] = {0, 0, 0, 0, 0, 0};
1077 for (size_t i = 0; i < numColors; i++)
1078 {
1079 const int count = pixelIndexCounts[i];
1080 if (count > 0)
1081 {
1082 const auto &pixel = subblockColors[i];
1083 if (pixel.A > 0)
1084 {
1085 int r = pixel.R - mu[0];
1086 int g = pixel.G - mu[1];
1087 int b = pixel.B - mu[2];
1088
1089 cov[0] += r * r * count;
1090 cov[1] += r * g * count;
1091 cov[2] += r * b * count;
1092 cov[3] += g * g * count;
1093 cov[4] += g * b * count;
1094 cov[5] += b * b * count;
1095 }
1096 }
1097 }
1098
1099 // Power iteration algorithm to get the eigenvalues and eigenvector
1100
1101 // Starts with diagonal vector
1102 float vfr = static_cast<float>(max[0] - min[0]);
1103 float vfg = static_cast<float>(max[1] - min[1]);
1104 float vfb = static_cast<float>(max[2] - min[2]);
1105 float eigenvalue = 0.0f;
1106
1107 constexpr size_t kPowerIterations = 4;
1108 for (size_t i = 0; i < kPowerIterations; i++)
1109 {
1110 float r = vfr * cov[0] + vfg * cov[1] + vfb * cov[2];
1111 float g = vfr * cov[1] + vfg * cov[3] + vfb * cov[4];
1112 float b = vfr * cov[2] + vfg * cov[4] + vfb * cov[5];
1113
1114 vfr = r;
1115 vfg = g;
1116 vfb = b;
1117
1118 eigenvalue = sqrt(r * r + g * g + b * b);
1119 if (eigenvalue > 0)
1120 {
1121 float invNorm = 1.0f / eigenvalue;
1122 vfr *= invNorm;
1123 vfg *= invNorm;
1124 vfb *= invNorm;
1125 }
1126 }
1127
1128 int vr, vg, vb;
1129
1130 static const float kDefaultLuminanceThreshold = 4.0f * 255;
1131 static const float kQuantizeRange = 512.0f;
1132 if (eigenvalue < kDefaultLuminanceThreshold) // too small, default to luminance
1133 {
1134 // Luminance weights defined by ITU-R Recommendation BT.601, scaled by 1000
1135 vr = 299;
1136 vg = 587;
1137 vb = 114;
1138 }
1139 else
1140 {
1141 // From the eigenvalue and eigenvector, choose the axis to project
1142 // colors on. When projecting colors we want to do integer computations
1143 // for speed, so we normalize the eigenvector to the [0, 512] range.
1144 float magn = std::max({std::abs(vfr), std::abs(vfg), std::abs(vfb)});
1145 magn = kQuantizeRange / magn;
1146 vr = static_cast<int>(vfr * magn);
1147 vg = static_cast<int>(vfg * magn);
1148 vb = static_cast<int>(vfb * magn);
1149 }
1150
1151 // Pick colors at extreme points
1152 int minD = INT_MAX;
1153 int maxD = 0;
1154 size_t minIndex = 0;
1155 size_t maxIndex = 0;
1156 for (size_t i = 0; i < numColors; i++)
1157 {
1158 const int count = pixelIndexCounts[i];
1159 if (count > 0)
1160 {
1161 const auto &pixel = subblockColors[i];
1162 if (pixel.A > 0)
1163 {
1164 int dot = pixel.R * vr + pixel.G * vg + pixel.B * vb;
1165 if (dot < minD)
1166 {
1167 minD = dot;
1168 minIndex = i;
1169 }
1170 if (dot > maxD)
1171 {
1172 maxD = dot;
1173 maxIndex = i;
1174 }
1175 }
1176 }
1177 }
1178
1179 *minColorIndex = static_cast<int>(minIndex);
1180 *maxColorIndex = static_cast<int>(maxIndex);
1181 }
1182
transcodeIndividualOrDifferentialBlockToBC1angle::__anon4a5303920111::ETC2Block1183 void transcodeIndividualOrDifferentialBlockToBC1(uint8_t *dest,
1184 size_t x,
1185 size_t y,
1186 size_t w,
1187 size_t h,
1188 int r1,
1189 int g1,
1190 int b1,
1191 int r2,
1192 int g2,
1193 int b2,
1194 const uint8_t alphaValues[4][4],
1195 bool nonOpaquePunchThroughAlpha) const
1196 {
1197 // A BC1 block has 2 endpoints, pixels is encoded as linear
1198 // interpolations of them. A ETC1/ETC2 individual or differential block
1199 // has 2 subblocks. Each subblock has one color and a modifier. We
1200 // select axis by principal component analysis (PCA) to use as
1201 // our two BC1 endpoints and then map pixels to BC1 by projecting on the
1202 // line between the two endpoints and choosing the right fraction.
1203
1204 // The goal of this algorithm is make it faster than decode ETC to RGBs
1205 // and then encode to BC. To achieve this, we only extract subblock
1206 // colors, pixel indices, and counts of each pixel indices from ETC.
1207 // With those information, we can only encode used subblock colors
1208 // to BC1, and copy the bits to the right pixels.
1209 // Fully decode and encode need to process 16 RGBA pixels. With this
1210 // algorithm, it's 8 pixels at maximum for a individual or
1211 // differential block. Saves us bandwidth and computations.
1212
1213 static const size_t kNumColors = 8;
1214
1215 const IntensityModifier *intensityModifier =
1216 nonOpaquePunchThroughAlpha ? intensityModifierNonOpaque : intensityModifierDefault;
1217
1218 // Compute the colors that pixels can have in each subblock both for
1219 // the decoding of the RGBA data and BC1 encoding
1220 R8G8B8A8 subblockColors[kNumColors];
1221 for (size_t modifierIdx = 0; modifierIdx < 4; modifierIdx++)
1222 {
1223 if (nonOpaquePunchThroughAlpha && (modifierIdx == 2))
1224 {
1225 // In ETC opaque punch through formats, individual and
1226 // differential blocks take index 2 as transparent pixel.
1227 // Thus we don't need to compute its color, just assign it
1228 // as black.
1229 subblockColors[modifierIdx] = createRGBA(0, 0, 0, 0);
1230 subblockColors[4 + modifierIdx] = createRGBA(0, 0, 0, 0);
1231 }
1232 else
1233 {
1234 const int i1 = intensityModifier[u.idht.mode.idm.cw1][modifierIdx];
1235 subblockColors[modifierIdx] = createRGBA(r1 + i1, g1 + i1, b1 + i1);
1236
1237 const int i2 = intensityModifier[u.idht.mode.idm.cw2][modifierIdx];
1238 subblockColors[4 + modifierIdx] = createRGBA(r2 + i2, g2 + i2, b2 + i2);
1239 }
1240 }
1241
1242 int pixelIndices[kNumPixelsInBlock];
1243 int pixelIndexCounts[kNumColors] = {0};
1244 // Extract pixel indices from a ETC block.
1245 for (size_t blockIdx = 0; blockIdx < 2; blockIdx++)
1246 {
1247 extractPixelIndices(pixelIndices, pixelIndexCounts, x, y, w, h, u.idht.mode.idm.flipbit,
1248 blockIdx);
1249 }
1250
1251 int minColorIndex, maxColorIndex;
1252 selectEndPointPCA(pixelIndexCounts, subblockColors, kNumColors, &minColorIndex,
1253 &maxColorIndex);
1254
1255 packBC1(dest, pixelIndices, pixelIndexCounts, subblockColors, kNumColors, minColorIndex,
1256 maxColorIndex, nonOpaquePunchThroughAlpha);
1257 }
1258
transcodeTBlockToBC1angle::__anon4a5303920111::ETC2Block1259 void transcodeTBlockToBC1(uint8_t *dest,
1260 size_t x,
1261 size_t y,
1262 size_t w,
1263 size_t h,
1264 const uint8_t alphaValues[4][4],
1265 bool nonOpaquePunchThroughAlpha) const
1266 {
1267 static const size_t kNumColors = 4;
1268
1269 // Table C.8, distance index for T and H modes
1270 const auto &block = u.idht.mode.tm;
1271
1272 int r1 = extend_4to8bits(block.TR1a << 2 | block.TR1b);
1273 int g1 = extend_4to8bits(block.TG1);
1274 int b1 = extend_4to8bits(block.TB1);
1275 int r2 = extend_4to8bits(block.TR2);
1276 int g2 = extend_4to8bits(block.TG2);
1277 int b2 = extend_4to8bits(block.TB2);
1278
1279 static int distance[8] = {3, 6, 11, 16, 23, 32, 41, 64};
1280 const int d = distance[block.Tda << 1 | block.Tdb];
1281
1282 // In ETC opaque punch through formats, index == 2 means transparent pixel.
1283 // Thus we don't need to compute its color, just assign it as black.
1284 const R8G8B8A8 paintColors[kNumColors] = {
1285 createRGBA(r1, g1, b1),
1286 createRGBA(r2 + d, g2 + d, b2 + d),
1287 nonOpaquePunchThroughAlpha ? createRGBA(0, 0, 0, 0) : createRGBA(r2, g2, b2),
1288 createRGBA(r2 - d, g2 - d, b2 - d),
1289 };
1290
1291 int pixelIndices[kNumPixelsInBlock];
1292 int pixelIndexCounts[kNumColors] = {0};
1293 for (size_t j = 0; j < 4; j++)
1294 {
1295 int *row = &pixelIndices[j * 4];
1296 for (size_t i = 0; i < 4; i++)
1297 {
1298 const size_t pixelIndex = getIndex(i, j);
1299 row[i] = static_cast<int>(pixelIndex);
1300 pixelIndexCounts[pixelIndex]++;
1301 }
1302 }
1303
1304 int minColorIndex, maxColorIndex;
1305 selectEndPointPCA(pixelIndexCounts, paintColors, kNumColors, &minColorIndex,
1306 &maxColorIndex);
1307
1308 packBC1(dest, pixelIndices, pixelIndexCounts, paintColors, kNumColors, minColorIndex,
1309 maxColorIndex, nonOpaquePunchThroughAlpha);
1310 }
1311
transcodeHBlockToBC1angle::__anon4a5303920111::ETC2Block1312 void transcodeHBlockToBC1(uint8_t *dest,
1313 size_t x,
1314 size_t y,
1315 size_t w,
1316 size_t h,
1317 const uint8_t alphaValues[4][4],
1318 bool nonOpaquePunchThroughAlpha) const
1319 {
1320 static const size_t kNumColors = 4;
1321
1322 // Table C.8, distance index for T and H modes
1323 const auto &block = u.idht.mode.hm;
1324
1325 int r1 = extend_4to8bits(block.HR1);
1326 int g1 = extend_4to8bits(block.HG1a << 1 | block.HG1b);
1327 int b1 = extend_4to8bits(block.HB1a << 3 | block.HB1b << 1 | block.HB1c);
1328 int r2 = extend_4to8bits(block.HR2);
1329 int g2 = extend_4to8bits(block.HG2a << 1 | block.HG2b);
1330 int b2 = extend_4to8bits(block.HB2);
1331
1332 static const int distance[8] = {3, 6, 11, 16, 23, 32, 41, 64};
1333 const int orderingTrickBit =
1334 ((r1 << 16 | g1 << 8 | b1) >= (r2 << 16 | g2 << 8 | b2) ? 1 : 0);
1335 const int d = distance[(block.Hda << 2) | (block.Hdb << 1) | orderingTrickBit];
1336
1337 // In ETC opaque punch through formats, index == 2 means transparent pixel.
1338 // Thus we don't need to compute its color, just assign it as black.
1339 const R8G8B8A8 paintColors[kNumColors] = {
1340 createRGBA(r1 + d, g1 + d, b1 + d),
1341 createRGBA(r1 - d, g1 - d, b1 - d),
1342 nonOpaquePunchThroughAlpha ? createRGBA(0, 0, 0, 0)
1343 : createRGBA(r2 + d, g2 + d, b2 + d),
1344 createRGBA(r2 - d, g2 - d, b2 - d),
1345 };
1346
1347 int pixelIndices[kNumPixelsInBlock];
1348 int pixelIndexCounts[kNumColors] = {0};
1349 for (size_t j = 0; j < 4; j++)
1350 {
1351 int *row = &pixelIndices[j * 4];
1352 for (size_t i = 0; i < 4; i++)
1353 {
1354 const size_t pixelIndex = getIndex(i, j);
1355 row[i] = static_cast<int>(pixelIndex);
1356 pixelIndexCounts[pixelIndex]++;
1357 }
1358 }
1359
1360 int minColorIndex, maxColorIndex;
1361 selectEndPointPCA(pixelIndexCounts, paintColors, kNumColors, &minColorIndex,
1362 &maxColorIndex);
1363
1364 packBC1(dest, pixelIndices, pixelIndexCounts, paintColors, kNumColors, minColorIndex,
1365 maxColorIndex, nonOpaquePunchThroughAlpha);
1366 }
1367
transcodePlanarBlockToBC1angle::__anon4a5303920111::ETC2Block1368 void transcodePlanarBlockToBC1(uint8_t *dest,
1369 size_t x,
1370 size_t y,
1371 size_t w,
1372 size_t h,
1373 const uint8_t alphaValues[4][4]) const
1374 {
1375 static const size_t kNumColors = kNumPixelsInBlock;
1376
1377 R8G8B8A8 rgbaBlock[kNumColors];
1378 decodePlanarBlock(reinterpret_cast<uint8_t *>(rgbaBlock), x, y, w, h, sizeof(R8G8B8A8) * 4,
1379 alphaValues);
1380
1381 // Planar block doesn't have a color table, fill indices as full
1382 int pixelIndices[kNumPixelsInBlock] = {0, 1, 2, 3, 4, 5, 6, 7,
1383 8, 9, 10, 11, 12, 13, 14, 15};
1384 int pixelIndexCounts[kNumColors] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
1385
1386 int minColorIndex, maxColorIndex;
1387 selectEndPointPCA(pixelIndexCounts, rgbaBlock, kNumColors, &minColorIndex, &maxColorIndex);
1388
1389 packBC1(dest, pixelIndices, pixelIndexCounts, rgbaBlock, kNumColors, minColorIndex,
1390 maxColorIndex, false);
1391 }
1392
1393 // Single channel utility functions
getSingleEACChannelangle::__anon4a5303920111::ETC2Block1394 int getSingleEACChannel(size_t x, size_t y, bool isSigned) const
1395 {
1396 int codeword = isSigned ? u.scblk.base_codeword.s : u.scblk.base_codeword.us;
1397 int multiplier = (u.scblk.multiplier == 0) ? 1 : u.scblk.multiplier * 8;
1398 return codeword * 8 + 4 + getSingleChannelModifier(x, y) * multiplier;
1399 }
1400
getSingleETC2Channelangle::__anon4a5303920111::ETC2Block1401 int getSingleETC2Channel(size_t x, size_t y, bool isSigned) const
1402 {
1403 int codeword = isSigned ? u.scblk.base_codeword.s : u.scblk.base_codeword.us;
1404 return codeword + getSingleChannelModifier(x, y) * u.scblk.multiplier;
1405 }
1406
getSingleChannelIndexangle::__anon4a5303920111::ETC2Block1407 int getSingleChannelIndex(size_t x, size_t y) const
1408 {
1409 ASSERT(x < 4 && y < 4);
1410
1411 // clang-format off
1412 switch (x * 4 + y)
1413 {
1414 case 0: return u.scblk.ma;
1415 case 1: return u.scblk.mb;
1416 case 2: return u.scblk.mc1 << 1 | u.scblk.mc2;
1417 case 3: return u.scblk.md;
1418 case 4: return u.scblk.me;
1419 case 5: return u.scblk.mf1 << 2 | u.scblk.mf2;
1420 case 6: return u.scblk.mg;
1421 case 7: return u.scblk.mh;
1422 case 8: return u.scblk.mi;
1423 case 9: return u.scblk.mj;
1424 case 10: return u.scblk.mk1 << 1 | u.scblk.mk2;
1425 case 11: return u.scblk.ml;
1426 case 12: return u.scblk.mm;
1427 case 13: return u.scblk.mn1 << 2 | u.scblk.mn2;
1428 case 14: return u.scblk.mo;
1429 case 15: return u.scblk.mp;
1430 default: UNREACHABLE(); return 0;
1431 }
1432 // clang-format on
1433 }
1434
getSingleChannelModifierangle::__anon4a5303920111::ETC2Block1435 int getSingleChannelModifier(size_t x, size_t y) const
1436 {
1437 // clang-format off
1438 static const int modifierTable[16][8] =
1439 {
1440 { -3, -6, -9, -15, 2, 5, 8, 14 },
1441 { -3, -7, -10, -13, 2, 6, 9, 12 },
1442 { -2, -5, -8, -13, 1, 4, 7, 12 },
1443 { -2, -4, -6, -13, 1, 3, 5, 12 },
1444 { -3, -6, -8, -12, 2, 5, 7, 11 },
1445 { -3, -7, -9, -11, 2, 6, 8, 10 },
1446 { -4, -7, -8, -11, 3, 6, 7, 10 },
1447 { -3, -5, -8, -11, 2, 4, 7, 10 },
1448 { -2, -6, -8, -10, 1, 5, 7, 9 },
1449 { -2, -5, -8, -10, 1, 4, 7, 9 },
1450 { -2, -4, -8, -10, 1, 3, 7, 9 },
1451 { -2, -5, -7, -10, 1, 4, 6, 9 },
1452 { -3, -4, -7, -10, 2, 3, 6, 9 },
1453 { -1, -2, -3, -10, 0, 1, 2, 9 },
1454 { -4, -6, -8, -9, 3, 5, 7, 8 },
1455 { -3, -5, -7, -9, 2, 4, 6, 8 }
1456 };
1457 // clang-format on
1458
1459 return modifierTable[u.scblk.table_index][getSingleChannelIndex(x, y)];
1460 }
1461 };
1462
1463 // clang-format off
1464 static const uint8_t DefaultETCAlphaValues[4][4] =
1465 {
1466 { 255, 255, 255, 255 },
1467 { 255, 255, 255, 255 },
1468 { 255, 255, 255, 255 },
1469 { 255, 255, 255, 255 },
1470 };
1471
1472 // clang-format on
LoadR11EACToR8(const ImageLoadContext & context,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)1473 void LoadR11EACToR8(const ImageLoadContext &context,
1474 size_t width,
1475 size_t height,
1476 size_t depth,
1477 const uint8_t *input,
1478 size_t inputRowPitch,
1479 size_t inputDepthPitch,
1480 uint8_t *output,
1481 size_t outputRowPitch,
1482 size_t outputDepthPitch,
1483 bool isSigned)
1484 {
1485 for (size_t z = 0; z < depth; z++)
1486 {
1487 for (size_t y = 0; y < height; y += 4)
1488 {
1489 const ETC2Block *sourceRow =
1490 priv::OffsetDataPointer<ETC2Block>(input, y / 4, z, inputRowPitch, inputDepthPitch);
1491 uint8_t *destRow =
1492 priv::OffsetDataPointer<uint8_t>(output, y, z, outputRowPitch, outputDepthPitch);
1493
1494 for (size_t x = 0; x < width; x += 4)
1495 {
1496 const ETC2Block *sourceBlock = sourceRow + (x / 4);
1497 uint8_t *destPixels = destRow + x;
1498
1499 sourceBlock->decodeAsSingleETC2Channel(destPixels, x, y, width, height, 1,
1500 outputRowPitch, isSigned);
1501 }
1502 }
1503 }
1504 }
1505
LoadRG11EACToRG8(const ImageLoadContext & context,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)1506 void LoadRG11EACToRG8(const ImageLoadContext &context,
1507 size_t width,
1508 size_t height,
1509 size_t depth,
1510 const uint8_t *input,
1511 size_t inputRowPitch,
1512 size_t inputDepthPitch,
1513 uint8_t *output,
1514 size_t outputRowPitch,
1515 size_t outputDepthPitch,
1516 bool isSigned)
1517 {
1518 for (size_t z = 0; z < depth; z++)
1519 {
1520 for (size_t y = 0; y < height; y += 4)
1521 {
1522 const ETC2Block *sourceRow =
1523 priv::OffsetDataPointer<ETC2Block>(input, y / 4, z, inputRowPitch, inputDepthPitch);
1524 uint8_t *destRow =
1525 priv::OffsetDataPointer<uint8_t>(output, y, z, outputRowPitch, outputDepthPitch);
1526
1527 for (size_t x = 0; x < width; x += 4)
1528 {
1529 uint8_t *destPixelsRed = destRow + (x * 2);
1530 const ETC2Block *sourceBlockRed = sourceRow + (x / 2);
1531 sourceBlockRed->decodeAsSingleETC2Channel(destPixelsRed, x, y, width, height, 2,
1532 outputRowPitch, isSigned);
1533
1534 uint8_t *destPixelsGreen = destPixelsRed + 1;
1535 const ETC2Block *sourceBlockGreen = sourceBlockRed + 1;
1536 sourceBlockGreen->decodeAsSingleETC2Channel(destPixelsGreen, x, y, width, height, 2,
1537 outputRowPitch, isSigned);
1538 }
1539 }
1540 }
1541 }
1542
LoadR11EACToR16(const ImageLoadContext & context,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,bool isFloat)1543 void LoadR11EACToR16(const ImageLoadContext &context,
1544 size_t width,
1545 size_t height,
1546 size_t depth,
1547 const uint8_t *input,
1548 size_t inputRowPitch,
1549 size_t inputDepthPitch,
1550 uint8_t *output,
1551 size_t outputRowPitch,
1552 size_t outputDepthPitch,
1553 bool isSigned,
1554 bool isFloat)
1555 {
1556 for (size_t z = 0; z < depth; z++)
1557 {
1558 for (size_t y = 0; y < height; y += 4)
1559 {
1560 const ETC2Block *sourceRow =
1561 priv::OffsetDataPointer<ETC2Block>(input, y / 4, z, inputRowPitch, inputDepthPitch);
1562 uint16_t *destRow =
1563 priv::OffsetDataPointer<uint16_t>(output, y, z, outputRowPitch, outputDepthPitch);
1564
1565 for (size_t x = 0; x < width; x += 4)
1566 {
1567 const ETC2Block *sourceBlock = sourceRow + (x / 4);
1568 uint16_t *destPixels = destRow + x;
1569
1570 sourceBlock->decodeAsSingleEACChannel(destPixels, x, y, width, height, 1,
1571 outputRowPitch, isSigned, isFloat);
1572 }
1573 }
1574 }
1575 }
1576
LoadRG11EACToRG16(const ImageLoadContext & context,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,bool isFloat)1577 void LoadRG11EACToRG16(const ImageLoadContext &context,
1578 size_t width,
1579 size_t height,
1580 size_t depth,
1581 const uint8_t *input,
1582 size_t inputRowPitch,
1583 size_t inputDepthPitch,
1584 uint8_t *output,
1585 size_t outputRowPitch,
1586 size_t outputDepthPitch,
1587 bool isSigned,
1588 bool isFloat)
1589 {
1590 for (size_t z = 0; z < depth; z++)
1591 {
1592 for (size_t y = 0; y < height; y += 4)
1593 {
1594 const ETC2Block *sourceRow =
1595 priv::OffsetDataPointer<ETC2Block>(input, y / 4, z, inputRowPitch, inputDepthPitch);
1596 uint16_t *destRow =
1597 priv::OffsetDataPointer<uint16_t>(output, y, z, outputRowPitch, outputDepthPitch);
1598
1599 for (size_t x = 0; x < width; x += 4)
1600 {
1601 uint16_t *destPixelsRed = destRow + (x * 2);
1602 const ETC2Block *sourceBlockRed = sourceRow + (x / 2);
1603 sourceBlockRed->decodeAsSingleEACChannel(destPixelsRed, x, y, width, height, 2,
1604 outputRowPitch, isSigned, isFloat);
1605
1606 uint16_t *destPixelsGreen = destPixelsRed + 1;
1607 const ETC2Block *sourceBlockGreen = sourceBlockRed + 1;
1608 sourceBlockGreen->decodeAsSingleEACChannel(destPixelsGreen, x, y, width, height, 2,
1609 outputRowPitch, isSigned, isFloat);
1610 }
1611 }
1612 }
1613 }
1614
LoadETC2RGB8ToRGBA8(const ImageLoadContext & context,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)1615 void LoadETC2RGB8ToRGBA8(const ImageLoadContext &context,
1616 size_t width,
1617 size_t height,
1618 size_t depth,
1619 const uint8_t *input,
1620 size_t inputRowPitch,
1621 size_t inputDepthPitch,
1622 uint8_t *output,
1623 size_t outputRowPitch,
1624 size_t outputDepthPitch,
1625 bool punchthroughAlpha)
1626 {
1627 for (size_t z = 0; z < depth; z++)
1628 {
1629 for (size_t y = 0; y < height; y += 4)
1630 {
1631 const ETC2Block *sourceRow =
1632 priv::OffsetDataPointer<ETC2Block>(input, y / 4, z, inputRowPitch, inputDepthPitch);
1633 uint8_t *destRow =
1634 priv::OffsetDataPointer<uint8_t>(output, y, z, outputRowPitch, outputDepthPitch);
1635
1636 for (size_t x = 0; x < width; x += 4)
1637 {
1638 const ETC2Block *sourceBlock = sourceRow + (x / 4);
1639 uint8_t *destPixels = destRow + (x * 4);
1640
1641 sourceBlock->decodeAsRGB(destPixels, x, y, width, height, outputRowPitch,
1642 DefaultETCAlphaValues, punchthroughAlpha);
1643 }
1644 }
1645 }
1646 }
1647
LoadETC2RGB8ToBC1(const ImageLoadContext & context,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)1648 void LoadETC2RGB8ToBC1(const ImageLoadContext &context,
1649 size_t width,
1650 size_t height,
1651 size_t depth,
1652 const uint8_t *input,
1653 size_t inputRowPitch,
1654 size_t inputDepthPitch,
1655 uint8_t *output,
1656 size_t outputRowPitch,
1657 size_t outputDepthPitch,
1658 bool punchthroughAlpha)
1659 {
1660 for (size_t z = 0; z < depth; z++)
1661 {
1662 for (size_t y = 0; y < height; y += 4)
1663 {
1664 const ETC2Block *sourceRow =
1665 priv::OffsetDataPointer<ETC2Block>(input, y / 4, z, inputRowPitch, inputDepthPitch);
1666 uint8_t *destRow = priv::OffsetDataPointer<uint8_t>(output, y / 4, z, outputRowPitch,
1667 outputDepthPitch);
1668
1669 for (size_t x = 0; x < width; x += 4)
1670 {
1671 const ETC2Block *sourceBlock = sourceRow + (x / 4);
1672 uint8_t *destPixels = destRow + (x * 2);
1673
1674 sourceBlock->transcodeAsBC1(destPixels, x, y, width, height, DefaultETCAlphaValues,
1675 punchthroughAlpha);
1676 }
1677 }
1678 }
1679 }
1680
LoadETC2RGBA8ToBC3(const ImageLoadContext & context,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,bool isSigned)1681 void LoadETC2RGBA8ToBC3(const ImageLoadContext &context,
1682 size_t width,
1683 size_t height,
1684 size_t depth,
1685 const uint8_t *input,
1686 size_t inputRowPitch,
1687 size_t inputDepthPitch,
1688 uint8_t *output,
1689 size_t outputRowPitch,
1690 size_t outputDepthPitch,
1691 bool punchthroughAlpha,
1692 bool isSigned)
1693 {
1694 for (size_t z = 0; z < depth; z++)
1695 {
1696 for (size_t y = 0; y < height; y += 4)
1697 {
1698 const ETC2Block *sourceRow =
1699 priv::OffsetDataPointer<ETC2Block>(input, y / 4, z, inputRowPitch, inputDepthPitch);
1700 uint8_t *destRow = priv::OffsetDataPointer<uint8_t>(output, y / 4, z, outputRowPitch,
1701 outputDepthPitch);
1702
1703 for (size_t x = 0; x < width; x += 4)
1704 {
1705 const ETC2Block *sourceAlphaBlock = sourceRow + (x / 4) * 2;
1706 uint8_t *destAlphaPixels = destRow + (x * 4);
1707
1708 const ETC2Block *sourceRgbBlock = sourceAlphaBlock + 1;
1709 uint8_t *destRgbPixels = destAlphaPixels + 8;
1710
1711 sourceRgbBlock->transcodeAsBC1(destRgbPixels, x, y, width, height,
1712 DefaultETCAlphaValues, punchthroughAlpha);
1713
1714 sourceAlphaBlock->transcodeAsBC4(destAlphaPixels, x, y, width, height, isSigned);
1715 }
1716 }
1717 }
1718 }
1719
LoadETC2RGBA8ToRGBA8(const ImageLoadContext & context,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)1720 void LoadETC2RGBA8ToRGBA8(const ImageLoadContext &context,
1721 size_t width,
1722 size_t height,
1723 size_t depth,
1724 const uint8_t *input,
1725 size_t inputRowPitch,
1726 size_t inputDepthPitch,
1727 uint8_t *output,
1728 size_t outputRowPitch,
1729 size_t outputDepthPitch,
1730 bool srgb)
1731 {
1732 uint8_t decodedAlphaValues[4][4];
1733
1734 for (size_t z = 0; z < depth; z++)
1735 {
1736 for (size_t y = 0; y < height; y += 4)
1737 {
1738 const ETC2Block *sourceRow =
1739 priv::OffsetDataPointer<ETC2Block>(input, y / 4, z, inputRowPitch, inputDepthPitch);
1740 uint8_t *destRow =
1741 priv::OffsetDataPointer<uint8_t>(output, y, z, outputRowPitch, outputDepthPitch);
1742
1743 for (size_t x = 0; x < width; x += 4)
1744 {
1745 const ETC2Block *sourceBlockAlpha = sourceRow + (x / 2);
1746 sourceBlockAlpha->decodeAsSingleETC2Channel(
1747 reinterpret_cast<uint8_t *>(decodedAlphaValues), x, y, width, height, 1, 4,
1748 false);
1749
1750 uint8_t *destPixels = destRow + (x * 4);
1751 const ETC2Block *sourceBlockRGB = sourceBlockAlpha + 1;
1752 sourceBlockRGB->decodeAsRGB(destPixels, x, y, width, height, outputRowPitch,
1753 decodedAlphaValues, false);
1754 }
1755 }
1756 }
1757 }
1758
1759 } // anonymous namespace
1760
LoadETC1RGB8ToRGBA8(const ImageLoadContext & context,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)1761 void LoadETC1RGB8ToRGBA8(const ImageLoadContext &context,
1762 size_t width,
1763 size_t height,
1764 size_t depth,
1765 const uint8_t *input,
1766 size_t inputRowPitch,
1767 size_t inputDepthPitch,
1768 uint8_t *output,
1769 size_t outputRowPitch,
1770 size_t outputDepthPitch)
1771 {
1772 LoadETC2RGB8ToRGBA8(context, width, height, depth, input, inputRowPitch, inputDepthPitch,
1773 output, outputRowPitch, outputDepthPitch, false);
1774 }
1775
LoadETC1RGB8ToBC1(const ImageLoadContext & context,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)1776 void LoadETC1RGB8ToBC1(const ImageLoadContext &context,
1777 size_t width,
1778 size_t height,
1779 size_t depth,
1780 const uint8_t *input,
1781 size_t inputRowPitch,
1782 size_t inputDepthPitch,
1783 uint8_t *output,
1784 size_t outputRowPitch,
1785 size_t outputDepthPitch)
1786 {
1787 LoadETC2RGB8ToBC1(context, width, height, depth, input, inputRowPitch, inputDepthPitch, output,
1788 outputRowPitch, outputDepthPitch, false);
1789 }
1790
LoadEACR11ToR8(const ImageLoadContext & context,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)1791 void LoadEACR11ToR8(const ImageLoadContext &context,
1792 size_t width,
1793 size_t height,
1794 size_t depth,
1795 const uint8_t *input,
1796 size_t inputRowPitch,
1797 size_t inputDepthPitch,
1798 uint8_t *output,
1799 size_t outputRowPitch,
1800 size_t outputDepthPitch)
1801 {
1802 LoadR11EACToR8(context, width, height, depth, input, inputRowPitch, inputDepthPitch, output,
1803 outputRowPitch, outputDepthPitch, false);
1804 }
1805
LoadEACR11SToR8(const ImageLoadContext & context,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)1806 void LoadEACR11SToR8(const ImageLoadContext &context,
1807 size_t width,
1808 size_t height,
1809 size_t depth,
1810 const uint8_t *input,
1811 size_t inputRowPitch,
1812 size_t inputDepthPitch,
1813 uint8_t *output,
1814 size_t outputRowPitch,
1815 size_t outputDepthPitch)
1816 {
1817 LoadR11EACToR8(context, width, height, depth, input, inputRowPitch, inputDepthPitch, output,
1818 outputRowPitch, outputDepthPitch, true);
1819 }
1820
LoadEACRG11ToRG8(const ImageLoadContext & context,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)1821 void LoadEACRG11ToRG8(const ImageLoadContext &context,
1822 size_t width,
1823 size_t height,
1824 size_t depth,
1825 const uint8_t *input,
1826 size_t inputRowPitch,
1827 size_t inputDepthPitch,
1828 uint8_t *output,
1829 size_t outputRowPitch,
1830 size_t outputDepthPitch)
1831 {
1832 LoadRG11EACToRG8(context, width, height, depth, input, inputRowPitch, inputDepthPitch, output,
1833 outputRowPitch, outputDepthPitch, false);
1834 }
1835
LoadEACRG11SToRG8(const ImageLoadContext & context,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)1836 void LoadEACRG11SToRG8(const ImageLoadContext &context,
1837 size_t width,
1838 size_t height,
1839 size_t depth,
1840 const uint8_t *input,
1841 size_t inputRowPitch,
1842 size_t inputDepthPitch,
1843 uint8_t *output,
1844 size_t outputRowPitch,
1845 size_t outputDepthPitch)
1846 {
1847 LoadRG11EACToRG8(context, width, height, depth, input, inputRowPitch, inputDepthPitch, output,
1848 outputRowPitch, outputDepthPitch, true);
1849 }
1850
LoadEACR11ToR16(const ImageLoadContext & context,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)1851 void LoadEACR11ToR16(const ImageLoadContext &context,
1852 size_t width,
1853 size_t height,
1854 size_t depth,
1855 const uint8_t *input,
1856 size_t inputRowPitch,
1857 size_t inputDepthPitch,
1858 uint8_t *output,
1859 size_t outputRowPitch,
1860 size_t outputDepthPitch)
1861 {
1862 LoadR11EACToR16(context, width, height, depth, input, inputRowPitch, inputDepthPitch, output,
1863 outputRowPitch, outputDepthPitch, false, false);
1864 }
1865
LoadEACR11SToR16(const ImageLoadContext & context,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)1866 void LoadEACR11SToR16(const ImageLoadContext &context,
1867 size_t width,
1868 size_t height,
1869 size_t depth,
1870 const uint8_t *input,
1871 size_t inputRowPitch,
1872 size_t inputDepthPitch,
1873 uint8_t *output,
1874 size_t outputRowPitch,
1875 size_t outputDepthPitch)
1876 {
1877 LoadR11EACToR16(context, width, height, depth, input, inputRowPitch, inputDepthPitch, output,
1878 outputRowPitch, outputDepthPitch, true, false);
1879 }
1880
LoadEACRG11ToRG16(const ImageLoadContext & context,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)1881 void LoadEACRG11ToRG16(const ImageLoadContext &context,
1882 size_t width,
1883 size_t height,
1884 size_t depth,
1885 const uint8_t *input,
1886 size_t inputRowPitch,
1887 size_t inputDepthPitch,
1888 uint8_t *output,
1889 size_t outputRowPitch,
1890 size_t outputDepthPitch)
1891 {
1892 LoadRG11EACToRG16(context, width, height, depth, input, inputRowPitch, inputDepthPitch, output,
1893 outputRowPitch, outputDepthPitch, false, false);
1894 }
1895
LoadEACRG11SToRG16(const ImageLoadContext & context,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)1896 void LoadEACRG11SToRG16(const ImageLoadContext &context,
1897 size_t width,
1898 size_t height,
1899 size_t depth,
1900 const uint8_t *input,
1901 size_t inputRowPitch,
1902 size_t inputDepthPitch,
1903 uint8_t *output,
1904 size_t outputRowPitch,
1905 size_t outputDepthPitch)
1906 {
1907 LoadRG11EACToRG16(context, width, height, depth, input, inputRowPitch, inputDepthPitch, output,
1908 outputRowPitch, outputDepthPitch, true, false);
1909 }
1910
LoadEACR11ToR16F(const ImageLoadContext & context,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)1911 void LoadEACR11ToR16F(const ImageLoadContext &context,
1912 size_t width,
1913 size_t height,
1914 size_t depth,
1915 const uint8_t *input,
1916 size_t inputRowPitch,
1917 size_t inputDepthPitch,
1918 uint8_t *output,
1919 size_t outputRowPitch,
1920 size_t outputDepthPitch)
1921 {
1922 LoadR11EACToR16(context, width, height, depth, input, inputRowPitch, inputDepthPitch, output,
1923 outputRowPitch, outputDepthPitch, false, true);
1924 }
1925
LoadEACR11SToR16F(const ImageLoadContext & context,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)1926 void LoadEACR11SToR16F(const ImageLoadContext &context,
1927 size_t width,
1928 size_t height,
1929 size_t depth,
1930 const uint8_t *input,
1931 size_t inputRowPitch,
1932 size_t inputDepthPitch,
1933 uint8_t *output,
1934 size_t outputRowPitch,
1935 size_t outputDepthPitch)
1936 {
1937 LoadR11EACToR16(context, width, height, depth, input, inputRowPitch, inputDepthPitch, output,
1938 outputRowPitch, outputDepthPitch, true, true);
1939 }
1940
LoadEACRG11ToRG16F(const ImageLoadContext & context,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)1941 void LoadEACRG11ToRG16F(const ImageLoadContext &context,
1942 size_t width,
1943 size_t height,
1944 size_t depth,
1945 const uint8_t *input,
1946 size_t inputRowPitch,
1947 size_t inputDepthPitch,
1948 uint8_t *output,
1949 size_t outputRowPitch,
1950 size_t outputDepthPitch)
1951 {
1952 LoadRG11EACToRG16(context, width, height, depth, input, inputRowPitch, inputDepthPitch, output,
1953 outputRowPitch, outputDepthPitch, false, true);
1954 }
1955
LoadEACRG11SToRG16F(const ImageLoadContext & context,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)1956 void LoadEACRG11SToRG16F(const ImageLoadContext &context,
1957 size_t width,
1958 size_t height,
1959 size_t depth,
1960 const uint8_t *input,
1961 size_t inputRowPitch,
1962 size_t inputDepthPitch,
1963 uint8_t *output,
1964 size_t outputRowPitch,
1965 size_t outputDepthPitch)
1966 {
1967 LoadRG11EACToRG16(context, width, height, depth, input, inputRowPitch, inputDepthPitch, output,
1968 outputRowPitch, outputDepthPitch, true, true);
1969 }
1970
LoadETC2RGB8ToRGBA8(const ImageLoadContext & context,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)1971 void LoadETC2RGB8ToRGBA8(const ImageLoadContext &context,
1972 size_t width,
1973 size_t height,
1974 size_t depth,
1975 const uint8_t *input,
1976 size_t inputRowPitch,
1977 size_t inputDepthPitch,
1978 uint8_t *output,
1979 size_t outputRowPitch,
1980 size_t outputDepthPitch)
1981 {
1982 LoadETC2RGB8ToRGBA8(context, width, height, depth, input, inputRowPitch, inputDepthPitch,
1983 output, outputRowPitch, outputDepthPitch, false);
1984 }
1985
LoadETC2RGB8ToBC1(const ImageLoadContext & context,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)1986 void LoadETC2RGB8ToBC1(const ImageLoadContext &context,
1987 size_t width,
1988 size_t height,
1989 size_t depth,
1990 const uint8_t *input,
1991 size_t inputRowPitch,
1992 size_t inputDepthPitch,
1993 uint8_t *output,
1994 size_t outputRowPitch,
1995 size_t outputDepthPitch)
1996 {
1997 LoadETC2RGB8ToBC1(context, width, height, depth, input, inputRowPitch, inputDepthPitch, output,
1998 outputRowPitch, outputDepthPitch, false);
1999 }
2000
LoadETC2SRGB8ToRGBA8(const ImageLoadContext & context,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)2001 void LoadETC2SRGB8ToRGBA8(const ImageLoadContext &context,
2002 size_t width,
2003 size_t height,
2004 size_t depth,
2005 const uint8_t *input,
2006 size_t inputRowPitch,
2007 size_t inputDepthPitch,
2008 uint8_t *output,
2009 size_t outputRowPitch,
2010 size_t outputDepthPitch)
2011 {
2012 LoadETC2RGB8ToRGBA8(context, width, height, depth, input, inputRowPitch, inputDepthPitch,
2013 output, outputRowPitch, outputDepthPitch, false);
2014 }
2015
LoadETC2SRGB8ToBC1(const ImageLoadContext & context,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)2016 void LoadETC2SRGB8ToBC1(const ImageLoadContext &context,
2017 size_t width,
2018 size_t height,
2019 size_t depth,
2020 const uint8_t *input,
2021 size_t inputRowPitch,
2022 size_t inputDepthPitch,
2023 uint8_t *output,
2024 size_t outputRowPitch,
2025 size_t outputDepthPitch)
2026 {
2027 LoadETC2RGB8ToBC1(context, width, height, depth, input, inputRowPitch, inputDepthPitch, output,
2028 outputRowPitch, outputDepthPitch, false);
2029 }
2030
LoadETC2RGB8A1ToRGBA8(const ImageLoadContext & context,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)2031 void LoadETC2RGB8A1ToRGBA8(const ImageLoadContext &context,
2032 size_t width,
2033 size_t height,
2034 size_t depth,
2035 const uint8_t *input,
2036 size_t inputRowPitch,
2037 size_t inputDepthPitch,
2038 uint8_t *output,
2039 size_t outputRowPitch,
2040 size_t outputDepthPitch)
2041 {
2042 LoadETC2RGB8ToRGBA8(context, width, height, depth, input, inputRowPitch, inputDepthPitch,
2043 output, outputRowPitch, outputDepthPitch, true);
2044 }
2045
LoadETC2RGB8A1ToBC1(const ImageLoadContext & context,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)2046 void LoadETC2RGB8A1ToBC1(const ImageLoadContext &context,
2047 size_t width,
2048 size_t height,
2049 size_t depth,
2050 const uint8_t *input,
2051 size_t inputRowPitch,
2052 size_t inputDepthPitch,
2053 uint8_t *output,
2054 size_t outputRowPitch,
2055 size_t outputDepthPitch)
2056 {
2057 LoadETC2RGB8ToBC1(context, width, height, depth, input, inputRowPitch, inputDepthPitch, output,
2058 outputRowPitch, outputDepthPitch, true);
2059 }
2060
LoadETC2SRGB8A1ToRGBA8(const ImageLoadContext & context,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)2061 void LoadETC2SRGB8A1ToRGBA8(const ImageLoadContext &context,
2062 size_t width,
2063 size_t height,
2064 size_t depth,
2065 const uint8_t *input,
2066 size_t inputRowPitch,
2067 size_t inputDepthPitch,
2068 uint8_t *output,
2069 size_t outputRowPitch,
2070 size_t outputDepthPitch)
2071 {
2072 LoadETC2RGB8ToRGBA8(context, width, height, depth, input, inputRowPitch, inputDepthPitch,
2073 output, outputRowPitch, outputDepthPitch, true);
2074 }
2075
LoadETC2SRGB8A1ToBC1(const ImageLoadContext & context,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)2076 void LoadETC2SRGB8A1ToBC1(const ImageLoadContext &context,
2077 size_t width,
2078 size_t height,
2079 size_t depth,
2080 const uint8_t *input,
2081 size_t inputRowPitch,
2082 size_t inputDepthPitch,
2083 uint8_t *output,
2084 size_t outputRowPitch,
2085 size_t outputDepthPitch)
2086 {
2087 LoadETC2RGB8ToBC1(context, width, height, depth, input, inputRowPitch, inputDepthPitch, output,
2088 outputRowPitch, outputDepthPitch, true);
2089 }
2090
LoadETC2RGBA8ToRGBA8(const ImageLoadContext & context,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)2091 void LoadETC2RGBA8ToRGBA8(const ImageLoadContext &context,
2092 size_t width,
2093 size_t height,
2094 size_t depth,
2095 const uint8_t *input,
2096 size_t inputRowPitch,
2097 size_t inputDepthPitch,
2098 uint8_t *output,
2099 size_t outputRowPitch,
2100 size_t outputDepthPitch)
2101 {
2102 LoadETC2RGBA8ToRGBA8(context, width, height, depth, input, inputRowPitch, inputDepthPitch,
2103 output, outputRowPitch, outputDepthPitch, false);
2104 }
2105
LoadETC2SRGBA8ToSRGBA8(const ImageLoadContext & context,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)2106 void LoadETC2SRGBA8ToSRGBA8(const ImageLoadContext &context,
2107 size_t width,
2108 size_t height,
2109 size_t depth,
2110 const uint8_t *input,
2111 size_t inputRowPitch,
2112 size_t inputDepthPitch,
2113 uint8_t *output,
2114 size_t outputRowPitch,
2115 size_t outputDepthPitch)
2116 {
2117 LoadETC2RGBA8ToRGBA8(context, width, height, depth, input, inputRowPitch, inputDepthPitch,
2118 output, outputRowPitch, outputDepthPitch, true);
2119 }
2120
LoadETC2RGBA8ToBC3(const ImageLoadContext & context,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)2121 void LoadETC2RGBA8ToBC3(const ImageLoadContext &context,
2122 size_t width,
2123 size_t height,
2124 size_t depth,
2125 const uint8_t *input,
2126 size_t inputRowPitch,
2127 size_t inputDepthPitch,
2128 uint8_t *output,
2129 size_t outputRowPitch,
2130 size_t outputDepthPitch)
2131 {
2132 LoadETC2RGBA8ToBC3(context, width, height, depth, input, inputRowPitch, inputDepthPitch, output,
2133 outputRowPitch, outputDepthPitch, false, false);
2134 }
2135
LoadETC2SRGBA8ToBC3(const ImageLoadContext & context,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)2136 void LoadETC2SRGBA8ToBC3(const ImageLoadContext &context,
2137 size_t width,
2138 size_t height,
2139 size_t depth,
2140 const uint8_t *input,
2141 size_t inputRowPitch,
2142 size_t inputDepthPitch,
2143 uint8_t *output,
2144 size_t outputRowPitch,
2145 size_t outputDepthPitch)
2146 {
2147 LoadETC2RGBA8ToBC3(context, width, height, depth, input, inputRowPitch, inputDepthPitch, output,
2148 outputRowPitch, outputDepthPitch, false, false);
2149 }
2150
LoadEACR11ToBC4(const ImageLoadContext & context,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)2151 void LoadEACR11ToBC4(const ImageLoadContext &context,
2152 size_t width,
2153 size_t height,
2154 size_t depth,
2155 const uint8_t *input,
2156 size_t inputRowPitch,
2157 size_t inputDepthPitch,
2158 uint8_t *output,
2159 size_t outputRowPitch,
2160 size_t outputDepthPitch,
2161 bool isSigned)
2162 {
2163 for (size_t z = 0; z < depth; z++)
2164 {
2165 for (size_t y = 0; y < height; y += 4)
2166 {
2167 const ETC2Block *sourceRow =
2168 priv::OffsetDataPointer<ETC2Block>(input, y / 4, z, inputRowPitch, inputDepthPitch);
2169 uint8_t *destRow = priv::OffsetDataPointer<uint8_t>(output, y / 4, z, outputRowPitch,
2170 outputDepthPitch);
2171
2172 for (size_t x = 0; x < width; x += 4)
2173 {
2174 const ETC2Block *sourceR11Block = sourceRow + (x / 4);
2175 uint8_t *destR11Pixels = destRow + (x * 2);
2176 sourceR11Block->transcodeAsBC4(destR11Pixels, x, y, width, height, isSigned);
2177 }
2178 }
2179 }
2180 }
2181
LoadEACRG11ToBC5(const ImageLoadContext & context,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)2182 void LoadEACRG11ToBC5(const ImageLoadContext &context,
2183 size_t width,
2184 size_t height,
2185 size_t depth,
2186 const uint8_t *input,
2187 size_t inputRowPitch,
2188 size_t inputDepthPitch,
2189 uint8_t *output,
2190 size_t outputRowPitch,
2191 size_t outputDepthPitch,
2192 bool isSigned)
2193 {
2194 for (size_t z = 0; z < depth; z++)
2195 {
2196 for (size_t y = 0; y < height; y += 4)
2197 {
2198 const ETC2Block *sourceRow =
2199 priv::OffsetDataPointer<ETC2Block>(input, y / 4, z, inputRowPitch, inputDepthPitch);
2200 uint8_t *destRow = priv::OffsetDataPointer<uint8_t>(output, y / 4, z, outputRowPitch,
2201 outputDepthPitch);
2202
2203 for (size_t x = 0; x < width; x += 4)
2204 {
2205 const ETC2Block *sourceR11Block = sourceRow + (x / 2);
2206 uint8_t *destR11Pixels = destRow + (x * 4);
2207
2208 const ETC2Block *sourceG11Block = sourceR11Block + 1;
2209 uint8_t *destG11Pixels = destR11Pixels + 8;
2210 sourceR11Block->transcodeAsBC4(destR11Pixels, x, y, width, height, isSigned);
2211 sourceG11Block->transcodeAsBC4(destG11Pixels, x, y, width, height, isSigned);
2212 }
2213 }
2214 }
2215 }
2216
LoadEACR11ToBC4(const ImageLoadContext & context,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)2217 void LoadEACR11ToBC4(const ImageLoadContext &context,
2218 size_t width,
2219 size_t height,
2220 size_t depth,
2221 const uint8_t *input,
2222 size_t inputRowPitch,
2223 size_t inputDepthPitch,
2224 uint8_t *output,
2225 size_t outputRowPitch,
2226 size_t outputDepthPitch)
2227 {
2228 LoadEACR11ToBC4(context, width, height, depth, input, inputRowPitch, inputDepthPitch, output,
2229 outputRowPitch, outputDepthPitch, false);
2230 }
2231
LoadEACR11SToBC4(const ImageLoadContext & context,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)2232 void LoadEACR11SToBC4(const ImageLoadContext &context,
2233 size_t width,
2234 size_t height,
2235 size_t depth,
2236 const uint8_t *input,
2237 size_t inputRowPitch,
2238 size_t inputDepthPitch,
2239 uint8_t *output,
2240 size_t outputRowPitch,
2241 size_t outputDepthPitch)
2242 {
2243 LoadEACR11ToBC4(context, width, height, depth, input, inputRowPitch, inputDepthPitch, output,
2244 outputRowPitch, outputDepthPitch, true);
2245 }
2246
LoadEACRG11ToBC5(const ImageLoadContext & context,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)2247 void LoadEACRG11ToBC5(const ImageLoadContext &context,
2248 size_t width,
2249 size_t height,
2250 size_t depth,
2251 const uint8_t *input,
2252 size_t inputRowPitch,
2253 size_t inputDepthPitch,
2254 uint8_t *output,
2255 size_t outputRowPitch,
2256 size_t outputDepthPitch)
2257 {
2258 LoadEACRG11ToBC5(context, width, height, depth, input, inputRowPitch, inputDepthPitch, output,
2259 outputRowPitch, outputDepthPitch, false);
2260 }
2261
LoadEACRG11SToBC5(const ImageLoadContext & context,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)2262 void LoadEACRG11SToBC5(const ImageLoadContext &context,
2263 size_t width,
2264 size_t height,
2265 size_t depth,
2266 const uint8_t *input,
2267 size_t inputRowPitch,
2268 size_t inputDepthPitch,
2269 uint8_t *output,
2270 size_t outputRowPitch,
2271 size_t outputDepthPitch)
2272 {
2273 LoadEACRG11ToBC5(context, width, height, depth, input, inputRowPitch, inputDepthPitch, output,
2274 outputRowPitch, outputDepthPitch, true);
2275 }
2276
2277 } // namespace angle
2278