| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 1 | /* libs/opengles/dxt.cpp | 
|  | 2 | ** | 
|  | 3 | ** Copyright 2007, The Android Open Source Project | 
|  | 4 | ** | 
|  | 5 | ** Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | 6 | ** you may not use this file except in compliance with the License. | 
|  | 7 | ** You may obtain a copy of the License at | 
|  | 8 | ** | 
|  | 9 | **     http://www.apache.org/licenses/LICENSE-2.0 | 
|  | 10 | ** | 
|  | 11 | ** Unless required by applicable law or agreed to in writing, software | 
|  | 12 | ** distributed under the License is distributed on an "AS IS" BASIS, | 
|  | 13 | ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | 14 | ** See the License for the specific language governing permissions and | 
|  | 15 | ** limitations under the License. | 
|  | 16 | */ | 
|  | 17 |  | 
|  | 18 | #define TIMING 0 | 
|  | 19 |  | 
|  | 20 | #if TIMING | 
|  | 21 | #include <sys/time.h> // for optimization timing | 
|  | 22 | #include <stdio.h> | 
|  | 23 | #include <stdlib.h> | 
|  | 24 | #endif | 
|  | 25 |  | 
|  | 26 | #include <GLES/gl.h> | 
|  | 27 | #include <utils/Endian.h> | 
|  | 28 |  | 
|  | 29 | #include "context.h" | 
|  | 30 |  | 
|  | 31 | #define TIMING 0 | 
|  | 32 |  | 
|  | 33 | namespace android { | 
|  | 34 |  | 
|  | 35 | static uint8_t avg23tab[64*64]; | 
|  | 36 | static volatile int tables_initialized = 0; | 
|  | 37 |  | 
|  | 38 | // Definitions below are equivalent to these over the valid range of arguments | 
|  | 39 | //  #define div5(x) ((x)/5) | 
|  | 40 | //  #define div7(x) ((x)/7) | 
|  | 41 |  | 
|  | 42 | // Use fixed-point to divide by 5 and 7 | 
|  | 43 | // 3277 = 2^14/5 + 1 | 
|  | 44 | // 2341 = 2^14/7 + 1 | 
|  | 45 | #define div5(x) (((x)*3277) >> 14) | 
|  | 46 | #define div7(x) (((x)*2341) >> 14) | 
|  | 47 |  | 
|  | 48 | // Table with entry [a << 6 | b] = (2*a + b)/3 for 0 <= a,b < 64 | 
|  | 49 | #define avg23(x0,x1) avg23tab[((x0) << 6) | (x1)] | 
|  | 50 |  | 
|  | 51 | // Extract 5/6/5 RGB | 
|  | 52 | #define red(x)   (((x) >> 11) & 0x1f) | 
|  | 53 | #define green(x) (((x) >>  5) & 0x3f) | 
|  | 54 | #define blue(x)  ( (x)        & 0x1f) | 
|  | 55 |  | 
|  | 56 | /* | 
|  | 57 | * Convert 5/6/5 RGB (as 3 ints) to 8/8/8 | 
|  | 58 | * | 
|  | 59 | * Operation count: 8 <<, 0 &, 5 | | 
|  | 60 | */ | 
|  | 61 | inline static int rgb565SepTo888(int r, int g, int b) | 
|  | 62 |  | 
|  | 63 | { | 
|  | 64 | return ((((r << 3) | (r >> 2)) << 16) | | 
|  | 65 | (((g << 2) | (g >> 4)) <<  8) | | 
|  | 66 | ((b << 3) | (b >> 2))); | 
|  | 67 | } | 
|  | 68 |  | 
|  | 69 | /* | 
|  | 70 | * Convert 5/6/5 RGB (as a single 16-bit word) to 8/8/8 | 
|  | 71 | * | 
|  | 72 | *                   r4r3r2r1 r0g5g4g3 g2g1g0b4 b3b2b1b0   rgb | 
|  | 73 | *            r4r3r2 r1r0g5g4 g3g2g1g0 b4b3b2b1 b0 0 0 0   rgb << 3 | 
|  | 74 | * r4r3r2r1 r0r4r3r2 g5g4g3g2 g1g0g5g4 b4b3b2b1 b0b4b3b2   desired result | 
|  | 75 | * | 
|  | 76 | * Construct the 24-bit RGB word as: | 
|  | 77 | * | 
|  | 78 | * r4r3r2r1 r0------ -------- -------- -------- --------  (rgb << 8) & 0xf80000 | 
|  | 79 | *            r4r3r2 -------- -------- -------- --------  (rgb << 3) & 0x070000 | 
|  | 80 | *                   g5g4g3g2 g1g0---- -------- --------  (rgb << 5) & 0x00fc00 | 
|  | 81 | *                                g5g4 -------- --------  (rgb >> 1) & 0x000300 | 
|  | 82 | *                                     b4b3b2b1 b0------  (rgb << 3) & 0x0000f8 | 
|  | 83 | *                                                b4b3b2  (rgb >> 2) & 0x000007 | 
|  | 84 | * | 
|  | 85 | * Operation count: 5 <<, 6 &, 5 | (n.b. rgb >> 3 is used twice) | 
|  | 86 | */ | 
|  | 87 | inline static int rgb565To888(int rgb) | 
|  | 88 |  | 
|  | 89 | { | 
|  | 90 | int rgb3 = rgb >> 3; | 
|  | 91 | return (((rgb << 8) & 0xf80000) | | 
|  | 92 | ( rgb3      & 0x070000) | | 
|  | 93 | ((rgb << 5) & 0x00fc00) | | 
|  | 94 | ((rgb >> 1) & 0x000300) | | 
|  | 95 | ( rgb3      & 0x0000f8) | | 
|  | 96 | ((rgb >> 2) & 0x000007)); | 
|  | 97 | } | 
|  | 98 |  | 
|  | 99 | #if __BYTE_ORDER == __BIG_ENDIAN | 
|  | 100 | static uint32_t swap(uint32_t x) { | 
|  | 101 | int b0 = (x >> 24) & 0xff; | 
|  | 102 | int b1 = (x >> 16) & 0xff; | 
|  | 103 | int b2 = (x >>  8) & 0xff; | 
|  | 104 | int b3 = (x      ) & 0xff; | 
|  | 105 |  | 
|  | 106 | return (uint32_t)((b3 << 24) | (b2 << 16) | (b1 << 8) | b0); | 
|  | 107 | } | 
|  | 108 | #endif | 
|  | 109 |  | 
|  | 110 | static void | 
|  | 111 | init_tables() | 
|  | 112 | { | 
|  | 113 | if (tables_initialized) { | 
|  | 114 | return; | 
|  | 115 | } | 
|  | 116 |  | 
|  | 117 | for (int i = 0; i < 64; i++) { | 
|  | 118 | for (int j = 0; j < 64; j++) { | 
|  | 119 | int avg = (2*i + j)/3; | 
|  | 120 | avg23tab[(i << 6) | j] = avg; | 
|  | 121 | } | 
|  | 122 | } | 
|  | 123 |  | 
|  | 124 | asm volatile ("" : : : "memory"); | 
|  | 125 | tables_initialized = 1; | 
|  | 126 | } | 
|  | 127 |  | 
|  | 128 | /* | 
|  | 129 | * Utility to scan a DXT1 compressed texture to determine whether it | 
|  | 130 | * contains a transparent pixel (color0 < color1, code == 3).  This | 
|  | 131 | * may be useful if the application lacks information as to whether | 
|  | 132 | * the true format is GL_COMPRESSED_RGB_S3TC_DXT1_EXT or | 
|  | 133 | * GL_COMPRESSED_RGBA_S3TC_DXT1_EXT. | 
|  | 134 | */ | 
|  | 135 | bool | 
|  | 136 | DXT1HasAlpha(const GLvoid *data, int width, int height) { | 
|  | 137 | #if TIMING | 
|  | 138 | struct timeval start_t, end_t; | 
|  | 139 | struct timezone tz; | 
|  | 140 |  | 
|  | 141 | gettimeofday(&start_t, &tz); | 
|  | 142 | #endif | 
|  | 143 |  | 
|  | 144 | bool hasAlpha = false; | 
|  | 145 |  | 
|  | 146 | int xblocks = (width + 3)/4; | 
|  | 147 | int yblocks = (height + 3)/4; | 
|  | 148 | int numblocks = xblocks*yblocks; | 
|  | 149 |  | 
|  | 150 | uint32_t const *d32 = (uint32_t *)data; | 
|  | 151 | for (int b = 0; b < numblocks; b++) { | 
|  | 152 | uint32_t colors = *d32++; | 
|  | 153 |  | 
|  | 154 | #if __BYTE_ORDER == __BIG_ENDIAN | 
|  | 155 | colors = swap(colors); | 
|  | 156 | #endif | 
|  | 157 |  | 
|  | 158 | uint16_t color0 = colors & 0xffff; | 
|  | 159 | uint16_t color1 = colors >> 16; | 
|  | 160 |  | 
|  | 161 | if (color0 < color1) { | 
|  | 162 | // There's no need to endian-swap within 'bits' | 
|  | 163 | // since we don't care which pixel is the transparent one | 
|  | 164 | uint32_t bits = *d32++; | 
|  | 165 |  | 
|  | 166 | // Detect if any (odd, even) pair of bits are '11' | 
|  | 167 | //      bits: b31 b30 b29 ... b3 b2 b1 b0 | 
|  | 168 | // bits >> 1: b31 b31 b30 ... b4 b3 b2 b1 | 
|  | 169 | //         &: b31 (b31 & b30) (b29 & b28) ... (b2 & b1) (b1 & b0) | 
|  | 170 | //  & 0x55..:   0 (b31 & b30)       0     ...     0     (b1 & b0) | 
|  | 171 | if (((bits & (bits >> 1)) & 0x55555555) != 0) { | 
|  | 172 | hasAlpha = true; | 
|  | 173 | goto done; | 
|  | 174 | } | 
|  | 175 | } else { | 
|  | 176 | // Skip 4 bytes | 
|  | 177 | ++d32; | 
|  | 178 | } | 
|  | 179 | } | 
|  | 180 |  | 
|  | 181 | done: | 
|  | 182 | #if TIMING | 
|  | 183 | gettimeofday(&end_t, &tz); | 
|  | 184 | long usec = (end_t.tv_sec - start_t.tv_sec)*1000000 + | 
|  | 185 | (end_t.tv_usec - start_t.tv_usec); | 
|  | 186 |  | 
|  | 187 | printf("Scanned w=%d h=%d in %ld usec\n", width, height, usec); | 
|  | 188 | #endif | 
|  | 189 |  | 
|  | 190 | return hasAlpha; | 
|  | 191 | } | 
|  | 192 |  | 
|  | 193 | static void | 
|  | 194 | decodeDXT1(const GLvoid *data, int width, int height, | 
|  | 195 | void *surface, int stride, | 
|  | 196 | bool hasAlpha) | 
|  | 197 |  | 
|  | 198 | { | 
|  | 199 | init_tables(); | 
|  | 200 |  | 
|  | 201 | uint32_t const *d32 = (uint32_t *)data; | 
|  | 202 |  | 
|  | 203 | // Color table for the current block | 
|  | 204 | uint16_t c[4]; | 
|  | 205 | c[0] = c[1] = c[2] = c[3] = 0; | 
|  | 206 |  | 
|  | 207 | // Specified colors from the previous block | 
|  | 208 | uint16_t prev_color0 = 0x0000; | 
|  | 209 | uint16_t prev_color1 = 0x0000; | 
|  | 210 |  | 
|  | 211 | uint16_t* rowPtr = (uint16_t*)surface; | 
|  | 212 | for (int base_y = 0; base_y < height; base_y += 4, rowPtr += 4*stride) { | 
|  | 213 | uint16_t *blockPtr = rowPtr; | 
|  | 214 | for (int base_x = 0; base_x < width; base_x += 4, blockPtr += 4) { | 
|  | 215 | uint32_t colors = *d32++; | 
|  | 216 | uint32_t bits = *d32++; | 
|  | 217 |  | 
|  | 218 | #if __BYTE_ORDER == __BIG_ENDIAN | 
|  | 219 | colors = swap(colors); | 
|  | 220 | bits = swap(bits); | 
|  | 221 | #endif | 
|  | 222 |  | 
|  | 223 | // Raw colors | 
|  | 224 | uint16_t color0 = colors & 0xffff; | 
|  | 225 | uint16_t color1 = colors >> 16; | 
|  | 226 |  | 
|  | 227 | // If the new block has the same base colors as the | 
|  | 228 | // previous one, we don't need to recompute the color | 
|  | 229 | // table c[] | 
|  | 230 | if (color0 != prev_color0 || color1 != prev_color1) { | 
|  | 231 | // Store raw colors for comparison with next block | 
|  | 232 | prev_color0 = color0; | 
|  | 233 | prev_color1 = color1; | 
|  | 234 |  | 
|  | 235 | int r0 =   red(color0); | 
|  | 236 | int g0 = green(color0); | 
|  | 237 | int b0 =  blue(color0); | 
|  | 238 |  | 
|  | 239 | int r1 =   red(color1); | 
|  | 240 | int g1 = green(color1); | 
|  | 241 | int b1 =  blue(color1); | 
|  | 242 |  | 
|  | 243 | if (hasAlpha) { | 
|  | 244 | c[0] = (r0 << 11) | ((g0 >> 1) << 6) | (b0 << 1) | 0x1; | 
|  | 245 | c[1] = (r1 << 11) | ((g1 >> 1) << 6) | (b1 << 1) | 0x1; | 
|  | 246 | } else { | 
|  | 247 | c[0] = color0; | 
|  | 248 | c[1] = color1; | 
|  | 249 | } | 
|  | 250 |  | 
|  | 251 | int r2, g2, b2, r3, g3, b3, a3; | 
|  | 252 |  | 
|  | 253 | int bbits = bits >> 1; | 
|  | 254 | bool has2 = ((bbits & ~bits) & 0x55555555) != 0; | 
|  | 255 | bool has3 = ((bbits &  bits) & 0x55555555) != 0; | 
|  | 256 |  | 
|  | 257 | if (has2 || has3) { | 
|  | 258 | if (color0 > color1) { | 
|  | 259 | r2 = avg23(r0, r1); | 
|  | 260 | g2 = avg23(g0, g1); | 
|  | 261 | b2 = avg23(b0, b1); | 
|  | 262 |  | 
|  | 263 | r3 = avg23(r1, r0); | 
|  | 264 | g3 = avg23(g1, g0); | 
|  | 265 | b3 = avg23(b1, b0); | 
|  | 266 | a3 = 1; | 
|  | 267 | } else { | 
|  | 268 | r2 = (r0 + r1) >> 1; | 
|  | 269 | g2 = (g0 + g1) >> 1; | 
|  | 270 | b2 = (b0 + b1) >> 1; | 
|  | 271 |  | 
|  | 272 | r3 = g3 = b3 = a3 = 0; | 
|  | 273 | } | 
|  | 274 | if (hasAlpha) { | 
|  | 275 | c[2] = (r2 << 11) | ((g2 >> 1) << 6) | | 
|  | 276 | (b2 << 1) | 0x1; | 
|  | 277 | c[3] = (r3 << 11) | ((g3 >> 1) << 6) | | 
|  | 278 | (b3 << 1) | a3; | 
|  | 279 | } else { | 
|  | 280 | c[2] = (r2 << 11) | (g2 << 5) | b2; | 
|  | 281 | c[3] = (r3 << 11) | (g3 << 5) | b3; | 
|  | 282 | } | 
|  | 283 | } | 
|  | 284 | } | 
|  | 285 |  | 
|  | 286 | uint16_t* blockRowPtr = blockPtr; | 
|  | 287 | for (int y = 0; y < 4; y++, blockRowPtr += stride) { | 
|  | 288 | // Don't process rows past the botom | 
|  | 289 | if (base_y + y >= height) { | 
|  | 290 | break; | 
|  | 291 | } | 
|  | 292 |  | 
|  | 293 | int w = min(width - base_x, 4); | 
|  | 294 | for (int x = 0; x < w; x++) { | 
|  | 295 | int code = bits & 0x3; | 
|  | 296 | bits >>= 2; | 
|  | 297 |  | 
|  | 298 | blockRowPtr[x] = c[code]; | 
|  | 299 | } | 
|  | 300 | } | 
|  | 301 | } | 
|  | 302 | } | 
|  | 303 | } | 
|  | 304 |  | 
|  | 305 | // Output data as internalformat=GL_RGBA, type=GL_UNSIGNED_BYTE | 
|  | 306 | static void | 
|  | 307 | decodeDXT3(const GLvoid *data, int width, int height, | 
|  | 308 | void *surface, int stride) | 
|  | 309 |  | 
|  | 310 | { | 
|  | 311 | init_tables(); | 
|  | 312 |  | 
|  | 313 | uint32_t const *d32 = (uint32_t *)data; | 
|  | 314 |  | 
|  | 315 | // Specified colors from the previous block | 
|  | 316 | uint16_t prev_color0 = 0x0000; | 
|  | 317 | uint16_t prev_color1 = 0x0000; | 
|  | 318 |  | 
|  | 319 | // Color table for the current block | 
|  | 320 | uint32_t c[4]; | 
|  | 321 | c[0] = c[1] = c[2] = c[3] = 0; | 
|  | 322 |  | 
|  | 323 | uint32_t* rowPtr = (uint32_t*)surface; | 
|  | 324 | for (int base_y = 0; base_y < height; base_y += 4, rowPtr += 4*stride) { | 
|  | 325 | uint32_t *blockPtr = rowPtr; | 
|  | 326 | for (int base_x = 0; base_x < width; base_x += 4, blockPtr += 4) { | 
|  | 327 |  | 
|  | 328 | #if __BYTE_ORDER == __BIG_ENDIAN | 
|  | 329 | uint32_t alphahi = *d32++; | 
|  | 330 | uint32_t alphalo = *d32++; | 
|  | 331 | alphahi = swap(alphahi); | 
|  | 332 | alphalo = swap(alphalo); | 
|  | 333 | #else | 
|  | 334 | uint32_t alphalo = *d32++; | 
|  | 335 | uint32_t alphahi = *d32++; | 
|  | 336 | #endif | 
|  | 337 |  | 
|  | 338 | uint32_t colors = *d32++; | 
|  | 339 | uint32_t bits = *d32++; | 
|  | 340 |  | 
|  | 341 | #if __BYTE_ORDER == __BIG_ENDIAN | 
|  | 342 | colors = swap(colors); | 
|  | 343 | bits = swap(bits); | 
|  | 344 | #endif | 
|  | 345 |  | 
|  | 346 | uint64_t alpha = ((uint64_t)alphahi << 32) | alphalo; | 
|  | 347 |  | 
|  | 348 | // Raw colors | 
|  | 349 | uint16_t color0 = colors & 0xffff; | 
|  | 350 | uint16_t color1 = colors >> 16; | 
|  | 351 |  | 
|  | 352 | // If the new block has the same base colors as the | 
|  | 353 | // previous one, we don't need to recompute the color | 
|  | 354 | // table c[] | 
|  | 355 | if (color0 != prev_color0 || color1 != prev_color1) { | 
|  | 356 | // Store raw colors for comparison with next block | 
|  | 357 | prev_color0 = color0; | 
|  | 358 | prev_color1 = color1; | 
|  | 359 |  | 
|  | 360 | int bbits = bits >> 1; | 
|  | 361 | bool has2 = ((bbits & ~bits) & 0x55555555) != 0; | 
|  | 362 | bool has3 = ((bbits &  bits) & 0x55555555) != 0; | 
|  | 363 |  | 
|  | 364 | if (has2 || has3) { | 
|  | 365 | int r0 =   red(color0); | 
|  | 366 | int g0 = green(color0); | 
|  | 367 | int b0 =  blue(color0); | 
|  | 368 |  | 
|  | 369 | int r1 =   red(color1); | 
|  | 370 | int g1 = green(color1); | 
|  | 371 | int b1 =  blue(color1); | 
|  | 372 |  | 
|  | 373 | int r2 = avg23(r0, r1); | 
|  | 374 | int g2 = avg23(g0, g1); | 
|  | 375 | int b2 = avg23(b0, b1); | 
|  | 376 |  | 
|  | 377 | int r3 = avg23(r1, r0); | 
|  | 378 | int g3 = avg23(g1, g0); | 
|  | 379 | int b3 = avg23(b1, b0); | 
|  | 380 |  | 
|  | 381 | c[0] = rgb565SepTo888(r0, g0, b0); | 
|  | 382 | c[1] = rgb565SepTo888(r1, g1, b1); | 
|  | 383 | c[2] = rgb565SepTo888(r2, g2, b2); | 
|  | 384 | c[3] = rgb565SepTo888(r3, g3, b3); | 
|  | 385 | } else { | 
|  | 386 | // Convert to 8 bits | 
|  | 387 | c[0] = rgb565To888(color0); | 
|  | 388 | c[1] = rgb565To888(color1); | 
|  | 389 | } | 
|  | 390 | } | 
|  | 391 |  | 
|  | 392 | uint32_t* blockRowPtr = blockPtr; | 
|  | 393 | for (int y = 0; y < 4; y++, blockRowPtr += stride) { | 
|  | 394 | // Don't process rows past the botom | 
|  | 395 | if (base_y + y >= height) { | 
|  | 396 | break; | 
|  | 397 | } | 
|  | 398 |  | 
|  | 399 | int w = min(width - base_x, 4); | 
|  | 400 | for (int x = 0; x < w; x++) { | 
|  | 401 | int a = alpha & 0xf; | 
|  | 402 | alpha >>= 4; | 
|  | 403 |  | 
|  | 404 | int code = bits & 0x3; | 
|  | 405 | bits >>= 2; | 
|  | 406 |  | 
|  | 407 | blockRowPtr[x] = c[code] | (a << 28) | (a << 24); | 
|  | 408 | } | 
|  | 409 | } | 
|  | 410 | } | 
|  | 411 | } | 
|  | 412 | } | 
|  | 413 |  | 
|  | 414 | // Output data as internalformat=GL_RGBA, type=GL_UNSIGNED_BYTE | 
|  | 415 | static void | 
|  | 416 | decodeDXT5(const GLvoid *data, int width, int height, | 
|  | 417 | void *surface, int stride) | 
|  | 418 |  | 
|  | 419 | { | 
|  | 420 | init_tables(); | 
|  | 421 |  | 
|  | 422 | uint32_t const *d32 = (uint32_t *)data; | 
|  | 423 |  | 
|  | 424 | // Specified alphas from the previous block | 
|  | 425 | uint8_t prev_alpha0 = 0x00; | 
|  | 426 | uint8_t prev_alpha1 = 0x00; | 
|  | 427 |  | 
|  | 428 | // Specified colors from the previous block | 
|  | 429 | uint16_t prev_color0 = 0x0000; | 
|  | 430 | uint16_t prev_color1 = 0x0000; | 
|  | 431 |  | 
|  | 432 | // Alpha table for the current block | 
|  | 433 | uint8_t a[8]; | 
|  | 434 | a[0] = a[1] = a[2] = a[3] = a[4] = a[5] = a[6] = a[7] = 0; | 
|  | 435 |  | 
|  | 436 | // Color table for the current block | 
|  | 437 | uint32_t c[4]; | 
|  | 438 | c[0] = c[1] = c[2] = c[3] = 0; | 
|  | 439 |  | 
|  | 440 | int good_a5 = 0; | 
|  | 441 | int bad_a5 = 0; | 
|  | 442 | int good_a6 = 0; | 
|  | 443 | int bad_a6 = 0; | 
|  | 444 | int good_a7 = 0; | 
|  | 445 | int bad_a7 = 0; | 
|  | 446 |  | 
|  | 447 | uint32_t* rowPtr = (uint32_t*)surface; | 
|  | 448 | for (int base_y = 0; base_y < height; base_y += 4, rowPtr += 4*stride) { | 
|  | 449 | uint32_t *blockPtr = rowPtr; | 
|  | 450 | for (int base_x = 0; base_x < width; base_x += 4, blockPtr += 4) { | 
|  | 451 |  | 
|  | 452 | #if __BYTE_ORDER == __BIG_ENDIAN | 
|  | 453 | uint32_t alphahi = *d32++; | 
|  | 454 | uint32_t alphalo = *d32++; | 
|  | 455 | alphahi = swap(alphahi); | 
|  | 456 | alphalo = swap(alphalo); | 
|  | 457 | #else | 
|  | 458 | uint32_t alphalo = *d32++; | 
|  | 459 | uint32_t alphahi = *d32++; | 
|  | 460 | #endif | 
|  | 461 |  | 
|  | 462 | uint32_t colors = *d32++; | 
|  | 463 | uint32_t bits = *d32++; | 
|  | 464 |  | 
|  | 465 | #if __BYTE_ORDER == __BIG_ENDIANx | 
|  | 466 | colors = swap(colors); | 
|  | 467 | bits = swap(bits); | 
|  | 468 | #endif | 
|  | 469 |  | 
|  | 470 | uint64_t alpha = ((uint64_t)alphahi << 32) | alphalo; | 
|  | 471 | uint64_t alpha0 = alpha & 0xff; | 
|  | 472 | alpha >>= 8; | 
|  | 473 | uint64_t alpha1 = alpha & 0xff; | 
|  | 474 | alpha >>= 8; | 
|  | 475 |  | 
|  | 476 | if (alpha0 != prev_alpha0 || alpha1 != prev_alpha1) { | 
|  | 477 | prev_alpha0 = alpha0; | 
|  | 478 | prev_alpha1 = alpha1; | 
|  | 479 |  | 
|  | 480 | a[0] = alpha0; | 
|  | 481 | a[1] = alpha1; | 
|  | 482 | int a01 = alpha0 + alpha1 - 1; | 
|  | 483 | if (alpha0 > alpha1) { | 
|  | 484 | a[2] = div7(6*alpha0 +   alpha1); | 
|  | 485 | a[4] = div7(4*alpha0 + 3*alpha1); | 
|  | 486 | a[6] = div7(2*alpha0 + 5*alpha1); | 
|  | 487 |  | 
|  | 488 | // Use symmetry to derive half of the values | 
|  | 489 | // A few values will be off by 1 (~.5%) | 
|  | 490 | // Alternate which values are computed directly | 
|  | 491 | // and which are derived to try to reduce bias | 
|  | 492 | a[3] = a01 - a[6]; | 
|  | 493 | a[5] = a01 - a[4]; | 
|  | 494 | a[7] = a01 - a[2]; | 
|  | 495 | } else { | 
|  | 496 | a[2] = div5(4*alpha0 +   alpha1); | 
|  | 497 | a[4] = div5(2*alpha0 + 3*alpha1); | 
|  | 498 | a[3] = a01 - a[4]; | 
|  | 499 | a[5] = a01 - a[2]; | 
|  | 500 | a[6] = 0x00; | 
|  | 501 | a[7] = 0xff; | 
|  | 502 | } | 
|  | 503 | } | 
|  | 504 |  | 
|  | 505 | // Raw colors | 
|  | 506 | uint16_t color0 = colors & 0xffff; | 
|  | 507 | uint16_t color1 = colors >> 16; | 
|  | 508 |  | 
|  | 509 | // If the new block has the same base colors as the | 
|  | 510 | // previous one, we don't need to recompute the color | 
|  | 511 | // table c[] | 
|  | 512 | if (color0 != prev_color0 || color1 != prev_color1) { | 
|  | 513 | // Store raw colors for comparison with next block | 
|  | 514 | prev_color0 = color0; | 
|  | 515 | prev_color1 = color1; | 
|  | 516 |  | 
|  | 517 | int bbits = bits >> 1; | 
|  | 518 | bool has2 = ((bbits & ~bits) & 0x55555555) != 0; | 
|  | 519 | bool has3 = ((bbits &  bits) & 0x55555555) != 0; | 
|  | 520 |  | 
|  | 521 | if (has2 || has3) { | 
|  | 522 | int r0 =   red(color0); | 
|  | 523 | int g0 = green(color0); | 
|  | 524 | int b0 =  blue(color0); | 
|  | 525 |  | 
|  | 526 | int r1 =   red(color1); | 
|  | 527 | int g1 = green(color1); | 
|  | 528 | int b1 =  blue(color1); | 
|  | 529 |  | 
|  | 530 | int r2 = avg23(r0, r1); | 
|  | 531 | int g2 = avg23(g0, g1); | 
|  | 532 | int b2 = avg23(b0, b1); | 
|  | 533 |  | 
|  | 534 | int r3 = avg23(r1, r0); | 
|  | 535 | int g3 = avg23(g1, g0); | 
|  | 536 | int b3 = avg23(b1, b0); | 
|  | 537 |  | 
|  | 538 | c[0] = rgb565SepTo888(r0, g0, b0); | 
|  | 539 | c[1] = rgb565SepTo888(r1, g1, b1); | 
|  | 540 | c[2] = rgb565SepTo888(r2, g2, b2); | 
|  | 541 | c[3] = rgb565SepTo888(r3, g3, b3); | 
|  | 542 | } else { | 
|  | 543 | // Convert to 8 bits | 
|  | 544 | c[0] = rgb565To888(color0); | 
|  | 545 | c[1] = rgb565To888(color1); | 
|  | 546 | } | 
|  | 547 | } | 
|  | 548 |  | 
|  | 549 | uint32_t* blockRowPtr = blockPtr; | 
|  | 550 | for (int y = 0; y < 4; y++, blockRowPtr += stride) { | 
|  | 551 | // Don't process rows past the botom | 
|  | 552 | if (base_y + y >= height) { | 
|  | 553 | break; | 
|  | 554 | } | 
|  | 555 |  | 
|  | 556 | int w = min(width - base_x, 4); | 
|  | 557 | for (int x = 0; x < w; x++) { | 
|  | 558 | int acode = alpha & 0x7; | 
|  | 559 | alpha >>= 3; | 
|  | 560 |  | 
|  | 561 | int code = bits & 0x3; | 
|  | 562 | bits >>= 2; | 
|  | 563 |  | 
|  | 564 | blockRowPtr[x] = c[code] | (a[acode] << 24); | 
|  | 565 | } | 
|  | 566 | } | 
|  | 567 | } | 
|  | 568 | } | 
|  | 569 | } | 
|  | 570 |  | 
|  | 571 | /* | 
|  | 572 | * Decode a DXT-compressed texture into memory.  DXT textures consist of | 
|  | 573 | * a series of 4x4 pixel blocks in left-to-right, top-down order. | 
|  | 574 | * The number of blocks is given by ceil(width/4)*ceil(height/4). | 
|  | 575 | * | 
|  | 576 | * 'data' points to the texture data. 'width' and 'height' indicate the | 
|  | 577 | * dimensions of the texture.  We assume width and height are >= 0 but | 
|  | 578 | * do not require them to be powers of 2 or divisible by any factor. | 
|  | 579 | * | 
|  | 580 | * The output is written to 'surface' with each scanline separated by | 
|  | 581 | * 'stride' 2- or 4-byte words. | 
|  | 582 | * | 
|  | 583 | * 'format' indicates the type of compression and must be one of the following: | 
|  | 584 | * | 
|  | 585 | *   GL_COMPRESSED_RGB_S3TC_DXT1_EXT: | 
|  | 586 | *      The output is written as 5/6/5 opaque RGB (16 bit words). | 
|  | 587 | *      8 bytes are read from 'data' for each block. | 
|  | 588 | * | 
|  | 589 | *   GL_COMPRESSED_RGBA_S3TC_DXT1_EXT | 
|  | 590 | *      The output is written as 5/5/5/1 RGBA (16 bit words) | 
|  | 591 | *      8 bytes are read from 'data' for each block. | 
|  | 592 | * | 
|  | 593 | *   GL_COMPRESSED_RGBA_S3TC_DXT3_EXT | 
|  | 594 | *   GL_COMPRESSED_RGBA_S3TC_DXT5_EXT | 
|  | 595 | *      The output is written as 8/8/8/8 ARGB (32 bit words) | 
|  | 596 | *      16 bytes are read from 'data' for each block. | 
|  | 597 | */ | 
|  | 598 | void | 
|  | 599 | decodeDXT(const GLvoid *data, int width, int height, | 
|  | 600 | void *surface, int stride, int format) | 
|  | 601 | { | 
|  | 602 | #if TIMING | 
|  | 603 | struct timeval start_t, end_t; | 
|  | 604 | struct timezone tz; | 
|  | 605 |  | 
|  | 606 | gettimeofday(&start_t, &tz); | 
|  | 607 | #endif | 
|  | 608 |  | 
|  | 609 | switch (format) { | 
|  | 610 | case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: | 
|  | 611 | decodeDXT1(data, width, height, surface, stride, false); | 
|  | 612 | break; | 
|  | 613 |  | 
|  | 614 | case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: | 
|  | 615 | decodeDXT1(data, width, height, surface, stride, true); | 
|  | 616 | break; | 
|  | 617 |  | 
|  | 618 | case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: | 
|  | 619 | decodeDXT3(data, width, height, surface, stride); | 
|  | 620 | break; | 
|  | 621 |  | 
|  | 622 | case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: | 
|  | 623 | decodeDXT5(data, width, height, surface, stride); | 
|  | 624 | break; | 
|  | 625 | } | 
|  | 626 |  | 
|  | 627 | #if TIMING | 
|  | 628 | gettimeofday(&end_t, &tz); | 
|  | 629 | long usec = (end_t.tv_sec - start_t.tv_sec)*1000000 + | 
|  | 630 | (end_t.tv_usec - start_t.tv_usec); | 
|  | 631 |  | 
|  | 632 | printf("Loaded w=%d h=%d in %ld usec\n", width, height, usec); | 
|  | 633 | #endif | 
|  | 634 | } | 
|  | 635 |  | 
|  | 636 | } // namespace android |