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