xref: /aosp_15_r20/external/angle/src/image_util/loadimage_etc.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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