tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

loadimage_etc.cpp (76247B)


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