Index: cc/resources/texture_compress/atc_dxt.cc |
diff --git a/cc/resources/texture_compress/atc_dxt.cc b/cc/resources/texture_compress/atc_dxt.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..0c99549ff8c59266701d7dca4752f2347f9a8c97 |
--- /dev/null |
+++ b/cc/resources/texture_compress/atc_dxt.cc |
@@ -0,0 +1,795 @@ |
+// Copyright 2014 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+// This file is based on the public domain code "stb_dxt.h" originally written |
+// by Fabian Giesen and Sean Barrett. |
+// |
+// The following changes were made: |
+// - Added support for ATC format. |
+// - Replaced the Principal Component Analysis based calculation to find the |
+// initial base colors with a much simpler bounding box implementation for low |
+// quality only. |
+// - Removed dithering support. |
+// - Some minor optimizations. |
+// - Reformatted the code (mainly with clang-format). |
+// - Swapped red and blue channels in the output to match Skia. |
+ |
+#include "cc/resources/texture_compress/atc_dxt.h" |
+#include <cmath> |
+#include <cstdlib> |
+#include "base/logging.h" |
+ |
+namespace cc { |
+namespace texture_compress { |
+ |
+struct TYPE_ATC_GENERIC : public TYPE_ATC { |
+ typedef TYPE_ATC BASE_TYPE; |
+ static const int kRemap[8]; |
+ static const int kW1Table[4]; |
+ static const int kProds[4]; |
+}; |
+ |
+struct TYPE_DXT_GENERIC : public TYPE_DXT { |
+ typedef TYPE_DXT BASE_TYPE; |
+ static const int kRemap[8]; |
+ static const int kW1Table[4]; |
+ static const int kProds[4]; |
+}; |
+ |
+const int TYPE_ATC_GENERIC::kRemap[8] = |
+ {0 << 30, 1 << 30, 0 << 30, 1 << 30, 2 << 30, 2 << 30, 3 << 30, 3 << 30}; |
+const int TYPE_ATC_GENERIC::kW1Table[4] = {3, 2, 1, 0}; |
+const int TYPE_ATC_GENERIC::kProds[4] = {0x090000, |
+ 0x040102, |
+ 0x010402, |
+ 0x000900}; |
+ |
+const int TYPE_DXT_GENERIC::kRemap[8] = |
+ {0 << 30, 2 << 30, 0 << 30, 2 << 30, 3 << 30, 3 << 30, 1 << 30, 1 << 30}; |
+const int TYPE_DXT_GENERIC::kW1Table[4] = {3, 0, 2, 1}; |
+const int TYPE_DXT_GENERIC::kProds[4] = {0x090000, |
+ 0x000900, |
+ 0x040102, |
+ 0x010402}; |
+ |
+// Number of passes over the block that's done to refine the base colors. |
+const int kNumRefinements = 2; |
+ |
+uint8_t g_o_match55[256][2]; |
+uint8_t g_o_match66[256][2]; |
+uint8_t g_o_match56[256][2]; |
+ |
+namespace { |
+ |
+inline int Mul8Bit(int a, int b) { |
+ int t = a * b + 128; |
+ return (t + (t >> 8)) >> 8; |
+} |
+ |
+// Linear interpolation at 1/3 point between a and b, using desired rounding |
+// type. |
+inline int Lerp13(int a, int b) { |
+ // Without rounding bias. |
+ // (2 * a + b) / 3; |
+ return ((2 * a + b) * 0xaaab) >> 17; |
+} |
+ |
+inline void Lerp13RGB(uint8_t* out, const uint8_t* p1, const uint8_t* p2) { |
+ out[0] = Lerp13(p1[0], p2[0]); |
+ out[1] = Lerp13(p1[1], p2[1]); |
+ out[2] = Lerp13(p1[2], p2[2]); |
+} |
+ |
+// Compute table to reproduce constant colors as accurately as possible. |
+void PrepareOptTable(uint8_t* table, |
+ const uint8_t* expand_max, |
+ const uint8_t* expand_min, |
+ int size_max, |
+ int size_min) { |
+ for (int i = 0; i < 256; ++i) { |
+ int best_err = 256; |
+ for (int mn = 0; mn < size_min; ++mn) { |
+ for (int mx = 0; mx < size_max; ++mx) { |
+ int mine = expand_min[mn]; |
+ int maxe = expand_max[mx]; |
+ int err = std::abs(Lerp13(maxe, mine) - i); |
+ |
+ // DX10 spec says that interpolation must be within 3% of "correct" |
+ // result, add this as error term. (normally we'd expect a random |
+ // distribution of +-1.5% error, but nowhere in the spec does it say |
+ // that the error has to be unbiased - better safe than sorry). |
+ err += std::abs(maxe - mine) * 3 / 100; |
+ |
+ if (err < best_err) { |
+ table[i * 2 + 0] = mx; |
+ table[i * 2 + 1] = mn; |
+ best_err = err; |
+ } |
+ } |
+ } |
+ } |
+} |
+ |
+inline uint8_t Expand5(int i) { |
+ return (i << 3) | (i >> 2); |
+} |
+ |
+inline uint8_t Expand6(int i) { |
+ return (i << 2) | (i >> 4); |
+} |
+ |
+inline uint16_t As16Bit(int r, int g, int b) { |
+ return (Mul8Bit(r, 31) << 11) + (Mul8Bit(g, 63) << 5) + Mul8Bit(b, 31); |
+} |
+ |
+inline int sclamp(float y, int p0, int p1) { |
+ int x = static_cast<int>(y); |
+ if (x < p0) { |
+ return p0; |
+ } |
+ if (x > p1) { |
+ return p1; |
+ } |
+ return x; |
+} |
+ |
+#if defined(OS_ANDROID) |
+inline uint16_t RGB2BGR(uint16_t rgb) { |
+ uint16_t r = rgb & 0xf800; |
+ uint16_t g = rgb & 0x07e0; |
+ uint16_t b = rgb & 0x001f; |
+ return (r >> 11) | g | (b << 11); |
+} |
+#endif |
+ |
+// Take two 16-bit base colors and generate 4 32-bit RGBX colors where: |
+// 0 = c0 |
+// 1 = c1 |
+// 2 = (2 * c0 + c1) / 3 |
+// 3 = (2 * c1 + c0) / 3 |
+// |
+// The base colors are expanded by reusing the top bits at the end. That makes |
+// sure that white is still white after being quantized and converted back. |
+// |
+// params: |
+// color (output) 4 RGBA pixels. |
+// c0 base color 0 (16 bit RGB) |
+// c1 base color 1 (16 bit RGB) |
+inline void EvalColors(uint8_t* color, uint16_t c0, uint16_t c1) { |
+ // Expand the two base colors to 32-bit |
+ // From: [00000000][00000000][rrrrrggg][gggbbbbb] |
+ // To: [00000000][bbbbbxxx][ggggggxx][rrrrrxxx] |
+ // Where x means repeat the upper bits for that color component. |
+ |
+ // Take shortcut if either color is zero. Both will never be zero. |
+ DCHECK(c0 | c1); |
+ if (c0 && c1) { |
+ // Combine the two base colors into one register to allow operating on both |
+ // pixels at the same time. |
+ // [rrrrrggg][gggbbbbb][RRRRRGGG][GGGBBBBB] |
+ uint32_t c01 = c1 | (c0 << 16); |
+ |
+ // Mask out the red components and shift it down one channel to avoid some |
+ // shifts when combining the channels. |
+ // [00000000][rrrrr000][00000000][RRRRR000] |
+ uint32_t c01_r = (c01 & 0xf800f800) >> 8; |
+ // Extend to be 8-bit by reusing top bits at the end. |
+ // Note that we leave some extra garbage bits in the other channels, but |
+ // that's ok since we mask that off when we combine the different |
+ // components. |
+ // [00000000][rrrrrrrr][xx000000][RRRRRRRR] |
+ c01_r |= (c01_r >> 5); |
+ |
+ // Mask out the green components. |
+ // [00000ggg][ggg00000][00000GGG][GGG00000] |
+ uint32_t c01_g = c01 & 0x07e007e0; |
+ // Shift it into place and extend. |
+ // [gggggggg][xxxx0000][GGGGGGGG][xxxx0000] |
+ c01_g = ((c01_g << 5) | (c01_g >> 1)); |
+ |
+ // Mask out the blue components. |
+ // [00000000][000bbbbb][00000000][000BBBBB] |
+ uint32_t c01_b = c01 & 0x001f001f; |
+ // Shift it into place and extend. |
+ // [bbbbbbbb][xx000000][BBBBBBBB][xx000000] |
+ c01_b = ((c01_b << 11) | (c01_b << 6)); |
+ |
+ // Combine the components into base color 0. |
+ // Shift the components into place and mask of each channel. |
+ // [00000000][bbbbbbbb][gggggggg][rrrrrrrr] |
+ *reinterpret_cast<uint32_t*>(color + 0) = ((c01_r >> 16) & 0x000000ff) | |
+ ((c01_g >> 16) & 0x0000ff00) | |
+ ((c01_b >> 8) & 0x00ff0000); |
+ |
+ // Combine the components into base color 1. |
+ // [00000000][BBBBBBBB][GGGGGGGG][RRRRRRRR] |
+ *reinterpret_cast<uint32_t*>(color + 4) = (c01_r & 0x000000ff) | |
+ (c01_g & 0x0000ff00) | |
+ ((c01_b << 8) & 0x00ff0000); |
+ |
+ Lerp13RGB(color + 8, color, color + 4); |
+ Lerp13RGB(color + 12, color + 4, color); |
+ } else { |
+ // Combine the two base colors into one register, one of them will be zero. |
+ // [00000000][00000000][rrrrrggg][gggbbbbb] |
+ uint32_t c = c0 | c1; |
+ |
+ // Mask out the red components and shift it down one channel to avoid some |
+ // shifts when combining the channels. |
+ // [00000000][00000000][00000000][rrrrr000] |
+ uint32_t c_r = (c & 0xf800) >> 8; |
+ // Extend to be 8-bit by reusing top bits at the end. |
+ // [00000000][00000000][00000000][rrrrrrrr] |
+ c_r |= c_r >> 5; |
+ |
+ // Mask out the green components. |
+ // [00000000][00000000][00000ggg][ggg00000] |
+ uint32_t c_g = c & 0x07e0; |
+ // Shift it into place and extend. Then mask off garbage bits. |
+ // [00000000][00000000][gggggggg][xxxx0000] |
+ c_g = ((c_g << 5) | (c_g >> 1)) & 0x0000ff00; |
+ |
+ // Mask out the blue components. |
+ // [00000000][00000000][00000000][000bbbbb] |
+ uint32_t c_b = c & 0x001f; |
+ // Shift it into place and extend. Then mask off garbage bits. |
+ // [00000000][bbbbbbbb][xx000000][00000000] |
+ c_b = ((c_b << 19) | (c_b << 14)) & 0x00ff0000; |
+ |
+ size_t zero_offset = !!c0 * 4; |
+ size_t nonzero_offset = !!c1 * 4; |
+ |
+ // Combine the components into non zero base color. |
+ // [00000000][bbbbbbbb][gggggggg][rrrrrrrr] |
+ *reinterpret_cast<uint32_t*>(color + nonzero_offset) = c_r | c_g | c_b; |
+ |
+ // We already know that the other base color is zero. |
+ *reinterpret_cast<uint32_t*>(color + zero_offset) = 0; |
+ |
+ color[8 + nonzero_offset + 0] = |
+ (color[nonzero_offset + 0] * (2 * 0xaaab)) >> 17; |
+ color[8 + nonzero_offset + 1] = |
+ (color[nonzero_offset + 1] * (2 * 0xaaab)) >> 17; |
+ color[8 + nonzero_offset + 2] = |
+ (color[nonzero_offset + 2] * (2 * 0xaaab)) >> 17; |
+ |
+ color[8 + zero_offset + 0] = (color[nonzero_offset + 0] * 0xaaab) >> 17; |
+ color[8 + zero_offset + 1] = (color[nonzero_offset + 1] * 0xaaab) >> 17; |
+ color[8 + zero_offset + 2] = (color[nonzero_offset + 2] * 0xaaab) >> 17; |
+ } |
+} |
+ |
+// The color matching function. |
+template <typename T> |
+uint32_t MatchColorsBlock(const uint8_t* block, uint8_t* color) { |
+ int dirr = color[0 * 4 + 0] - color[1 * 4 + 0]; |
+ int dirg = color[0 * 4 + 1] - color[1 * 4 + 1]; |
+ int dirb = color[0 * 4 + 2] - color[1 * 4 + 2]; |
+ |
+ int stops[4]; |
+ for (int i = 0; i < 4; ++i) { |
+ stops[i] = color[i * 4 + 0] * dirr + color[i * 4 + 1] * dirg + |
+ color[i * 4 + 2] * dirb; |
+ } |
+ |
+ // Think of the colors as arranged on a line; project point onto that line, |
+ // then choose next color out of available ones. we compute the crossover |
+ // points for "best color in top half"/"best in bottom half" and then the same |
+ // inside that subinterval. |
+ // |
+ // Relying on this 1d approximation isn't always optimal in terms of euclidean |
+ // distance, but it's very close and a lot faster. |
+ // http://cbloomrants.blogspot.com/2008/12/12-08-08-dxtc-summary.html |
+ |
+ int c0_point = (stops[1] + stops[3]) >> 1; |
+ int half_point = (stops[3] + stops[2]) >> 1; |
+ int c3_point = (stops[2] + stops[0]) >> 1; |
+ |
+ uint32_t mask = 0; |
+ for (int i = 0; i < 16; i++) { |
+ int dot = block[i * 4 + 0] * dirr + block[i * 4 + 1] * dirg + |
+ block[i * 4 + 2] * dirb; |
+ |
+ int bits = ((dot < half_point) ? 4 : 0) | ((dot < c0_point) ? 2 : 0) | |
+ ((dot < c3_point) ? 1 : 0); |
+ |
+ mask >>= 2; |
+ mask |= T::kRemap[bits]; |
+ } |
+ |
+ return mask; |
+} |
+ |
+void GetBaseColors(const uint8_t* block, |
+ int v_r, |
+ int v_g, |
+ int v_b, |
+ uint16_t* pmax16, |
+ uint16_t* pmin16) { |
+// Pick colors at extreme points. |
+#ifdef VERIFY_RESULTS |
+ // Rewritten to match the SIMD implementation, not as efficient. |
+ int dots[16]; |
+ for (int i = 0; i < 16; ++i) { |
+ dots[i] = block[i * 4 + 0] * v_r + block[i * 4 + 1] * v_g + |
+ block[i * 4 + 2] * v_b; |
+ } |
+ int max_dot = dots[0]; |
+ int min_dot = dots[0]; |
+ for (int i = 1; i < 16; ++i) { |
+ if (dots[i] > max_dot) |
+ max_dot = dots[i]; |
+ if (dots[i] < min_dot) |
+ min_dot = dots[i]; |
+ } |
+ uint32_t max_pixels[16]; |
+ uint32_t min_pixels[16]; |
+ for (int i = 0; i < 16; ++i) { |
+ const uint32_t* p = reinterpret_cast<const uint32_t*>(block) + i; |
+ max_pixels[i] = (dots[i] == max_dot) ? *p : 0; |
+ min_pixels[i] = (dots[i] == min_dot) ? *p : 0; |
+ } |
+ uint32_t max_pixel = max_pixels[0]; |
+ uint32_t min_pixel = min_pixels[0]; |
+ for (int i = 1; i < 16; ++i) { |
+ if (max_pixels[i] > max_pixel) { |
+ max_pixel = max_pixels[i]; |
+ } |
+ if (min_pixels[i] > min_pixel) { |
+ min_pixel = min_pixels[i]; |
+ } |
+ } |
+ uint8_t* maxp = reinterpret_cast<uint8_t*>(&max_pixel); |
+ uint8_t* minp = reinterpret_cast<uint8_t*>(&min_pixel); |
+#else |
+ int mind = 0x7fffffff; |
+ int maxd = -0x7fffffff; |
+ const uint8_t* minp = block; |
+ const uint8_t* maxp = block; |
+ for (int i = 0; i < 16; ++i) { |
+ int dot = block[i * 4 + 0] * v_r + block[i * 4 + 1] * v_g + |
+ block[i * 4 + 2] * v_b; |
+ |
+ if (dot < mind) { |
+ mind = dot; |
+ minp = block + i * 4; |
+ } |
+ |
+ if (dot > maxd) { |
+ maxd = dot; |
+ maxp = block + i * 4; |
+ } |
+ } |
+#endif |
+ |
+ *pmax16 = As16Bit(maxp[0], maxp[1], maxp[2]); |
+ *pmin16 = As16Bit(minp[0], minp[1], minp[2]); |
+} |
+ |
+// Figure out the two base colors to use from a block of 16 pixels |
+// by Primary Component Analysis and map along principal axis. |
+// |
+// params: |
+// block 16 32-bit RGBX colors. |
+// pmax16 (output) base color 0 (minimum value), 16-bit RGB |
+// pmin16 (output) base color 1 (maximum value), 16-bit RGB |
+void OptimizeColorsBlock(const uint8_t* block, |
+ uint16_t* pmax16, |
+ uint16_t* pmin16) { |
+ // Determine color distribution. |
+ int mu[3]; |
+ int min[3]; |
+ int max[3]; |
+ for (int ch = 0; ch < 3; ++ch) { |
+ const uint8_t* bp = block + ch; |
+ int muv = bp[0]; |
+ int minv = muv; |
+ int maxv = muv; |
+ for (int i = 4; i < 64; i += 4) { |
+ int pixel = bp[i]; |
+ muv += pixel; |
+ if (pixel < minv) { |
+ minv = pixel; |
+ } else if (pixel > maxv) { |
+ maxv = pixel; |
+ } |
+ } |
+ |
+ mu[ch] = (muv + 8) >> 4; |
+ min[ch] = minv; |
+ max[ch] = maxv; |
+ } |
+ |
+ // Determine covariance matrix. |
+ int cov[6] = {0, 0, 0, 0, 0, 0}; |
+ for (int i = 0; i < 16; ++i) { |
+ int r = block[i * 4 + 0] - mu[0]; |
+ int g = block[i * 4 + 1] - mu[1]; |
+ int b = block[i * 4 + 2] - mu[2]; |
+ |
+ cov[0] += r * r; |
+ cov[1] += r * g; |
+ cov[2] += r * b; |
+ cov[3] += g * g; |
+ cov[4] += g * b; |
+ cov[5] += b * b; |
+ } |
+ |
+ // Convert covariance matrix to float, find principal axis via power iter. |
+ float covf[6]; |
+ for (int i = 0; i < 6; ++i) { |
+ covf[i] = cov[i] / 255.0f; |
+ } |
+ |
+ float vfr = static_cast<float>(max[0] - min[0]); |
+ float vfg = static_cast<float>(max[1] - min[1]); |
+ float vfb = static_cast<float>(max[2] - min[2]); |
+ |
+ // Iterate to the power of 4. |
+ for (int iter = 0; iter < 4; ++iter) { |
+ float r = vfr * covf[0] + vfg * covf[1] + vfb * covf[2]; |
+ float g = vfr * covf[1] + vfg * covf[3] + vfb * covf[4]; |
+ float b = vfr * covf[2] + vfg * covf[4] + vfb * covf[5]; |
+ |
+ vfr = r; |
+ vfg = g; |
+ vfb = b; |
+ } |
+ |
+ double magn = std::abs(vfr); |
+ double mag_g = std::abs(vfg); |
+ double mag_b = std::abs(vfb); |
+ if (mag_g > magn) { |
+ magn = mag_g; |
+ } |
+ if (mag_b > magn) { |
+ magn = mag_b; |
+ } |
+ |
+ int v_r = 299; // JPEG YCbCr luma coefs, scaled by 1000. |
+ int v_g = 587; |
+ int v_b = 114; |
+ if (magn >= 4.0f) { // Too small, default to luminance. |
+ magn = 512.0 / magn; |
+ v_r = static_cast<int>(vfr * magn); |
+ v_g = static_cast<int>(vfg * magn); |
+ v_b = static_cast<int>(vfb * magn); |
+ } |
+ |
+ GetBaseColors(block, v_r, v_g, v_b, pmax16, pmin16); |
+} |
+ |
+// Figure out the two base colors simply using a direction vector between min |
+// and max colors. |
+// |
+// params: |
+// block 16 32-bit RGBX colors. |
+// pmax16 (output) base color 0 (minimum value), 16-bit RGB |
+// pmin16 (output) base color 1 (maximum value), 16-bit RGB |
+void GetApproximateBaseColors(const uint8_t* block, |
+ uint16_t* pmax16, |
+ uint16_t* pmin16) { |
+ uint8_t dir[3]; |
+ for (int ch = 0; ch < 3; ++ch) { |
+ const uint8_t* bp = block + ch; |
+ uint8_t minv = bp[0]; |
+ uint8_t maxv = bp[0]; |
+ for (int i = 4; i < 64; i += 4) { |
+ uint8_t pixel = bp[i]; |
+ if (pixel < minv) { |
+ minv = pixel; |
+ } else if (pixel > maxv) { |
+ maxv = pixel; |
+ } |
+ } |
+ |
+ dir[ch] = maxv - minv; |
+ } |
+ |
+ GetBaseColors(block, dir[0], dir[1], dir[2], pmax16, pmin16); |
+} |
+ |
+// The refinement function. |
+// Tries to optimize colors to suit block contents better. |
+// (By solving a least squares system via normal equations+Cramer's rule) |
+// |
+// params: |
+// block 16 32-bit RGBX colors. |
+// pmax16 (output) base color 0 (minimum value), 16-bit RGB |
+// pmin16 (output) base color 1 (maximum value), 16-bit RGB |
+// mask 16 2-bit color indices. |
+template <typename T> |
+int RefineBlock(const uint8_t* block, |
+ uint16_t* pmax16, |
+ uint16_t* pmin16, |
+ uint32_t mask) { |
+ uint16_t min16 = 0; |
+ uint16_t max16 = 0; |
+ if ((mask ^ (mask << 2)) < 4) { // All pixels have the same index? |
+ // Yes, linear system would be singular; solve using optimal |
+ // single-color match on average color. |
+ int r = 8; |
+ int g = 8; |
+ int b = 8; |
+ for (int i = 0; i < 16; ++i) { |
+ r += block[i * 4 + 0]; |
+ g += block[i * 4 + 1]; |
+ b += block[i * 4 + 2]; |
+ } |
+ |
+ r >>= 4; |
+ g >>= 4; |
+ b >>= 4; |
+ |
+ max16 = MatchSingleColorMax<typename T::BASE_TYPE>(r, g, b); |
+ min16 = MatchSingleColorMin<typename T::BASE_TYPE>(r, g, b); |
+ } else { |
+ int at1_r = 0; |
+ int at1_g = 0; |
+ int at1_b = 0; |
+ int at2_r = 0; |
+ int at2_g = 0; |
+ int at2_b = 0; |
+ int akku = 0; |
+ uint32_t cm = mask; |
+ for (int i = 0; i < 16; ++i, cm >>= 2) { |
+ int step = cm & 3; |
+ |
+ int w1 = T::kW1Table[step]; |
+ int r = block[i * 4 + 0]; |
+ int g = block[i * 4 + 1]; |
+ int b = block[i * 4 + 2]; |
+ |
+ // Some magic to save a lot of multiplies in the accumulating loop... |
+ // (Precomputed products of weights for least squares system, accumulated |
+ // inside one 32-bit register.) |
+ akku += T::kProds[step]; |
+ at1_r += w1 * r; |
+ at1_g += w1 * g; |
+ at1_b += w1 * b; |
+ at2_r += r; |
+ at2_g += g; |
+ at2_b += b; |
+ } |
+ |
+ at2_r = 3 * at2_r - at1_r; |
+ at2_g = 3 * at2_g - at1_g; |
+ at2_b = 3 * at2_b - at1_b; |
+ |
+ // Extract solutions and decide solvability. |
+ int xx = akku >> 16; |
+ int yy = (akku >> 8) & 0xff; |
+ int xy = (akku >> 0) & 0xff; |
+ |
+ float frb = 3.0f * 31.0f / 255.0f / (xx * yy - xy * xy); |
+ float fg = frb * 63.0f / 31.0f; |
+ |
+ // Solve. |
+ max16 = sclamp((at1_r * yy - at2_r * xy) * frb + 0.5f, 0, 31) << 11; |
+ max16 |= sclamp((at1_g * yy - at2_g * xy) * fg + 0.5f, 0, 63) << 5; |
+ max16 |= sclamp((at1_b * yy - at2_b * xy) * frb + 0.5f, 0, 31) << 0; |
+ |
+ min16 = sclamp((at2_r * xx - at1_r * xy) * frb + 0.5f, 0, 31) << 11; |
+ min16 |= sclamp((at2_g * xx - at1_g * xy) * fg + 0.5f, 0, 63) << 5; |
+ min16 |= sclamp((at2_b * xx - at1_b * xy) * frb + 0.5f, 0, 31) << 0; |
+ } |
+ |
+ uint16_t oldMin = *pmin16; |
+ uint16_t oldMax = *pmax16; |
+ *pmin16 = min16; |
+ *pmax16 = max16; |
+ return oldMin != min16 || oldMax != max16; |
+} |
+ |
+// Color block compression. |
+template <typename T, Quality QUALITY> |
+void CompressColorBlock(uint8_t* dst, const uint8_t* block) { |
+ // Check if block is constant. |
+ int i = 1; |
+ uint32_t first_pixel = |
+ reinterpret_cast<const uint32_t*>(block)[0] & 0x00ffffff; |
+ for (; i < 16; ++i) { |
+ if ((reinterpret_cast<const uint32_t*>(block)[i] & 0x00ffffff) != |
+ first_pixel) { |
+ break; |
+ } |
+ } |
+ |
+ uint32_t mask = 0; |
+ uint16_t max16 = 0; |
+ uint16_t min16 = 0; |
+ if (i == 16) { // Constant color |
+ int r = block[0]; |
+ int g = block[1]; |
+ int b = block[2]; |
+ max16 = MatchSingleColorMax<typename T::BASE_TYPE>(r, g, b); |
+ min16 = MatchSingleColorMin<typename T::BASE_TYPE>(r, g, b); |
+ mask = T::kConstantColorIndices; |
+ } else { |
+ if (QUALITY == kQualityLow) { |
+ GetApproximateBaseColors(block, &max16, &min16); |
+ } else { |
+ // Do Primary Component Analysis and map along principal axis. |
+ OptimizeColorsBlock(block, &max16, &min16); |
+ } |
+ |
+ if (max16 != min16) { |
+ uint8_t color[4 * 4]; |
+ EvalColors(color, max16, min16); |
+ mask = MatchColorsBlock<T>(block, color); |
+ } |
+ |
+ if (QUALITY == kQualityHigh) { |
+ // Refine (multiple times if requested). |
+ for (int i = 0; i < kNumRefinements; ++i) { |
+ uint32_t lastmask = mask; |
+ |
+ if (RefineBlock<T>(block, &max16, &min16, mask)) { |
+ if (max16 != min16) { |
+ uint8_t color[4 * 4]; |
+ EvalColors(color, max16, min16); |
+ mask = MatchColorsBlock<T>(block, color); |
+ } else { |
+ mask = 0; |
+ break; |
+ } |
+ } |
+ |
+ if (mask == lastmask) { |
+ break; |
+ } |
+ } |
+ } |
+ } |
+ |
+#if defined(OS_ANDROID) |
+ // Swapping r and b channels to match Skia. |
+ // See skia/config/SkUserConfig.h |
+ max16 = RGB2BGR(max16); |
+ min16 = RGB2BGR(min16); |
+#endif |
+ |
+ FormatFixup_Generic<typename T::BASE_TYPE>(&max16, &min16, &mask); |
+ |
+ uint32_t* dst32 = reinterpret_cast<uint32_t*>(dst); |
+ dst32[0] = max16 | (min16 << 16); |
+ dst32[1] = mask; |
+} |
+ |
+// Alpha block compression. |
+void CompressAlphaBlock(uint8_t* dst, const uint8_t* src) { |
+ // Find min/max alpha. |
+ int mn = src[3]; |
+ int mx = mn; |
+ for (int i = 1; i < 16; ++i) { |
+ int alpha = src[i * 4 + 3]; |
+ if (alpha < mn) { |
+ mn = alpha; |
+ } else if (alpha > mx) { |
+ mx = alpha; |
+ } |
+ } |
+ |
+ // Encode them. |
+ dst[0] = mx; |
+ dst[1] = mn; |
+ dst += 2; |
+ |
+ if (mx == mn) { |
+ memset(dst, 0, 6); |
+ } else { |
+ // Determine bias and emit color indices. |
+ // Given the choice of mx/mn, these indices are optimal: |
+ // http://fgiesen.wordpress.com/2009/12/15/dxt5-alpha-block-index-determination/ |
+ int dist = mx - mn; |
+ int dist4 = dist * 4; |
+ int dist2 = dist * 2; |
+ int bias = (dist < 8) ? (dist - 1) : (dist / 2 + 2); |
+ bias -= mn * 7; |
+ int bits = 0; |
+ int mask = 0; |
+ |
+ for (int i = 0; i < 16; ++i) { |
+ int a = src[i * 4 + 3] * 7 + bias; |
+ |
+ // Select index. this is a "linear scale" lerp factor between 0 (val=min) |
+ // and 7 (val=max). |
+ int t = (a >= dist4) ? -1 : 0; |
+ int ind = t & 4; |
+ a -= dist4 & t; |
+ |
+ t = (a >= dist2) ? -1 : 0; |
+ ind += t & 2; |
+ a -= dist2 & t; |
+ |
+ ind += (a >= dist); |
+ |
+ // Turn linear scale into DXT index (0/1 are extremal pts). |
+ ind = -ind & 7; |
+ ind ^= (2 > ind); |
+ |
+ // Write index. |
+ mask |= ind << bits; |
+ if ((bits += 3) >= 8) { |
+ *dst++ = mask; |
+ mask >>= 8; |
+ bits -= 8; |
+ } |
+ } |
+ } |
+} |
+ |
+static void ExtractBlock(uint8_t* dst, const uint8_t* src, int width) { |
+ for (int j = 0; j < 4; ++j) { |
+ memcpy(&dst[j * 4 * 4], src, 4 * 4); |
+ src += width * 4; |
+ } |
+} |
+ |
+template <typename T, bool OPAQUE, Quality QUALITY> |
+void CompressImage(const uint8_t* src, uint8_t* dst, int width, int height) { |
+ for (int y = 0; y < height; y += 4, src += width * 4 * 4) { |
+ for (int x = 0; x < width; x += 4) { |
+ uint8_t block[64]; |
+ ExtractBlock(block, src + x * 4, width); |
+ |
+ if (!OPAQUE) { |
+ CompressAlphaBlock(dst, block); |
+ dst += 8; |
+ } |
+ |
+ CompressColorBlock<T, QUALITY>(dst, block); |
+ dst += 8; |
+ } |
+ } |
+} |
+ |
+} // namespace |
+ |
+void Init_ATC_DXT() { |
+ uint8_t expand5[32]; |
+ for (int i = 0; i < 32; ++i) { |
+ expand5[i] = Expand5(i); |
+ } |
+ |
+ uint8_t expand6[64]; |
+ for (int i = 0; i < 64; ++i) { |
+ expand6[i] = Expand6(i); |
+ } |
+ |
+ PrepareOptTable(&g_o_match55[0][0], expand5, expand5, 32, 32); |
+ PrepareOptTable(&g_o_match66[0][0], expand6, expand6, 64, 64); |
+ PrepareOptTable(&g_o_match56[0][0], expand5, expand6, 32, 64); |
+} |
+ |
+void CompressATC_Generic(const uint8_t* src, |
+ uint8_t* dst, |
+ int width, |
+ int height) { |
+ CompressImage<TYPE_ATC_GENERIC, true, kQualityHigh>(src, dst, width, height); |
+} |
+ |
+void CompressATCIA_Generic(const uint8_t* src, |
+ uint8_t* dst, |
+ int width, |
+ int height) { |
+ CompressImage<TYPE_ATC_GENERIC, false, kQualityHigh>(src, dst, width, height); |
+} |
+ |
+void CompressDXT1_Generic(const uint8_t* src, |
+ uint8_t* dst, |
+ int width, |
+ int height) { |
+ CompressImage<TYPE_DXT_GENERIC, true, kQualityHigh>(src, dst, width, height); |
+} |
+ |
+void CompressDXT5_Generic(const uint8_t* src, |
+ uint8_t* dst, |
+ int width, |
+ int height) { |
+ CompressImage<TYPE_DXT_GENERIC, false, kQualityHigh>(src, dst, width, height); |
+} |
+ |
+} // namespace texture_compress |
+} // namespace cc |