1 // Copyright 2009 Google Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "gfxstream/etc.h"
16 
17 #include <algorithm>
18 #include <assert.h>
19 #include <string.h>
20 #include <stdint.h>
21 #include <stdio.h>
22 
23 typedef uint16_t etc1_uint16;
24 
25 /* From http://www.khronos.org/registry/gles/extensions/OES/OES_compressed_ETC1_RGB8_texture.txt
26 
27  The number of bits that represent a 4x4 texel block is 64 bits if
28  <internalformat> is given by ETC1_RGB8_OES.
29 
30  The data for a block is a number of bytes,
31 
32  {q0, q1, q2, q3, q4, q5, q6, q7}
33 
34  where byte q0 is located at the lowest memory address and q7 at
35  the highest. The 64 bits specifying the block is then represented
36  by the following 64 bit integer:
37 
38  int64bit = 256*(256*(256*(256*(256*(256*(256*q0+q1)+q2)+q3)+q4)+q5)+q6)+q7;
39 
40  ETC1_RGB8_OES:
41 
42  a) bit layout in bits 63 through 32 if diffbit = 0
43 
44  63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48
45  -----------------------------------------------
46  | base col1 | base col2 | base col1 | base col2 |
47  | R1 (4bits)| R2 (4bits)| G1 (4bits)| G2 (4bits)|
48  -----------------------------------------------
49 
50  47 46 45 44 43 42 41 40 39 38 37 36 35 34  33  32
51  ---------------------------------------------------
52  | base col1 | base col2 | table  | table  |diff|flip|
53  | B1 (4bits)| B2 (4bits)| cw 1   | cw 2   |bit |bit |
54  ---------------------------------------------------
55 
56 
57  b) bit layout in bits 63 through 32 if diffbit = 1
58 
59  63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48
60  -----------------------------------------------
61  | base col1    | dcol 2 | base col1    | dcol 2 |
62  | R1' (5 bits) | dR2    | G1' (5 bits) | dG2    |
63  -----------------------------------------------
64 
65  47 46 45 44 43 42 41 40 39 38 37 36 35 34  33  32
66  ---------------------------------------------------
67  | base col 1   | dcol 2 | table  | table  |diff|flip|
68  | B1' (5 bits) | dB2    | cw 1   | cw 2   |bit |bit |
69  ---------------------------------------------------
70 
71 
72  c) bit layout in bits 31 through 0 (in both cases)
73 
74  31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16
75  -----------------------------------------------
76  |       most significant pixel index bits       |
77  | p| o| n| m| l| k| j| i| h| g| f| e| d| c| b| a|
78  -----------------------------------------------
79 
80  15 14 13 12 11 10  9  8  7  6  5  4  3   2   1  0
81  --------------------------------------------------
82  |         least significant pixel index bits       |
83  | p| o| n| m| l| k| j| i| h| g| f| e| d| c | b | a |
84  --------------------------------------------------
85 
86 
87  Add table 3.17.2: Intensity modifier sets for ETC1 compressed textures:
88 
89  table codeword                modifier table
90  ------------------        ----------------------
91  0                     -8  -2  2   8
92  1                    -17  -5  5  17
93  2                    -29  -9  9  29
94  3                    -42 -13 13  42
95  4                    -60 -18 18  60
96  5                    -80 -24 24  80
97  6                   -106 -33 33 106
98  7                   -183 -47 47 183
99 
100 
101  Add table 3.17.3 Mapping from pixel index values to modifier values for
102  ETC1 compressed textures:
103 
104  pixel index value
105  ---------------
106  msb     lsb           resulting modifier value
107  -----   -----          -------------------------
108  1       1            -b (large negative value)
109  1       0            -a (small negative value)
110  0       0             a (small positive value)
111  0       1             b (large positive value)
112 
113  ETC2 codec:
114      from https://www.khronos.org/registry/gles/specs/3.0/es_spec_3.0.4.pdf
115      page 289
116  */
117 
118 static const int kRGBModifierTable[] = {
119 /* 0 */2, 8, -2, -8,
120 /* 1 */5, 17, -5, -17,
121 /* 2 */9, 29, -9, -29,
122 /* 3 */13, 42, -13, -42,
123 /* 4 */18, 60, -18, -60,
124 /* 5 */24, 80, -24, -80,
125 /* 6 */33, 106, -33, -106,
126 /* 7 */47, 183, -47, -183 };
127 
128 static const int kRGBOpaqueModifierTable[] = {
129 /* 0 */0, 8, 0, -8,
130 /* 1 */0, 17, 0, -17,
131 /* 2 */0, 29, 0, -29,
132 /* 3 */0, 42, 0, -42,
133 /* 4 */0, 60, 0, -60,
134 /* 5 */0, 80, 0, -80,
135 /* 6 */0, 106, 0, -106,
136 /* 7 */0, 183, 0, -183 };
137 
138 static const int kAlphaModifierTable[] = {
139 /* 0 */ -3, -6, -9, -15, 2, 5, 8, 14,
140 /* 1 */ -3, -7, -10, -13, 2, 6, 9, 12,
141 /* 2 */ -2, -5, -8, -13, 1, 4, 7, 12,
142 /* 3 */ -2, -4, -6, -13, 1, 3, 5, 12,
143 /* 4 */ -3, -6, -8, -12, 2, 5, 7, 11,
144 /* 5 */ -3, -7, -9, -11, 2, 6, 8, 10,
145 /* 6 */ -4, -7, -8, -11, 3, 6, 7, 10,
146 /* 7 */ -3, -5, -8, -11, 2, 4, 7, 10,
147 /* 8 */ -2, -6, -8, -10, 1, 5, 7, 9,
148 /* 9 */ -2, -5, -8, -10, 1, 4, 7, 9,
149 /* 10 */ -2, -4, -8, -10, 1, 3, 7, 9,
150 /* 11 */ -2, -5, -7, -10, 1, 4, 6, 9,
151 /* 12 */ -3, -4, -7, -10, 2, 3, 6, 9,
152 /* 13 */ -1, -2, -3, -10, 0, 1, 2, 9,
153 /* 14 */ -4, -6, -8, -9, 3, 5, 7, 8,
154 /* 15 */ -3, -5, -7, -9, 2, 4, 6, 8
155 };
156 
157 static const int kLookup[8] = { 0, 1, 2, 3, -4, -3, -2, -1 };
158 
clamp(int x)159 static inline int clamp(int x) {
160     return (x >= 0 ? (x < 255 ? x : 255) : 0);
161 }
162 
clamp2047(int x)163 static inline int clamp2047(int x) {
164     return (x >= 0 ? (x < 2047 ? x : 2047) : 0);
165 }
166 
clampSigned1023(int x)167 static inline int clampSigned1023(int x) {
168     return (x >= -1023 ? (x < 1023 ? x : 1023) : -1023);
169 }
170 
171 static
convert4To8(int b)172 inline int convert4To8(int b) {
173     int c = b & 0xf;
174     return (c << 4) | c;
175 }
176 
177 static
convert5To8(int b)178 inline int convert5To8(int b) {
179     int c = b & 0x1f;
180     return (c << 3) | (c >> 2);
181 }
182 
183 static
convert6To8(int b)184 inline int convert6To8(int b) {
185     int c = b & 0x3f;
186     return (c << 2) | (c >> 4);
187 }
188 
189 static
convert7To8(int b)190 inline int convert7To8(int b) {
191     int c = b & 0x7f;
192     return (c << 1) | (c >> 6);
193 }
194 
195 static
divideBy255(int d)196 inline int divideBy255(int d) {
197     return (d + 128 + (d >> 8)) >> 8;
198 }
199 
200 static
convert8To4(int b)201 inline int convert8To4(int b) {
202     int c = b & 0xff;
203     return divideBy255(c * 15);
204 }
205 
206 static
convert8To5(int b)207 inline int convert8To5(int b) {
208     int c = b & 0xff;
209     return divideBy255(c * 31);
210 }
211 
212 static
convertDiff(int base,int diff)213 inline int convertDiff(int base, int diff) {
214     return convert5To8((0x1f & base) + kLookup[0x7 & diff]);
215 }
216 static
isOverflowed(int base,int diff)217 int isOverflowed(int base, int diff) {
218     int val = (0x1f & base) + kLookup[0x7 & diff];
219     return val < 0 || val >= 32;
220 }
221 
222 static
decode_subblock(etc1_byte * pOut,int r,int g,int b,const int * table,etc1_uint32 low,bool second,bool flipped,bool isPunchthroughAlpha,bool opaque)223 void decode_subblock(etc1_byte* pOut, int r, int g, int b, const int* table,
224         etc1_uint32 low, bool second, bool flipped, bool isPunchthroughAlpha,
225         bool opaque) {
226     int baseX = 0;
227     int baseY = 0;
228     int channels = isPunchthroughAlpha ? 4 : 3;
229     if (second) {
230         if (flipped) {
231             baseY = 2;
232         } else {
233             baseX = 2;
234         }
235     }
236     for (int i = 0; i < 8; i++) {
237         int x, y;
238         if (flipped) {
239             x = baseX + (i >> 1);
240             y = baseY + (i & 1);
241         } else {
242             x = baseX + (i >> 2);
243             y = baseY + (i & 3);
244         }
245         int k = y + (x * 4);
246         int msb = ((low >> (k + 15)) & 2);
247         int lsb = ((low >> k) & 1);
248         etc1_byte* q = pOut + channels * (x + 4 * y);
249         if (isPunchthroughAlpha && !opaque && msb && !lsb) {
250             // rgba all 0
251             memset(q, 0, 4);
252             q += 4;
253         } else {
254             int offset = lsb | msb;
255             int delta = table[offset];
256             *q++ = clamp(r + delta);
257             *q++ = clamp(g + delta);
258             *q++ = clamp(b + delta);
259             if (isPunchthroughAlpha) {
260                 *q++ = 255;
261             }
262         }
263     }
264 }
265 
etc2_T_H_index(const int * clrTable,etc1_uint32 low,bool isPunchthroughAlpha,bool opaque,etc1_byte * pOut)266 static void etc2_T_H_index(const int* clrTable, etc1_uint32 low,
267                            bool isPunchthroughAlpha, bool opaque,
268                            etc1_byte* pOut) {
269     etc1_byte* q = pOut;
270     for (int y = 0; y < 4; y++) {
271         for (int x = 0; x < 4; x++) {
272             int k = y + x * 4;
273             int msb = (low >> (k + 15)) & 2;
274             int lsb = (low >> k) & 1;
275             if (isPunchthroughAlpha && !opaque && msb && !lsb) {
276                 // rgba all 0
277                 memset(q, 0, 4);
278                 q += 4;
279             } else {
280                 int offset = lsb | msb;
281                 for (int c = 0; c < 3; c++) {
282                     *q++ = clrTable[offset*3 + c];
283                 }
284                 if (isPunchthroughAlpha) {
285                     *q++ = 255;
286                 }
287             }
288         }
289     }
290 }
291 
292 // ETC2 codec:
293 //     from https://www.khronos.org/registry/gles/specs/3.0/es_spec_3.0.4.pdf
294 //     page 289
295 
etc2_decode_block_T(etc1_uint32 high,etc1_uint32 low,bool isPunchthroughAlpha,bool opaque,etc1_byte * pOut)296 static void etc2_decode_block_T(etc1_uint32 high, etc1_uint32 low,
297         bool isPunchthroughAlpha, bool opaque, etc1_byte* pOut) {
298     const int LUT[] = {3, 6, 11, 16, 23, 32, 41, 64};
299     int r1, r2, g1, g2, b1, b2;
300     r1 = convert4To8((((high >> 27) & 3) << 2) | ((high >> 24) & 3));
301     g1 = convert4To8(high >> 20);
302     b1 = convert4To8(high >> 16);
303     r2 = convert4To8(high >> 12);
304     g2 = convert4To8(high >> 8);
305     b2 = convert4To8(high >> 4);
306     // 3 bits intense modifier
307     int intenseIdx = (((high >> 2) & 3) << 1) | (high & 1);
308     int intenseMod = LUT[intenseIdx];
309     int clrTable[12];
310     clrTable[0] = r1;
311     clrTable[1] = g1;
312     clrTable[2] = b1;
313     clrTable[3] = clamp(r2 + intenseMod);
314     clrTable[4] = clamp(g2 + intenseMod);
315     clrTable[5] = clamp(b2 + intenseMod);
316     clrTable[6] = r2;
317     clrTable[7] = g2;
318     clrTable[8] = b2;
319     clrTable[9] = clamp(r2 - intenseMod);
320     clrTable[10] = clamp(g2 - intenseMod);
321     clrTable[11] = clamp(b2 - intenseMod);
322     etc2_T_H_index(clrTable, low, isPunchthroughAlpha, opaque, pOut);
323 }
324 
etc2_decode_block_H(etc1_uint32 high,etc1_uint32 low,bool isPunchthroughAlpha,bool opaque,etc1_byte * pOut)325 static void etc2_decode_block_H(etc1_uint32 high, etc1_uint32 low,
326         bool isPunchthroughAlpha, bool opaque, etc1_byte* pOut) {
327     const int LUT[] = {3, 6, 11, 16, 23, 32, 41, 64};
328     int r1, r2, g1, g2, b1, b2;
329     r1 = convert4To8(high >> 27);
330     g1 = convert4To8((high >> 24) << 1 | ((high >> 20) & 1));
331     b1 = convert4To8((high >> 19) << 3 | ((high >> 15) & 7));
332     r2 = convert4To8(high >> 11);
333     g2 = convert4To8(high >> 7);
334     b2 = convert4To8(high >> 3);
335     // 3 bits intense modifier
336     int intenseIdx = high & 4;
337     intenseIdx |= (high & 1) << 1;
338     intenseIdx |= (((r1 << 16) | (g1 << 8) | b1) >= ((r2 << 16) | (g2 << 8) | b2));
339     int intenseMod = LUT[intenseIdx];
340     int clrTable[12];
341     clrTable[0] = clamp(r1 + intenseMod);
342     clrTable[1] = clamp(g1 + intenseMod);
343     clrTable[2] = clamp(b1 + intenseMod);
344     clrTable[3] = clamp(r1 - intenseMod);
345     clrTable[4] = clamp(g1 - intenseMod);
346     clrTable[5] = clamp(b1 - intenseMod);
347     clrTable[6] = clamp(r2 + intenseMod);
348     clrTable[7] = clamp(g2 + intenseMod);
349     clrTable[8] = clamp(b2 + intenseMod);
350     clrTable[9] = clamp(r2 - intenseMod);
351     clrTable[10] = clamp(g2 - intenseMod);
352     clrTable[11] = clamp(b2 - intenseMod);
353     etc2_T_H_index(clrTable, low, isPunchthroughAlpha, opaque, pOut);
354 }
355 
etc2_decode_block_P(etc1_uint32 high,etc1_uint32 low,bool isPunchthroughAlpha,etc1_byte * pOut)356 static void etc2_decode_block_P(etc1_uint32 high, etc1_uint32 low,
357         bool isPunchthroughAlpha, etc1_byte* pOut) {
358     int ro, go, bo, rh, gh, bh, rv, gv, bv;
359     uint64_t data = high;
360     data = data << 32 | low;
361     ro = convert6To8(data >> 57);
362     go = convert7To8((data >> 56 << 6) | ((data >> 49) & 63));
363     bo = convert6To8((data >> 48 << 5)
364             | (((data >> 43) & 3 ) << 3)
365             | ((data >> 39) & 7));
366     rh = convert6To8((data >> 34 << 1) | ((data >> 32) & 1));
367     gh = convert7To8(data >> 25);
368     bh = convert6To8(data >> 19);
369     rv = convert6To8(data >> 13);
370     gv = convert7To8(data >> 6);
371     bv = convert6To8(data);
372     etc1_byte* q = pOut;
373     for (int i = 0; i < 16; i++) {
374         int y = i >> 2;
375         int x = i & 3;
376         *q++ = clamp((x * (rh - ro) + y * (rv - ro) + 4 * ro + 2) >> 2);
377         *q++ = clamp((x * (gh - go) + y * (gv - go) + 4 * go + 2) >> 2);
378         *q++ = clamp((x * (bh - bo) + y * (bv - bo) + 4 * bo + 2) >> 2);
379         if (isPunchthroughAlpha) *q++ = 255;
380     }
381 }
382 
383 // Input is an ETC1 / ETC2 compressed version of the data.
384 // Output is a 4 x 4 square of 3-byte pixels in form R, G, B
385 // ETC2 codec:
386 //     from https://www.khronos.org/registry/gles/specs/3.0/es_spec_3.0.4.pdf
387 //     page 289
388 
etc2_decode_rgb_block(const etc1_byte * pIn,bool isPunchthroughAlpha,etc1_byte * pOut)389 void etc2_decode_rgb_block(const etc1_byte* pIn, bool isPunchthroughAlpha,
390                            etc1_byte* pOut) {
391     etc1_uint32 high = (pIn[0] << 24) | (pIn[1] << 16) | (pIn[2] << 8) | pIn[3];
392     etc1_uint32 low = (pIn[4] << 24) | (pIn[5] << 16) | (pIn[6] << 8) | pIn[7];
393     bool opaque = (high >> 1) & 1;
394     int r1, r2, g1, g2, b1, b2;
395     if (isPunchthroughAlpha || high & 2) {
396         // differential
397         int rBase = high >> 27;
398         int gBase = high >> 19;
399         int bBase = high >> 11;
400         if (isOverflowed(rBase, high >> 24)) {
401             etc2_decode_block_T(high, low, isPunchthroughAlpha, opaque, pOut);
402             return;
403         }
404         if (isOverflowed(gBase, high >> 16)) {
405             etc2_decode_block_H(high, low, isPunchthroughAlpha, opaque, pOut);
406             return;
407         }
408         if (isOverflowed(bBase, high >> 8)) {
409             etc2_decode_block_P(high, low, isPunchthroughAlpha, pOut);
410             return;
411         }
412         r1 = convert5To8(rBase);
413         r2 = convertDiff(rBase, high >> 24);
414         g1 = convert5To8(gBase);
415         g2 = convertDiff(gBase, high >> 16);
416         b1 = convert5To8(bBase);
417         b2 = convertDiff(bBase, high >> 8);
418     } else {
419         // not differential
420         r1 = convert4To8(high >> 28);
421         r2 = convert4To8(high >> 24);
422         g1 = convert4To8(high >> 20);
423         g2 = convert4To8(high >> 16);
424         b1 = convert4To8(high >> 12);
425         b2 = convert4To8(high >> 8);
426     }
427     int tableIndexA = 7 & (high >> 5);
428     int tableIndexB = 7 & (high >> 2);
429     const int* rgbModifierTable = opaque || !isPunchthroughAlpha ?
430                                   kRGBModifierTable : kRGBOpaqueModifierTable;
431     const int* tableA = rgbModifierTable + tableIndexA * 4;
432     const int* tableB = rgbModifierTable + tableIndexB * 4;
433     bool flipped = (high & 1) != 0;
434     decode_subblock(pOut, r1, g1, b1, tableA, low, false, flipped,
435                     isPunchthroughAlpha, opaque);
436     decode_subblock(pOut, r2, g2, b2, tableB, low, true, flipped,
437                     isPunchthroughAlpha, opaque);
438 }
439 
eac_decode_single_channel_block(const etc1_byte * pIn,int decodedElementBytes,bool isSigned,etc1_byte * pOut)440 void eac_decode_single_channel_block(const etc1_byte* pIn,
441                                      int decodedElementBytes, bool isSigned,
442                                      etc1_byte* pOut) {
443     assert(decodedElementBytes == 1 || decodedElementBytes == 2 || decodedElementBytes == 4);
444     int base_codeword = isSigned ? reinterpret_cast<const char*>(pIn)[0]
445                                  : pIn[0];
446     if (base_codeword == -128) base_codeword = -127;
447     int multiplier = pIn[1] >> 4;
448     int tblIdx = pIn[1] & 15;
449     const int* table = kAlphaModifierTable + tblIdx * 8;
450     const etc1_byte* p = pIn + 2;
451     // position in a byte of the next 3-bit index:
452     // | a a a | b b b | c c c | d d d ...
453     // | byte               | byte...
454     int bitOffset = 5;
455     for (int i = 0; i < 16; i ++) {
456         // flip x, y in output
457         int outIdx = (i % 4) * 4 + i / 4;
458         etc1_byte* q = pOut + outIdx * decodedElementBytes;
459 
460         int modifier = 0;
461         if (bitOffset < 0) { // (Part of) the index is in the next byte.
462             modifier += p[0] << (-bitOffset);
463             p ++;
464             bitOffset += 8;
465         }
466         modifier += p[0] >> bitOffset;
467         modifier &= 7;
468         bitOffset -= 3; // move to the next index
469         if (bitOffset == -3) {
470             bitOffset = 5;
471             p++;
472         }
473         int modifierValue = table[modifier];
474         int decoded = base_codeword + modifierValue * multiplier;
475         if (decodedElementBytes == 1) {
476             *q = clamp(decoded);
477         } else { // decodedElementBytes == 4
478             decoded *= 8;
479             if (multiplier == 0) {
480                 decoded += modifierValue;
481             }
482             if (isSigned) {
483                 decoded = clampSigned1023(decoded);
484                 reinterpret_cast<float*>(q)[0] = (float)decoded / 1023.0;
485             } else {
486                 decoded += 4;
487                 decoded = clamp2047(decoded);
488                 reinterpret_cast<float*>(q)[0] = (float)decoded / 2047.0;
489             }
490         }
491     }
492 }
493 
494 typedef struct {
495     etc1_uint32 high;
496     etc1_uint32 low;
497     etc1_uint32 score; // Lower is more accurate
498 } etc_compressed;
499 
500 static
take_best(etc_compressed * a,const etc_compressed * b)501 inline void take_best(etc_compressed* a, const etc_compressed* b) {
502     if (a->score > b->score) {
503         *a = *b;
504     }
505 }
506 
507 static
etc_average_colors_subblock(const etc1_byte * pIn,etc1_uint32 inMask,etc1_byte * pColors,bool flipped,bool second)508 void etc_average_colors_subblock(const etc1_byte* pIn, etc1_uint32 inMask,
509         etc1_byte* pColors, bool flipped, bool second) {
510     int r = 0;
511     int g = 0;
512     int b = 0;
513 
514     if (flipped) {
515         int by = 0;
516         if (second) {
517             by = 2;
518         }
519         for (int y = 0; y < 2; y++) {
520             int yy = by + y;
521             for (int x = 0; x < 4; x++) {
522                 int i = x + 4 * yy;
523                 if (inMask & (1 << i)) {
524                     const etc1_byte* p = pIn + i * 3;
525                     r += *(p++);
526                     g += *(p++);
527                     b += *(p++);
528                 }
529             }
530         }
531     } else {
532         int bx = 0;
533         if (second) {
534             bx = 2;
535         }
536         for (int y = 0; y < 4; y++) {
537             for (int x = 0; x < 2; x++) {
538                 int xx = bx + x;
539                 int i = xx + 4 * y;
540                 if (inMask & (1 << i)) {
541                     const etc1_byte* p = pIn + i * 3;
542                     r += *(p++);
543                     g += *(p++);
544                     b += *(p++);
545                 }
546             }
547         }
548     }
549     pColors[0] = (etc1_byte)((r + 4) >> 3);
550     pColors[1] = (etc1_byte)((g + 4) >> 3);
551     pColors[2] = (etc1_byte)((b + 4) >> 3);
552 }
553 
554 static
square(int x)555 inline int square(int x) {
556     return x * x;
557 }
558 
chooseModifier(const etc1_byte * pBaseColors,const etc1_byte * pIn,etc1_uint32 * pLow,int bitIndex,const int * pModifierTable)559 static etc1_uint32 chooseModifier(const etc1_byte* pBaseColors,
560         const etc1_byte* pIn, etc1_uint32 *pLow, int bitIndex,
561         const int* pModifierTable) {
562     etc1_uint32 bestScore = ~0;
563     int bestIndex = 0;
564     int pixelR = pIn[0];
565     int pixelG = pIn[1];
566     int pixelB = pIn[2];
567     int r = pBaseColors[0];
568     int g = pBaseColors[1];
569     int b = pBaseColors[2];
570     for (int i = 0; i < 4; i++) {
571         int modifier = pModifierTable[i];
572         int decodedG = clamp(g + modifier);
573         etc1_uint32 score = (etc1_uint32) (6 * square(decodedG - pixelG));
574         if (score >= bestScore) {
575             continue;
576         }
577         int decodedR = clamp(r + modifier);
578         score += (etc1_uint32) (3 * square(decodedR - pixelR));
579         if (score >= bestScore) {
580             continue;
581         }
582         int decodedB = clamp(b + modifier);
583         score += (etc1_uint32) square(decodedB - pixelB);
584         if (score < bestScore) {
585             bestScore = score;
586             bestIndex = i;
587         }
588     }
589     etc1_uint32 lowMask = (((bestIndex >> 1) << 16) | (bestIndex & 1))
590             << bitIndex;
591     *pLow |= lowMask;
592     return bestScore;
593 }
594 
595 static
etc_encode_subblock_helper(const etc1_byte * pIn,etc1_uint32 inMask,etc_compressed * pCompressed,bool flipped,bool second,const etc1_byte * pBaseColors,const int * pModifierTable)596 void etc_encode_subblock_helper(const etc1_byte* pIn, etc1_uint32 inMask,
597         etc_compressed* pCompressed, bool flipped, bool second,
598         const etc1_byte* pBaseColors, const int* pModifierTable) {
599     int score = pCompressed->score;
600     if (flipped) {
601         int by = 0;
602         if (second) {
603             by = 2;
604         }
605         for (int y = 0; y < 2; y++) {
606             int yy = by + y;
607             for (int x = 0; x < 4; x++) {
608                 int i = x + 4 * yy;
609                 if (inMask & (1 << i)) {
610                     score += chooseModifier(pBaseColors, pIn + i * 3,
611                             &pCompressed->low, yy + x * 4, pModifierTable);
612                 }
613             }
614         }
615     } else {
616         int bx = 0;
617         if (second) {
618             bx = 2;
619         }
620         for (int y = 0; y < 4; y++) {
621             for (int x = 0; x < 2; x++) {
622                 int xx = bx + x;
623                 int i = xx + 4 * y;
624                 if (inMask & (1 << i)) {
625                     score += chooseModifier(pBaseColors, pIn + i * 3,
626                             &pCompressed->low, y + xx * 4, pModifierTable);
627                 }
628             }
629         }
630     }
631     pCompressed->score = score;
632 }
633 
inRange4bitSigned(int color)634 static bool inRange4bitSigned(int color) {
635     return color >= -4 && color <= 3;
636 }
637 
etc_encodeBaseColors(etc1_byte * pBaseColors,const etc1_byte * pColors,etc_compressed * pCompressed)638 static void etc_encodeBaseColors(etc1_byte* pBaseColors,
639         const etc1_byte* pColors, etc_compressed* pCompressed) {
640     int r1, g1, b1, r2, g2, b2; // 8 bit base colors for sub-blocks
641     bool differential;
642     {
643         int r51 = convert8To5(pColors[0]);
644         int g51 = convert8To5(pColors[1]);
645         int b51 = convert8To5(pColors[2]);
646         int r52 = convert8To5(pColors[3]);
647         int g52 = convert8To5(pColors[4]);
648         int b52 = convert8To5(pColors[5]);
649 
650         r1 = convert5To8(r51);
651         g1 = convert5To8(g51);
652         b1 = convert5To8(b51);
653 
654         int dr = r52 - r51;
655         int dg = g52 - g51;
656         int db = b52 - b51;
657 
658         differential = inRange4bitSigned(dr) && inRange4bitSigned(dg)
659                 && inRange4bitSigned(db);
660         if (differential) {
661             r2 = convert5To8(r51 + dr);
662             g2 = convert5To8(g51 + dg);
663             b2 = convert5To8(b51 + db);
664             pCompressed->high |= (r51 << 27) | ((7 & dr) << 24) | (g51 << 19)
665                     | ((7 & dg) << 16) | (b51 << 11) | ((7 & db) << 8) | 2;
666         }
667     }
668 
669     if (!differential) {
670         int r41 = convert8To4(pColors[0]);
671         int g41 = convert8To4(pColors[1]);
672         int b41 = convert8To4(pColors[2]);
673         int r42 = convert8To4(pColors[3]);
674         int g42 = convert8To4(pColors[4]);
675         int b42 = convert8To4(pColors[5]);
676         r1 = convert4To8(r41);
677         g1 = convert4To8(g41);
678         b1 = convert4To8(b41);
679         r2 = convert4To8(r42);
680         g2 = convert4To8(g42);
681         b2 = convert4To8(b42);
682         pCompressed->high |= (r41 << 28) | (r42 << 24) | (g41 << 20) | (g42
683                 << 16) | (b41 << 12) | (b42 << 8);
684     }
685     pBaseColors[0] = r1;
686     pBaseColors[1] = g1;
687     pBaseColors[2] = b1;
688     pBaseColors[3] = r2;
689     pBaseColors[4] = g2;
690     pBaseColors[5] = b2;
691 }
692 
693 static
etc_encode_block_helper(const etc1_byte * pIn,etc1_uint32 inMask,const etc1_byte * pColors,etc_compressed * pCompressed,bool flipped)694 void etc_encode_block_helper(const etc1_byte* pIn, etc1_uint32 inMask,
695         const etc1_byte* pColors, etc_compressed* pCompressed, bool flipped) {
696     pCompressed->score = ~0;
697     pCompressed->high = (flipped ? 1 : 0);
698     pCompressed->low = 0;
699 
700     etc1_byte pBaseColors[6];
701 
702     etc_encodeBaseColors(pBaseColors, pColors, pCompressed);
703 
704     int originalHigh = pCompressed->high;
705 
706     const int* pModifierTable = kRGBModifierTable;
707     for (int i = 0; i < 8; i++, pModifierTable += 4) {
708         etc_compressed temp;
709         temp.score = 0;
710         temp.high = originalHigh | (i << 5);
711         temp.low = 0;
712         etc_encode_subblock_helper(pIn, inMask, &temp, flipped, false,
713                 pBaseColors, pModifierTable);
714         take_best(pCompressed, &temp);
715     }
716     pModifierTable = kRGBModifierTable;
717     etc_compressed firstHalf = *pCompressed;
718     for (int i = 0; i < 8; i++, pModifierTable += 4) {
719         etc_compressed temp;
720         temp.score = firstHalf.score;
721         temp.high = firstHalf.high | (i << 2);
722         temp.low = firstHalf.low;
723         etc_encode_subblock_helper(pIn, inMask, &temp, flipped, true,
724                 pBaseColors + 3, pModifierTable);
725         if (i == 0) {
726             *pCompressed = temp;
727         } else {
728             take_best(pCompressed, &temp);
729         }
730     }
731 }
732 
writeBigEndian(etc1_byte * pOut,etc1_uint32 d)733 static void writeBigEndian(etc1_byte* pOut, etc1_uint32 d) {
734     pOut[0] = (etc1_byte)(d >> 24);
735     pOut[1] = (etc1_byte)(d >> 16);
736     pOut[2] = (etc1_byte)(d >> 8);
737     pOut[3] = (etc1_byte) d;
738 }
739 
740 // Input is a 4 x 4 square of 3-byte pixels in form R, G, B
741 // inmask is a 16-bit mask where bit (1 << (x + y * 4)) tells whether the corresponding (x,y)
742 // pixel is valid or not. Invalid pixel color values are ignored when compressing.
743 // Output is an ETC1 compressed version of the data.
744 
etc1_encode_block(const etc1_byte * pIn,etc1_uint32 inMask,etc1_byte * pOut)745 void etc1_encode_block(const etc1_byte* pIn, etc1_uint32 inMask,
746         etc1_byte* pOut) {
747     etc1_byte colors[6];
748     etc1_byte flippedColors[6];
749     etc_average_colors_subblock(pIn, inMask, colors, false, false);
750     etc_average_colors_subblock(pIn, inMask, colors + 3, false, true);
751     etc_average_colors_subblock(pIn, inMask, flippedColors, true, false);
752     etc_average_colors_subblock(pIn, inMask, flippedColors + 3, true, true);
753 
754     etc_compressed a, b;
755     etc_encode_block_helper(pIn, inMask, colors, &a, false);
756     etc_encode_block_helper(pIn, inMask, flippedColors, &b, true);
757     take_best(&a, &b);
758     writeBigEndian(pOut, a.high);
759     writeBigEndian(pOut + 4, a.low);
760 }
761 
762 // Return the size of the encoded image data (does not include size of PKM header).
763 
etc1_get_encoded_data_size(etc1_uint32 width,etc1_uint32 height)764 etc1_uint32 etc1_get_encoded_data_size(etc1_uint32 width, etc1_uint32 height) {
765     return (((width + 3) & ~3) * ((height + 3) & ~3)) >> 1;
766 }
767 
etc_get_encoded_data_size(ETC2ImageFormat format,etc1_uint32 width,etc1_uint32 height)768 etc1_uint32 etc_get_encoded_data_size(ETC2ImageFormat format, etc1_uint32 width,
769                                       etc1_uint32 height) {
770     etc1_uint32 size = ((width + 3) & ~3) * ((height + 3) & ~3);
771     switch (format) {
772         case EtcRGB8:
773         case EtcRGB8A1:
774         case EtcR11:
775         case EtcSignedR11:
776             return size >> 1;
777         case EtcRG11:
778         case EtcSignedRG11:
779         case EtcRGBA8:
780             return size;
781         default:
782             assert(0);
783             return 0;
784     }
785 }
786 
etc_get_decoded_pixel_size(ETC2ImageFormat format)787 etc1_uint32 etc_get_decoded_pixel_size(ETC2ImageFormat format) {
788     switch (format) {
789         case EtcRGB8:
790             return 3;
791         case EtcRGBA8:
792             return 4;
793         case EtcRGB8A1:
794         case EtcR11:
795         case EtcSignedR11:
796             return 4;
797         case EtcRG11:
798         case EtcSignedRG11:
799             return 8;
800         default:
801             assert(0);
802             return 0;
803     }
804 }
805 
806 // Encode an entire image.
807 // pIn - pointer to the image data. Formatted such that the Red component of
808 //       pixel (x,y) is at pIn + pixelSize * x + stride * y + redOffset;
809 // pOut - pointer to encoded data. Must be large enough to store entire encoded image.
810 
etc1_encode_image(const etc1_byte * pIn,etc1_uint32 width,etc1_uint32 height,etc1_uint32 pixelSize,etc1_uint32 stride,etc1_byte * pOut)811 int etc1_encode_image(const etc1_byte* pIn, etc1_uint32 width, etc1_uint32 height,
812         etc1_uint32 pixelSize, etc1_uint32 stride, etc1_byte* pOut) {
813     if (pixelSize < 2 || pixelSize > 3) {
814         return -1;
815     }
816     static const unsigned short kYMask[] = { 0x0, 0xf, 0xff, 0xfff, 0xffff };
817     static const unsigned short kXMask[] = { 0x0, 0x1111, 0x3333, 0x7777,
818             0xffff };
819     etc1_byte block[ETC1_DECODED_BLOCK_SIZE];
820     etc1_byte encoded[ETC1_ENCODED_BLOCK_SIZE];
821 
822     etc1_uint32 encodedWidth = (width + 3) & ~3;
823     etc1_uint32 encodedHeight = (height + 3) & ~3;
824 
825     for (etc1_uint32 y = 0; y < encodedHeight; y += 4) {
826         etc1_uint32 yEnd = height - y;
827         if (yEnd > 4) {
828             yEnd = 4;
829         }
830         int ymask = kYMask[yEnd];
831         for (etc1_uint32 x = 0; x < encodedWidth; x += 4) {
832             etc1_uint32 xEnd = width - x;
833             if (xEnd > 4) {
834                 xEnd = 4;
835             }
836             int mask = ymask & kXMask[xEnd];
837             for (etc1_uint32 cy = 0; cy < yEnd; cy++) {
838                 etc1_byte* q = block + (cy * 4) * 3;
839                 const etc1_byte* p = pIn + pixelSize * x + stride * (y + cy);
840                 if (pixelSize == 3) {
841                     memcpy(q, p, xEnd * 3);
842                 } else {
843                     for (etc1_uint32 cx = 0; cx < xEnd; cx++) {
844                         int pixel = (p[1] << 8) | p[0];
845                         *q++ = convert5To8(pixel >> 11);
846                         *q++ = convert6To8(pixel >> 5);
847                         *q++ = convert5To8(pixel);
848                         p += pixelSize;
849                     }
850                 }
851             }
852             etc1_encode_block(block, mask, encoded);
853             memcpy(pOut, encoded, sizeof(encoded));
854             pOut += sizeof(encoded);
855         }
856     }
857     return 0;
858 }
859 
860 // Decode an entire image.
861 // pIn - pointer to encoded data.
862 // pOut - pointer to the image data. Will be written such that the Red component of
863 //       pixel (x,y) is at pIn + pixelSize * x + stride * y + redOffset. Must be
864 //        large enough to store entire image.
865 
866 
etc2_decode_image(const etc1_byte * pIn,ETC2ImageFormat format,etc1_byte * pOut,etc1_uint32 width,etc1_uint32 height,etc1_uint32 stride)867 int etc2_decode_image(const etc1_byte* pIn, ETC2ImageFormat format,
868         etc1_byte* pOut,
869         etc1_uint32 width, etc1_uint32 height,
870         etc1_uint32 stride) {
871     etc1_byte block[std::max({ETC1_DECODED_BLOCK_SIZE,
872                               ETC2_DECODED_RGB8A1_BLOCK_SIZE,
873                               EAC_DECODED_R11_BLOCK_SIZE,
874                               EAC_DECODED_RG11_BLOCK_SIZE})];
875     etc1_byte alphaBlock[EAC_DECODED_ALPHA_BLOCK_SIZE];
876 
877     etc1_uint32 encodedWidth = (width + 3) & ~3;
878     etc1_uint32 encodedHeight = (height + 3) & ~3;
879 
880     int pixelSize = etc_get_decoded_pixel_size(format);
881     bool isSigned = (format == EtcSignedR11 || format == EtcSignedRG11);
882 
883     for (etc1_uint32 y = 0; y < encodedHeight; y += 4) {
884         etc1_uint32 yEnd = height - y;
885         if (yEnd > 4) {
886             yEnd = 4;
887         }
888         for (etc1_uint32 x = 0; x < encodedWidth; x += 4) {
889             etc1_uint32 xEnd = width - x;
890             if (xEnd > 4) {
891                 xEnd = 4;
892             }
893             switch (format) {
894                 case EtcRGBA8:
895                     eac_decode_single_channel_block(pIn, 1, false, alphaBlock);
896                     pIn += EAC_ENCODE_ALPHA_BLOCK_SIZE;
897                     // Do not break
898                     // Fall through to EtcRGB8 to decode the RGB part
899                     [[fallthrough]];
900                 case EtcRGB8:
901                     etc2_decode_rgb_block(pIn, false, block);
902                     pIn += ETC1_ENCODED_BLOCK_SIZE;
903                     break;
904                 case EtcRGB8A1:
905                     etc2_decode_rgb_block(pIn, true, block);
906                     pIn += ETC1_ENCODED_BLOCK_SIZE;
907                     break;
908                 case EtcR11:
909                 case EtcSignedR11:
910                     eac_decode_single_channel_block(pIn, 4, isSigned, block);
911                     pIn += EAC_ENCODE_R11_BLOCK_SIZE;
912                     break;
913                 case EtcRG11:
914                 case EtcSignedRG11:
915                     // r channel
916                     eac_decode_single_channel_block(pIn, 4, isSigned, block);
917                     pIn += EAC_ENCODE_R11_BLOCK_SIZE;
918                     // g channel
919                     eac_decode_single_channel_block(pIn, 4, isSigned,
920                             block + EAC_DECODED_R11_BLOCK_SIZE);
921                     pIn += EAC_ENCODE_R11_BLOCK_SIZE;
922                     break;
923                 default:
924                     assert(0);
925             }
926             for (etc1_uint32 cy = 0; cy < yEnd; cy++) {
927                 etc1_byte* p = pOut + pixelSize * x + stride * (y + cy);
928                 switch (format) {
929                     case EtcRGB8:
930                     case EtcRGB8A1:
931                     case EtcR11:
932                     case EtcSignedR11: {
933                             const etc1_byte* q = block + (cy * 4) * pixelSize;
934                             memcpy(p, q, xEnd * pixelSize);
935                         }
936                         break;
937                     case EtcRG11:
938                     case EtcSignedRG11: {
939                             const etc1_byte* r = block + cy * EAC_DECODED_R11_BLOCK_SIZE / 4;
940                             const etc1_byte* g = block + cy * EAC_DECODED_R11_BLOCK_SIZE / 4 + EAC_DECODED_R11_BLOCK_SIZE;
941                             int channelSize = pixelSize / 2;
942                             for (etc1_uint32 cx = 0; cx < xEnd; cx++) {
943                                 memcpy(p, r, channelSize);
944                                 p += channelSize;
945                                 r += channelSize;
946                                 memcpy(p, g, channelSize);
947                                 p += channelSize;
948                                 g += channelSize;
949                             }
950                         }
951                         break;
952                     case EtcRGBA8: {
953                             const etc1_byte* q = block + (cy * 4) * 3;
954                             const etc1_byte* qa = alphaBlock + cy * 4;
955                             for (etc1_uint32 cx = 0; cx < xEnd; cx++) {
956                                 // copy rgb data
957                                 memcpy(p, q, 3);
958                                 p += 3;
959                                 q += 3;
960                                 *p++ = *qa++;
961                             }
962                         }
963                         break;
964                     default:
965                         assert(0);
966                 }
967             }
968         }
969     }
970     return 0;
971 }
972 
973 static const char kMagic[] = { 'P', 'K', 'M', ' ', '1', '0' };
974 
975 static const etc1_uint32 ETC1_PKM_FORMAT_OFFSET = 6;
976 static const etc1_uint32 ETC1_PKM_ENCODED_WIDTH_OFFSET = 8;
977 static const etc1_uint32 ETC1_PKM_ENCODED_HEIGHT_OFFSET = 10;
978 static const etc1_uint32 ETC1_PKM_WIDTH_OFFSET = 12;
979 static const etc1_uint32 ETC1_PKM_HEIGHT_OFFSET = 14;
980 
981 static const etc1_uint32 ETC1_RGB_NO_MIPMAPS = 0;
982 
writeBEUint16(etc1_byte * pOut,etc1_uint32 data)983 static void writeBEUint16(etc1_byte* pOut, etc1_uint32 data) {
984     pOut[0] = (etc1_byte) (data >> 8);
985     pOut[1] = (etc1_byte) data;
986 }
987 
readBEUint16(const etc1_byte * pIn)988 static etc1_uint32 readBEUint16(const etc1_byte* pIn) {
989     return (pIn[0] << 8) | pIn[1];
990 }
991 
992 // Format a PKM header
993 
etc1_pkm_format_header(etc1_byte * pHeader,etc1_uint32 width,etc1_uint32 height)994 void etc1_pkm_format_header(etc1_byte* pHeader, etc1_uint32 width, etc1_uint32 height) {
995     memcpy(pHeader, kMagic, sizeof(kMagic));
996     etc1_uint32 encodedWidth = (width + 3) & ~3;
997     etc1_uint32 encodedHeight = (height + 3) & ~3;
998     writeBEUint16(pHeader + ETC1_PKM_FORMAT_OFFSET, ETC1_RGB_NO_MIPMAPS);
999     writeBEUint16(pHeader + ETC1_PKM_ENCODED_WIDTH_OFFSET, encodedWidth);
1000     writeBEUint16(pHeader + ETC1_PKM_ENCODED_HEIGHT_OFFSET, encodedHeight);
1001     writeBEUint16(pHeader + ETC1_PKM_WIDTH_OFFSET, width);
1002     writeBEUint16(pHeader + ETC1_PKM_HEIGHT_OFFSET, height);
1003 }
1004 
1005 // Check if a PKM header is correctly formatted.
1006 
etc1_pkm_is_valid(const etc1_byte * pHeader)1007 etc1_bool etc1_pkm_is_valid(const etc1_byte* pHeader) {
1008     if (memcmp(pHeader, kMagic, sizeof(kMagic))) {
1009         return false;
1010     }
1011     etc1_uint32 format = readBEUint16(pHeader + ETC1_PKM_FORMAT_OFFSET);
1012     etc1_uint32 encodedWidth = readBEUint16(pHeader + ETC1_PKM_ENCODED_WIDTH_OFFSET);
1013     etc1_uint32 encodedHeight = readBEUint16(pHeader + ETC1_PKM_ENCODED_HEIGHT_OFFSET);
1014     etc1_uint32 width = readBEUint16(pHeader + ETC1_PKM_WIDTH_OFFSET);
1015     etc1_uint32 height = readBEUint16(pHeader + ETC1_PKM_HEIGHT_OFFSET);
1016     return format == ETC1_RGB_NO_MIPMAPS &&
1017             encodedWidth >= width && encodedWidth - width < 4 &&
1018             encodedHeight >= height && encodedHeight - height < 4;
1019 }
1020 
1021 // Read the image width from a PKM header
1022 
etc1_pkm_get_width(const etc1_byte * pHeader)1023 etc1_uint32 etc1_pkm_get_width(const etc1_byte* pHeader) {
1024     return readBEUint16(pHeader + ETC1_PKM_WIDTH_OFFSET);
1025 }
1026 
1027 // Read the image height from a PKM header
1028 
etc1_pkm_get_height(const etc1_byte * pHeader)1029 etc1_uint32 etc1_pkm_get_height(const etc1_byte* pHeader){
1030     return readBEUint16(pHeader + ETC1_PKM_HEIGHT_OFFSET);
1031 }
1032