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