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 "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 case EtcRGB8:
900 etc2_decode_rgb_block(pIn, false, block);
901 pIn += ETC1_ENCODED_BLOCK_SIZE;
902 break;
903 case EtcRGB8A1:
904 etc2_decode_rgb_block(pIn, true, block);
905 pIn += ETC1_ENCODED_BLOCK_SIZE;
906 break;
907 case EtcR11:
908 case EtcSignedR11:
909 eac_decode_single_channel_block(pIn, 4, isSigned, block);
910 pIn += EAC_ENCODE_R11_BLOCK_SIZE;
911 break;
912 case EtcRG11:
913 case EtcSignedRG11:
914 // r channel
915 eac_decode_single_channel_block(pIn, 4, isSigned, block);
916 pIn += EAC_ENCODE_R11_BLOCK_SIZE;
917 // g channel
918 eac_decode_single_channel_block(pIn, 4, isSigned,
919 block + EAC_DECODED_R11_BLOCK_SIZE);
920 pIn += EAC_ENCODE_R11_BLOCK_SIZE;
921 break;
922 default:
923 assert(0);
924 }
925 for (etc1_uint32 cy = 0; cy < yEnd; cy++) {
926 etc1_byte* p = pOut + pixelSize * x + stride * (y + cy);
927 switch (format) {
928 case EtcRGB8:
929 case EtcRGB8A1:
930 case EtcR11:
931 case EtcSignedR11: {
932 const etc1_byte* q = block + (cy * 4) * pixelSize;
933 memcpy(p, q, xEnd * pixelSize);
934 }
935 break;
936 case EtcRG11:
937 case EtcSignedRG11: {
938 const etc1_byte* r = block + cy * EAC_DECODED_R11_BLOCK_SIZE / 4;
939 const etc1_byte* g = block + cy * EAC_DECODED_R11_BLOCK_SIZE / 4 + EAC_DECODED_R11_BLOCK_SIZE;
940 int channelSize = pixelSize / 2;
941 for (etc1_uint32 cx = 0; cx < xEnd; cx++) {
942 memcpy(p, r, channelSize);
943 p += channelSize;
944 r += channelSize;
945 memcpy(p, g, channelSize);
946 p += channelSize;
947 g += channelSize;
948 }
949 }
950 break;
951 case EtcRGBA8: {
952 const etc1_byte* q = block + (cy * 4) * 3;
953 const etc1_byte* qa = alphaBlock + cy * 4;
954 for (etc1_uint32 cx = 0; cx < xEnd; cx++) {
955 // copy rgb data
956 memcpy(p, q, 3);
957 p += 3;
958 q += 3;
959 *p++ = *qa++;
960 }
961 }
962 break;
963 default:
964 assert(0);
965 }
966 }
967 }
968 }
969 return 0;
970 }
971
972 static const char kMagic[] = { 'P', 'K', 'M', ' ', '1', '0' };
973
974 static const etc1_uint32 ETC1_PKM_FORMAT_OFFSET = 6;
975 static const etc1_uint32 ETC1_PKM_ENCODED_WIDTH_OFFSET = 8;
976 static const etc1_uint32 ETC1_PKM_ENCODED_HEIGHT_OFFSET = 10;
977 static const etc1_uint32 ETC1_PKM_WIDTH_OFFSET = 12;
978 static const etc1_uint32 ETC1_PKM_HEIGHT_OFFSET = 14;
979
980 static const etc1_uint32 ETC1_RGB_NO_MIPMAPS = 0;
981
writeBEUint16(etc1_byte * pOut,etc1_uint32 data)982 static void writeBEUint16(etc1_byte* pOut, etc1_uint32 data) {
983 pOut[0] = (etc1_byte) (data >> 8);
984 pOut[1] = (etc1_byte) data;
985 }
986
readBEUint16(const etc1_byte * pIn)987 static etc1_uint32 readBEUint16(const etc1_byte* pIn) {
988 return (pIn[0] << 8) | pIn[1];
989 }
990
991 // Format a PKM header
992
etc1_pkm_format_header(etc1_byte * pHeader,etc1_uint32 width,etc1_uint32 height)993 void etc1_pkm_format_header(etc1_byte* pHeader, etc1_uint32 width, etc1_uint32 height) {
994 memcpy(pHeader, kMagic, sizeof(kMagic));
995 etc1_uint32 encodedWidth = (width + 3) & ~3;
996 etc1_uint32 encodedHeight = (height + 3) & ~3;
997 writeBEUint16(pHeader + ETC1_PKM_FORMAT_OFFSET, ETC1_RGB_NO_MIPMAPS);
998 writeBEUint16(pHeader + ETC1_PKM_ENCODED_WIDTH_OFFSET, encodedWidth);
999 writeBEUint16(pHeader + ETC1_PKM_ENCODED_HEIGHT_OFFSET, encodedHeight);
1000 writeBEUint16(pHeader + ETC1_PKM_WIDTH_OFFSET, width);
1001 writeBEUint16(pHeader + ETC1_PKM_HEIGHT_OFFSET, height);
1002 }
1003
1004 // Check if a PKM header is correctly formatted.
1005
etc1_pkm_is_valid(const etc1_byte * pHeader)1006 etc1_bool etc1_pkm_is_valid(const etc1_byte* pHeader) {
1007 if (memcmp(pHeader, kMagic, sizeof(kMagic))) {
1008 return false;
1009 }
1010 etc1_uint32 format = readBEUint16(pHeader + ETC1_PKM_FORMAT_OFFSET);
1011 etc1_uint32 encodedWidth = readBEUint16(pHeader + ETC1_PKM_ENCODED_WIDTH_OFFSET);
1012 etc1_uint32 encodedHeight = readBEUint16(pHeader + ETC1_PKM_ENCODED_HEIGHT_OFFSET);
1013 etc1_uint32 width = readBEUint16(pHeader + ETC1_PKM_WIDTH_OFFSET);
1014 etc1_uint32 height = readBEUint16(pHeader + ETC1_PKM_HEIGHT_OFFSET);
1015 return format == ETC1_RGB_NO_MIPMAPS &&
1016 encodedWidth >= width && encodedWidth - width < 4 &&
1017 encodedHeight >= height && encodedHeight - height < 4;
1018 }
1019
1020 // Read the image width from a PKM header
1021
etc1_pkm_get_width(const etc1_byte * pHeader)1022 etc1_uint32 etc1_pkm_get_width(const etc1_byte* pHeader) {
1023 return readBEUint16(pHeader + ETC1_PKM_WIDTH_OFFSET);
1024 }
1025
1026 // Read the image height from a PKM header
1027
etc1_pkm_get_height(const etc1_byte * pHeader)1028 etc1_uint32 etc1_pkm_get_height(const etc1_byte* pHeader){
1029 return readBEUint16(pHeader + ETC1_PKM_HEIGHT_OFFSET);
1030 }
1031