1 // Copyright 2009 Google Inc.
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
7 // http://www.apache.org/licenses/LICENSE-2.0
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.
15 // This is branched from frameworks/base/opengl/include/ETC1/etc1.cc
17 // It has been modified as follows:
18 // 1. Unused or not related to encoding methods have been removed.
19 // 2. Methods related to determining the size of the output texture have been
21 // 3. EncodeImage has been modified to operate directly on a bitmap, work with
22 // 4bpp input, and resize the output to a power-of-two size in order to work
23 // with the graphics driver.
31 /* From http://www.khronos.org/registry/gles/extensions/OES/OES_compressed_ETC1_RGB8_texture.txt
33 The number of bits that represent a 4x4 texel block is 64 bits if
34 <internalformat> is given by ETC1_RGB8_OES.
36 The data for a block is a number of bytes,
38 {q0, q1, q2, q3, q4, q5, q6, q7}
40 where byte q0 is located at the lowest memory address and q7 at
41 the highest. The 64 bits specifying the block is then represented
42 by the following 64 bit integer:
44 int64bit = 256*(256*(256*(256*(256*(256*(256*q0+q1)+q2)+q3)+q4)+q5)+q6)+q7;
48 a) bit layout in bits 63 through 32 if diffbit = 0
50 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48
51 -----------------------------------------------
52 | base col1 | base col2 | base col1 | base col2 |
53 | R1 (4bits)| R2 (4bits)| G1 (4bits)| G2 (4bits)|
54 -----------------------------------------------
56 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32
57 ---------------------------------------------------
58 | base col1 | base col2 | table | table |diff|flip|
59 | B1 (4bits)| B2 (4bits)| cw 1 | cw 2 |bit |bit |
60 ---------------------------------------------------
63 b) bit layout in bits 63 through 32 if diffbit = 1
65 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48
66 -----------------------------------------------
67 | base col1 | dcol 2 | base col1 | dcol 2 |
68 | R1' (5 bits) | dR2 | G1' (5 bits) | dG2 |
69 -----------------------------------------------
71 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32
72 ---------------------------------------------------
73 | base col 1 | dcol 2 | table | table |diff|flip|
74 | B1' (5 bits) | dB2 | cw 1 | cw 2 |bit |bit |
75 ---------------------------------------------------
78 c) bit layout in bits 31 through 0 (in both cases)
80 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16
81 -----------------------------------------------
82 | most significant pixel index bits |
83 | p| o| n| m| l| k| j| i| h| g| f| e| d| c| b| a|
84 -----------------------------------------------
86 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
87 --------------------------------------------------
88 | least significant pixel index bits |
89 | p| o| n| m| l| k| j| i| h| g| f| e| d| c | b | a |
90 --------------------------------------------------
93 Add table 3.17.2: Intensity modifier sets for ETC1 compressed textures:
95 table codeword modifier table
96 ------------------ ----------------------
107 Add table 3.17.3 Mapping from pixel index values to modifier values for
108 ETC1 compressed textures:
112 msb lsb resulting modifier value
113 ----- ----- -------------------------
114 1 1 -b (large negative value)
115 1 0 -a (small negative value)
116 0 0 a (small positive value)
117 0 1 b (large positive value)
122 #define ETC1_ENCODED_BLOCK_SIZE 8
123 #define ETC1_DECODED_BLOCK_SIZE 48
127 typedef unsigned char etc1_byte;
128 typedef int etc1_bool;
129 typedef unsigned int etc1_uint32;
131 static const int kModifierTable[] = {
133 /* 1 */5, 17, -5, -17,
134 /* 2 */9, 29, -9, -29,
135 /* 3 */13, 42, -13, -42,
136 /* 4 */18, 60, -18, -60,
137 /* 5 */24, 80, -24, -80,
138 /* 6 */33, 106, -33, -106,
139 /* 7 */47, 183, -47, -183 };
142 static inline etc1_byte clamp(int x) {
143 return (etc1_byte) (x >= 0 ? (x < 255 ? x : 255) : 0);
147 inline int convert4To8(int b) {
153 inline int convert5To8(int b) {
155 return (c << 3) | (c >> 2);
159 inline int convert6To8(int b) {
161 return (c << 2) | (c >> 4);
165 inline int divideBy255(int d) {
166 return (d + 128 + (d >> 8)) >> 8;
170 inline int convert8To4(int b) {
172 return divideBy255(c * 15);
176 inline int convert8To5(int b) {
178 return divideBy255(c * 31);
184 etc1_uint32 score; // Lower is more accurate
188 inline void take_best(etc_compressed* a, const etc_compressed* b) {
189 if (a->score > b->score) {
195 void etc_average_colors_subblock(const etc1_byte* pIn, etc1_uint32 inMask,
196 etc1_byte* pColors, bool flipped, bool second) {
206 for (int y = 0; y < 2; y++) {
208 for (int x = 0; x < 4; x++) {
210 if (inMask & (1 << i)) {
211 const etc1_byte* p = pIn + i * 3;
223 for (int y = 0; y < 4; y++) {
224 for (int x = 0; x < 2; x++) {
227 if (inMask & (1 << i)) {
228 const etc1_byte* p = pIn + i * 3;
236 pColors[0] = (etc1_byte)((r + 4) >> 3);
237 pColors[1] = (etc1_byte)((g + 4) >> 3);
238 pColors[2] = (etc1_byte)((b + 4) >> 3);
242 inline int square(int x) {
246 static etc1_uint32 chooseModifier(const etc1_byte* pBaseColors,
247 const etc1_byte* pIn, etc1_uint32 *pLow, int bitIndex,
248 const int* pModifierTable) {
249 etc1_uint32 bestScore = ~0;
254 int r = pBaseColors[0];
255 int g = pBaseColors[1];
256 int b = pBaseColors[2];
257 for (int i = 0; i < 4; i++) {
258 int modifier = pModifierTable[i];
259 int decodedG = clamp(g + modifier);
260 etc1_uint32 score = (etc1_uint32) (6 * square(decodedG - pixelG));
261 if (score >= bestScore) {
264 int decodedR = clamp(r + modifier);
265 score += (etc1_uint32) (3 * square(decodedR - pixelR));
266 if (score >= bestScore) {
269 int decodedB = clamp(b + modifier);
270 score += (etc1_uint32) square(decodedB - pixelB);
271 if (score < bestScore) {
276 etc1_uint32 lowMask = (((bestIndex >> 1) << 16) | (bestIndex & 1))
283 void etc_encode_subblock_helper(const etc1_byte* pIn, etc1_uint32 inMask,
284 etc_compressed* pCompressed, bool flipped, bool second,
285 const etc1_byte* pBaseColors, const int* pModifierTable) {
286 int score = pCompressed->score;
292 for (int y = 0; y < 2; y++) {
294 for (int x = 0; x < 4; x++) {
296 if (inMask & (1 << i)) {
297 score += chooseModifier(pBaseColors, pIn + i * 3,
298 &pCompressed->low, yy + x * 4, pModifierTable);
307 for (int y = 0; y < 4; y++) {
308 for (int x = 0; x < 2; x++) {
311 if (inMask & (1 << i)) {
312 score += chooseModifier(pBaseColors, pIn + i * 3,
313 &pCompressed->low, y + xx * 4, pModifierTable);
318 pCompressed->score = score;
321 static bool inRange4bitSigned(int color) {
322 return color >= -4 && color <= 3;
325 static void etc_encodeBaseColors(etc1_byte* pBaseColors,
326 const etc1_byte* pColors, etc_compressed* pCompressed) {
327 int r1, g1, b1, r2, g2, b2; // 8 bit base colors for sub-blocks
330 int r51 = convert8To5(pColors[0]);
331 int g51 = convert8To5(pColors[1]);
332 int b51 = convert8To5(pColors[2]);
333 int r52 = convert8To5(pColors[3]);
334 int g52 = convert8To5(pColors[4]);
335 int b52 = convert8To5(pColors[5]);
337 r1 = convert5To8(r51);
338 g1 = convert5To8(g51);
339 b1 = convert5To8(b51);
345 differential = inRange4bitSigned(dr) && inRange4bitSigned(dg)
346 && inRange4bitSigned(db);
348 r2 = convert5To8(r51 + dr);
349 g2 = convert5To8(g51 + dg);
350 b2 = convert5To8(b51 + db);
351 pCompressed->high |= (r51 << 27) | ((7 & dr) << 24) | (g51 << 19)
352 | ((7 & dg) << 16) | (b51 << 11) | ((7 & db) << 8) | 2;
357 int r41 = convert8To4(pColors[0]);
358 int g41 = convert8To4(pColors[1]);
359 int b41 = convert8To4(pColors[2]);
360 int r42 = convert8To4(pColors[3]);
361 int g42 = convert8To4(pColors[4]);
362 int b42 = convert8To4(pColors[5]);
363 r1 = convert4To8(r41);
364 g1 = convert4To8(g41);
365 b1 = convert4To8(b41);
366 r2 = convert4To8(r42);
367 g2 = convert4To8(g42);
368 b2 = convert4To8(b42);
369 pCompressed->high |= (r41 << 28) | (r42 << 24) | (g41 << 20) | (g42
370 << 16) | (b41 << 12) | (b42 << 8);
381 void etc_encode_block_helper(const etc1_byte* pIn, etc1_uint32 inMask,
382 const etc1_byte* pColors, etc_compressed* pCompressed, bool flipped) {
383 pCompressed->score = ~0;
384 pCompressed->high = (flipped ? 1 : 0);
385 pCompressed->low = 0;
387 etc1_byte pBaseColors[6];
389 etc_encodeBaseColors(pBaseColors, pColors, pCompressed);
391 int originalHigh = pCompressed->high;
393 const int* pModifierTable = kModifierTable;
394 for (int i = 0; i < 8; i++, pModifierTable += 4) {
397 temp.high = originalHigh | (i << 5);
399 etc_encode_subblock_helper(pIn, inMask, &temp, flipped, false,
400 pBaseColors, pModifierTable);
401 take_best(pCompressed, &temp);
403 pModifierTable = kModifierTable;
404 etc_compressed firstHalf = *pCompressed;
405 for (int i = 0; i < 8; i++, pModifierTable += 4) {
407 temp.score = firstHalf.score;
408 temp.high = firstHalf.high | (i << 2);
409 temp.low = firstHalf.low;
410 etc_encode_subblock_helper(pIn, inMask, &temp, flipped, true,
411 pBaseColors + 3, pModifierTable);
415 take_best(pCompressed, &temp);
420 static void writeBigEndian(etc1_byte* pOut, etc1_uint32 d) {
421 pOut[0] = (etc1_byte)(d >> 24);
422 pOut[1] = (etc1_byte)(d >> 16);
423 pOut[2] = (etc1_byte)(d >> 8);
424 pOut[3] = (etc1_byte) d;
427 // Input is a 4 x 4 square of 3-byte pixels in form R, G, B
428 // inmask is a 16-bit mask where bit (1 << (x + y * 4)) tells whether the corresponding (x,y)
429 // pixel is valid or not. Invalid pixel color values are ignored when compressing.
430 // Output is an ETC1 compressed version of the data.
432 static void etc1_encode_block(etc1_byte* pIn, int inMask, etc1_byte* pOut) {
434 etc1_byte flippedColors[6];
435 etc_average_colors_subblock(pIn, inMask, colors, false, false);
436 etc_average_colors_subblock(pIn, inMask, colors + 3, false, true);
437 etc_average_colors_subblock(pIn, inMask, flippedColors, true, false);
438 etc_average_colors_subblock(pIn, inMask, flippedColors + 3, true, true);
441 etc_encode_block_helper(pIn, inMask, colors, &a, false);
442 etc_encode_block_helper(pIn, inMask, flippedColors, &b, true);
444 writeBigEndian(pOut, a.high);
445 writeBigEndian(pOut + 4, a.low);
448 } // anonymous namespace
450 // Return the size of the encoded image data.
452 etc1_uint32 etc1_get_encoded_data_size(etc1_uint32 width, etc1_uint32 height) {
453 return (((width + 3) & ~3) * ((height + 3) & ~3)) >> 1;
456 // Encode an entire image.
457 // pIn - pointer to the image data. Formatted such that the Red component of
458 // pixel (x,y) is at pIn + pixelSize * x + stride * y + redOffset;
459 // pOut - pointer to encoded data. Must be large enough to store entire encoded image.
460 // Returns false if there was an error.
462 bool etc1_encode_image(const etc1_byte* pIn, etc1_uint32 width, etc1_uint32 height,
463 etc1_uint32 pixelSize, etc1_uint32 stride, etc1_byte* pOut, etc1_uint32 outWidth,
464 etc1_uint32 outHeight) {
468 static const unsigned short kYMask[] = { 0x0, 0xf, 0xff, 0xfff, 0xffff };
469 static const unsigned short kXMask[] = { 0x0, 0x1111, 0x3333, 0x7777,
471 etc1_byte block[ETC1_DECODED_BLOCK_SIZE];
472 etc1_byte encoded[ETC1_ENCODED_BLOCK_SIZE];
474 etc1_uint32 encodedWidth = (outWidth + 3) & ~3;
475 etc1_uint32 encodedHeight = (outHeight + 3) & ~3;
477 for (etc1_uint32 y = 0; y < encodedHeight; y += 4) {
478 etc1_uint32 yEnd = outHeight - y;
482 int ymask = kYMask[yEnd];
483 for (etc1_uint32 x = 0; x < encodedWidth; x += 4) {
484 etc1_uint32 xEnd = outWidth - x;
488 const int mask = ymask & kXMask[xEnd];
489 // Shortcut to only encode blocks which overlap the input image.
490 // The outside region will be undefined garbage.
491 if (x < width && y < height) {
492 for (etc1_uint32 cy = 0; cy < yEnd; cy++) {
493 etc1_byte* q = block + (cy * 4) * 3;
494 const etc1_byte* p = pIn + pixelSize * x + stride * (y + cy);
495 if (y + cy < height) {
496 for (etc1_uint32 cx = 0; cx < xEnd; cx++) {
497 if (x + cx < width) {
498 if (pixelSize == 4) {
499 // RGBA_8888: Filter out the input's alpha channel.
504 // RGB_565: Unpack input's 2 bytes to RGB.
505 int pixel = (p[1] << 8) | p[0];
506 *q++ = convert5To8(pixel >> 11);
507 *q++ = convert6To8(pixel >> 5);
508 *q++ = convert5To8(pixel);
512 // Out of bounds of the input image but within a
513 // block that must be properly encoded, so pad
514 // the original image with the last pixel.
522 // Out of bounds of the input image but within a
523 // block that must be properly encoded, so pad the
524 // original image with the last pixel.
525 *(q + 0) = *(q - 12);
526 *(q + 1) = *(q - 11);
527 *(q + 2) = *(q - 10);
531 etc1_encode_block(block, mask, encoded);
532 memcpy(pOut, encoded, sizeof(encoded));
533 } else if (x == width && width > 0 && height > 0) {
534 // We need to extend the block right after to the last pixel of
535 // the source bitmap for the blending to work nicely.
536 for (etc1_uint32 cy = 0; cy < yEnd; cy++) {
537 etc1_byte* q = block + (cy * 4) * 3;
538 const etc1_byte* p = pIn + pixelSize * (width - 1) +
539 stride * std::min(y + cy, height - 1);
540 for (etc1_uint32 cx = 0; cx < xEnd; cx++) {
541 if (pixelSize == 4) {
542 // RGBA_8888: Filter out the input's alpha channel.
547 // RGB_565: Unpack input's 2 bytes to RGB.
548 int pixel = (p[1] << 8) | p[0];
549 *q++ = convert5To8(pixel >> 11);
550 *q++ = convert6To8(pixel >> 5);
551 *q++ = convert5To8(pixel);
555 etc1_encode_block(block, mask, encoded);
556 memcpy(pOut, encoded, sizeof(encoded));
557 } else if (y == height && width > 0 && height > 0) {
558 // We need to extend the block right after to the last pixel of
559 // the source bitmap for the blending to work nicely.
560 for (etc1_uint32 cy = 0; cy < yEnd; cy++) {
561 etc1_byte* q = block + (cy * 4) * 3;
562 for (etc1_uint32 cx = 0; cx < xEnd; cx++) {
563 const etc1_byte* p = pIn +
564 pixelSize * std::min(x + cx, width - 1) +
565 stride * (height - 1);
566 if (pixelSize == 4) {
567 // RGBA_8888: Filter out the input's alpha channel.
572 // RGB_565: Unpack input's 2 bytes to RGB.
573 int pixel = (p[1] << 8) | p[0];
574 *q++ = convert5To8(pixel >> 11);
575 *q++ = convert6To8(pixel >> 5);
576 *q++ = convert5To8(pixel);
580 etc1_encode_block(block, mask, encoded);
581 memcpy(pOut, encoded, sizeof(encoded));
583 memset(pOut, 0xFF, sizeof(encoded));
585 pOut += sizeof(encoded);