2 * Copyright 2014 Google Inc.
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
8 #include "SkTextureCompressor_ASTC.h"
9 #include "SkTextureCompressor_Blitter.h"
11 #include "SkBlitter.h"
15 // This table contains the weight values for each texel. This is used in determining
16 // how to convert a 12x12 grid of alpha values into a 6x5 grid of index values. Since
17 // we have a 6x5 grid, that gives 30 values that we have to compute. For each index,
18 // we store up to 20 different triplets of values. In order the triplets are:
19 // weight, texel-x, texel-y
20 // The weight value corresponds to the amount that this index contributes to the final
21 // index value of the given texel. Hence, we need to reconstruct the 6x5 index grid
22 // from their relative contribution to the 12x12 texel grid.
24 // The algorithm is something like this:
29 // weight = table[i][w*3];
30 // texel-x = table[i][w*3 + 1];
31 // texel-y = table[i][w*3 + 2];
33 // total-weight += weight;
34 // total-alpha += weight * alphas[texel-x][texel-y];
36 // total-alpha /= total-weight;
37 // index = top three bits of total-alpha
39 // If the associated index does not contribute to 20 different texels (e.g. it's in
40 // a corner), then the extra texels are stored with -1's in the table.
42 static const int8_t k6x5To12x12Table[30][60] = {
43 { 16, 0, 0, 9, 1, 0, 1, 2, 0, 10, 0, 1, 6, 1, 1, 1, 2, 1, 4, 0, 2, 2,
44 1, 2, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0,
45 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0}, // n = 20
46 { 7, 1, 0, 15, 2, 0, 10, 3, 0, 3, 4, 0, 4, 1, 1, 9, 2, 1, 6, 3, 1, 2,
47 4, 1, 2, 1, 2, 4, 2, 2, 3, 3, 2, 1, 4, 2, -1, 0, 0, -1, 0, 0, -1, 0,
48 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0}, // n = 20
49 { 6, 3, 0, 13, 4, 0, 12, 5, 0, 4, 6, 0, 4, 3, 1, 8, 4, 1, 8, 5, 1, 3,
50 6, 1, 1, 3, 2, 3, 4, 2, 3, 5, 2, 1, 6, 2, -1, 0, 0, -1, 0, 0, -1, 0,
51 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0}, // n = 20
52 { 4, 5, 0, 12, 6, 0, 13, 7, 0, 6, 8, 0, 2, 5, 1, 7, 6, 1, 8, 7, 1, 4,
53 8, 1, 1, 5, 2, 3, 6, 2, 3, 7, 2, 2, 8, 2, -1, 0, 0, -1, 0, 0, -1, 0,
54 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0}, // n = 20
55 { 3, 7, 0, 10, 8, 0, 15, 9, 0, 7, 10, 0, 2, 7, 1, 6, 8, 1, 9, 9, 1, 4,
56 10, 1, 1, 7, 2, 2, 8, 2, 4, 9, 2, 2, 10, 2, -1, 0, 0, -1, 0, 0, -1, 0,
57 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0}, // n = 20
58 { 1, 9, 0, 9, 10, 0, 16, 11, 0, 1, 9, 1, 6, 10, 1, 10, 11, 1, 2, 10, 2, 4,
59 11, 2, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0,
60 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0}, // n = 20
61 { 6, 0, 1, 3, 1, 1, 12, 0, 2, 7, 1, 2, 1, 2, 2, 15, 0, 3, 8, 1, 3, 1,
62 2, 3, 9, 0, 4, 5, 1, 4, 1, 2, 4, 3, 0, 5, 2, 1, 5, -1, 0, 0, -1, 0,
63 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0}, // n = 20
64 { 3, 1, 1, 6, 2, 1, 4, 3, 1, 1, 4, 1, 5, 1, 2, 11, 2, 2, 7, 3, 2, 2,
65 4, 2, 7, 1, 3, 14, 2, 3, 9, 3, 3, 3, 4, 3, 4, 1, 4, 8, 2, 4, 6, 3,
66 4, 2, 4, 4, 1, 1, 5, 3, 2, 5, 2, 3, 5, 1, 4, 5}, // n = 20
67 { 2, 3, 1, 5, 4, 1, 4, 5, 1, 1, 6, 1, 5, 3, 2, 10, 4, 2, 9, 5, 2, 3,
68 6, 2, 6, 3, 3, 12, 4, 3, 11, 5, 3, 4, 6, 3, 3, 3, 4, 7, 4, 4, 7, 5,
69 4, 2, 6, 4, 1, 3, 5, 2, 4, 5, 2, 5, 5, 1, 6, 5}, // n = 20
70 { 2, 5, 1, 5, 6, 1, 5, 7, 1, 2, 8, 1, 3, 5, 2, 9, 6, 2, 10, 7, 2, 4,
71 8, 2, 4, 5, 3, 11, 6, 3, 12, 7, 3, 6, 8, 3, 2, 5, 4, 7, 6, 4, 7, 7,
72 4, 3, 8, 4, 1, 5, 5, 2, 6, 5, 2, 7, 5, 1, 8, 5}, // n = 20
73 { 1, 7, 1, 4, 8, 1, 6, 9, 1, 3, 10, 1, 2, 7, 2, 8, 8, 2, 11, 9, 2, 5,
74 10, 2, 3, 7, 3, 9, 8, 3, 14, 9, 3, 7, 10, 3, 2, 7, 4, 6, 8, 4, 8, 9,
75 4, 4, 10, 4, 1, 7, 5, 2, 8, 5, 3, 9, 5, 1, 10, 5}, // n = 20
76 { 3, 10, 1, 6, 11, 1, 1, 9, 2, 7, 10, 2, 12, 11, 2, 1, 9, 3, 8, 10, 3, 15,
77 11, 3, 1, 9, 4, 5, 10, 4, 9, 11, 4, 2, 10, 5, 3, 11, 5, -1, 0, 0, -1, 0,
78 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0}, // n = 20
79 { 1, 0, 3, 1, 1, 3, 7, 0, 4, 4, 1, 4, 13, 0, 5, 7, 1, 5, 1, 2, 5, 13,
80 0, 6, 7, 1, 6, 1, 2, 6, 7, 0, 7, 4, 1, 7, 1, 0, 8, 1, 1, 8, -1, 0,
81 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0}, // n = 20
82 { 1, 2, 3, 1, 3, 3, 3, 1, 4, 7, 2, 4, 4, 3, 4, 1, 4, 4, 6, 1, 5, 12,
83 2, 5, 8, 3, 5, 2, 4, 5, 6, 1, 6, 12, 2, 6, 8, 3, 6, 2, 4, 6, 3, 1,
84 7, 7, 2, 7, 4, 3, 7, 1, 4, 7, 1, 2, 8, 1, 3, 8}, // n = 20
85 { 1, 4, 3, 1, 5, 3, 3, 3, 4, 6, 4, 4, 5, 5, 4, 2, 6, 4, 5, 3, 5, 11,
86 4, 5, 10, 5, 5, 3, 6, 5, 5, 3, 6, 11, 4, 6, 10, 5, 6, 3, 6, 6, 3, 3,
87 7, 6, 4, 7, 5, 5, 7, 2, 6, 7, 1, 4, 8, 1, 5, 8}, // n = 20
88 { 1, 6, 3, 1, 7, 3, 2, 5, 4, 5, 6, 4, 6, 7, 4, 3, 8, 4, 3, 5, 5, 10,
89 6, 5, 11, 7, 5, 5, 8, 5, 3, 5, 6, 10, 6, 6, 11, 7, 6, 5, 8, 6, 2, 5,
90 7, 5, 6, 7, 6, 7, 7, 3, 8, 7, 1, 6, 8, 1, 7, 8}, // n = 20
91 { 1, 8, 3, 1, 9, 3, 1, 7, 4, 4, 8, 4, 7, 9, 4, 3, 10, 4, 2, 7, 5, 8,
92 8, 5, 12, 9, 5, 6, 10, 5, 2, 7, 6, 8, 8, 6, 12, 9, 6, 6, 10, 6, 1, 7,
93 7, 4, 8, 7, 7, 9, 7, 3, 10, 7, 1, 8, 8, 1, 9, 8}, // n = 20
94 { 1, 10, 3, 1, 11, 3, 4, 10, 4, 7, 11, 4, 1, 9, 5, 7, 10, 5, 13, 11, 5, 1,
95 9, 6, 7, 10, 6, 13, 11, 6, 4, 10, 7, 7, 11, 7, 1, 10, 8, 1, 11, 8, -1, 0,
96 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0}, // n = 20
97 { 3, 0, 6, 2, 1, 6, 9, 0, 7, 5, 1, 7, 1, 2, 7, 15, 0, 8, 8, 1, 8, 1,
98 2, 8, 12, 0, 9, 7, 1, 9, 1, 2, 9, 6, 0, 10, 3, 1, 10, -1, 0, 0, -1, 0,
99 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0}, // n = 20
100 { 1, 1, 6, 3, 2, 6, 2, 3, 6, 1, 4, 6, 4, 1, 7, 8, 2, 7, 6, 3, 7, 2,
101 4, 7, 7, 1, 8, 14, 2, 8, 9, 3, 8, 3, 4, 8, 5, 1, 9, 11, 2, 9, 8, 3,
102 9, 2, 4, 9, 3, 1, 10, 6, 2, 10, 4, 3, 10, 1, 4, 10}, // n = 20
103 { 1, 3, 6, 2, 4, 6, 2, 5, 6, 1, 6, 6, 3, 3, 7, 7, 4, 7, 7, 5, 7, 2,
104 6, 7, 6, 3, 8, 12, 4, 8, 11, 5, 8, 4, 6, 8, 4, 3, 9, 10, 4, 9, 9, 5,
105 9, 3, 6, 9, 2, 3, 10, 5, 4, 10, 5, 5, 10, 2, 6, 10}, // n = 20
106 { 1, 5, 6, 2, 6, 6, 2, 7, 6, 1, 8, 6, 2, 5, 7, 7, 6, 7, 7, 7, 7, 3,
107 8, 7, 4, 5, 8, 11, 6, 8, 12, 7, 8, 6, 8, 8, 3, 5, 9, 9, 6, 9, 10, 7,
108 9, 5, 8, 9, 1, 5, 10, 4, 6, 10, 5, 7, 10, 2, 8, 10}, // n = 20
109 { 1, 7, 6, 2, 8, 6, 3, 9, 6, 1, 10, 6, 2, 7, 7, 6, 8, 7, 8, 9, 7, 4,
110 10, 7, 3, 7, 8, 9, 8, 8, 14, 9, 8, 7, 10, 8, 2, 7, 9, 7, 8, 9, 11, 9,
111 9, 5, 10, 9, 1, 7, 10, 4, 8, 10, 6, 9, 10, 3, 10, 10}, // n = 20
112 { 2, 10, 6, 3, 11, 6, 1, 9, 7, 5, 10, 7, 9, 11, 7, 1, 9, 8, 8, 10, 8, 15,
113 11, 8, 1, 9, 9, 7, 10, 9, 12, 11, 9, 3, 10, 10, 6, 11, 10, -1, 0, 0, -1, 0,
114 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0}, // n = 20
115 { 4, 0, 9, 2, 1, 9, 10, 0, 10, 6, 1, 10, 1, 2, 10, 16, 0, 11, 9, 1, 11, 1,
116 2, 11, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0,
117 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0}, // n = 20
118 { 2, 1, 9, 4, 2, 9, 2, 3, 9, 1, 4, 9, 4, 1, 10, 9, 2, 10, 6, 3, 10, 2,
119 4, 10, 7, 1, 11, 15, 2, 11, 10, 3, 11, 3, 4, 11, -1, 0, 0, -1, 0, 0, -1, 0,
120 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0}, // n = 20
121 { 2, 3, 9, 3, 4, 9, 3, 5, 9, 1, 6, 9, 4, 3, 10, 8, 4, 10, 7, 5, 10, 2,
122 6, 10, 6, 3, 11, 13, 4, 11, 12, 5, 11, 4, 6, 11, -1, 0, 0, -1, 0, 0, -1, 0,
123 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0}, // n = 20
124 { 1, 5, 9, 3, 6, 9, 3, 7, 9, 1, 8, 9, 3, 5, 10, 8, 6, 10, 8, 7, 10, 4,
125 8, 10, 4, 5, 11, 12, 6, 11, 13, 7, 11, 6, 8, 11, -1, 0, 0, -1, 0, 0, -1, 0,
126 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0}, // n = 20
127 { 1, 7, 9, 3, 8, 9, 4, 9, 9, 2, 10, 9, 2, 7, 10, 6, 8, 10, 9, 9, 10, 4,
128 10, 10, 3, 7, 11, 10, 8, 11, 15, 9, 11, 7, 10, 11, -1, 0, 0, -1, 0, 0, -1, 0,
129 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0}, // n = 20
130 { 2, 10, 9, 4, 11, 9, 1, 9, 10, 6, 10, 10, 10, 11, 10, 1, 9, 11, 9, 10, 11, 16,
131 11, 11, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0,
132 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0} // n = 20
135 // Returns the alpha value of a texel at position (x, y) from src.
136 // (x, y) are assumed to be in the range [0, 12).
137 inline uint8_t GetAlpha(const uint8_t *src, int rowBytes, int x, int y) {
138 SkASSERT(x >= 0 && x < 12);
139 SkASSERT(y >= 0 && y < 12);
140 SkASSERT(rowBytes >= 12);
141 return *(src + y*rowBytes + x);
144 inline uint8_t GetAlphaTranspose(const uint8_t *src, int rowBytes, int x, int y) {
145 return GetAlpha(src, rowBytes, y, x);
148 // Output the 16 bytes stored in top and bottom and advance the pointer. The bytes
149 // are stored as the integers are represented in memory, so they should be swapped
151 static inline void send_packing(uint8_t** dst, const uint64_t top, const uint64_t bottom) {
152 uint64_t* dst64 = reinterpret_cast<uint64_t*>(*dst);
158 // Compresses an ASTC block, by looking up the proper contributions from
159 // k6x5To12x12Table and computing an index from the associated values.
160 typedef uint8_t (*GetAlphaProc)(const uint8_t* src, int rowBytes, int x, int y);
162 template<GetAlphaProc getAlphaProc>
163 static void compress_a8_astc_block(uint8_t** dst, const uint8_t* src, int rowBytes) {
164 // Check for single color
165 bool constant = true;
166 const uint32_t firstInt = *(reinterpret_cast<const uint32_t*>(src));
167 for (int i = 0; i < 12; ++i) {
168 const uint32_t *rowInt = reinterpret_cast<const uint32_t *>(src + i*rowBytes);
169 constant = constant && (rowInt[0] == firstInt);
170 constant = constant && (rowInt[1] == firstInt);
171 constant = constant && (rowInt[2] == firstInt);
176 // All of the indices are set to zero, and the colors are
177 // v0 = 0, v1 = 255, so everything will be transparent.
178 send_packing(dst, SkTEndian_SwapLE64(0x0000000001FE000173ULL), 0);
180 } else if (0xFFFFFFFF == firstInt) {
181 // All of the indices are set to zero, and the colors are
182 // v0 = 255, v1 = 0, so everything will be opaque.
183 send_packing(dst, SkTEndian_SwapLE64(0x000000000001FE0173ULL), 0);
188 uint8_t indices[30]; // 6x5 index grid
189 for (int idx = 0; idx < 30; ++idx) {
192 for (int w = 0; w < 20; ++w) {
193 const int8_t weight = k6x5To12x12Table[idx][w*3];
195 const int x = k6x5To12x12Table[idx][w*3 + 1];
196 const int y = k6x5To12x12Table[idx][w*3 + 2];
198 alphaTot += weight * getAlphaProc(src, rowBytes, x, y);
200 // In our table, not every entry has 20 weights, and all
201 // of them are nonzero. Once we hit a negative weight, we
202 // know that all of the other weights are not valid either.
207 indices[idx] = (alphaTot / weightTot) >> 5;
210 // Pack indices... The ASTC block layout is fairly complicated. An extensive
211 // description can be found here:
212 // https://www.opengl.org/registry/specs/KHR/texture_compression_astc_hdr.txt
214 // Here is a summary of the options that we've chosen:
215 // 1. Block mode: 0b00101110011
218 // - Low-precision index values
219 // - Index range 0-7 (three bits per index)
220 // 2. Partitions: 0b00
222 // 3. Color Endpoint Mode: 0b0000
223 // - Direct luminance -- e0=(v0,v0,v0,0xFF); e1=(v1,v1,v1,0xFF);
224 // 4. 8-bit endpoints:
227 // The rest of the block contains the 30 index values from before, which
228 // are currently stored in the indices variable.
230 uint64_t top = 0x0000000001FE000173ULL;
233 for (int idx = 0; idx <= 20; ++idx) {
234 const uint8_t index = indices[idx];
235 bottom |= static_cast<uint64_t>(index) << (61-(idx*3));
238 // index 21 straddles top and bottom
240 const uint8_t index = indices[21];
242 top |= static_cast<uint64_t>((index >> 2) | (index & 2)) << 62;
245 for (int idx = 22; idx < 30; ++idx) {
246 const uint8_t index = indices[idx];
247 top |= static_cast<uint64_t>(index) << (59-(idx-22)*3);
250 // Reverse each 3-bit index since indices are read in reverse order...
251 uint64_t t = (bottom ^ (bottom >> 2)) & 0x2492492492492492ULL;
252 bottom = bottom ^ t ^ (t << 2);
254 t = (top ^ (top >> 2)) & 0x0924924000000000ULL;
255 top = top ^ t ^ (t << 2);
257 send_packing(dst, SkEndian_SwapLE64(top), SkEndian_SwapLE64(bottom));
260 inline void CompressA8ASTCBlockVertical(uint8_t* dst, const uint8_t* src) {
261 compress_a8_astc_block<GetAlphaTranspose>(&dst, src, 12);
264 ////////////////////////////////////////////////////////////////////////////////
268 // Full details available in the spec:
269 // http://www.khronos.org/registry/gles/extensions/OES/OES_texture_compression_astc.txt
271 ////////////////////////////////////////////////////////////////////////////////
273 // Enable this to assert whenever a decoded block has invalid ASTC values. Otherwise,
274 // each invalid block will result in a disgusting magenta color.
275 #define ASSERT_ASTC_DECODE_ERROR 0
277 // Reverse 64-bit integer taken from TAOCP 4a, although it's better
278 // documented at this site:
279 // http://matthewarcus.wordpress.com/2012/11/18/reversing-a-64-bit-word/
281 template <typename T, T m, int k>
282 static inline T swap_bits(T p) {
283 T q = ((p>>k)^p) & m;
287 static inline uint64_t reverse64(uint64_t n) {
288 static const uint64_t m0 = 0x5555555555555555ULL;
289 static const uint64_t m1 = 0x0300c0303030c303ULL;
290 static const uint64_t m2 = 0x00c0300c03f0003fULL;
291 static const uint64_t m3 = 0x00000ffc00003fffULL;
292 n = ((n>>1)&m0) | (n&m0)<<1;
293 n = swap_bits<uint64_t, m1, 4>(n);
294 n = swap_bits<uint64_t, m2, 8>(n);
295 n = swap_bits<uint64_t, m3, 20>(n);
296 n = (n >> 34) | (n << 30);
300 // An ASTC block is 128 bits. We represent it as two 64-bit integers in order
301 // to efficiently operate on the block using bitwise operations.
306 // Reverses the bits of an ASTC block, making the LSB of the
307 // 128 bit block the MSB.
308 inline void reverse() {
309 const uint64_t newLow = reverse64(this->fHigh);
310 this->fHigh = reverse64(this->fLow);
315 // Writes the given color to every pixel in the block. This is used by void-extent
316 // blocks (a special constant-color encoding of a block) and by the error function.
317 static inline void write_constant_color(uint8_t* dst, int blockDimX, int blockDimY,
318 int dstRowBytes, SkColor color) {
319 for (int y = 0; y < blockDimY; ++y) {
320 SkColor *dstColors = reinterpret_cast<SkColor*>(dst);
321 for (int x = 0; x < blockDimX; ++x) {
322 dstColors[x] = color;
328 // Sets the entire block to the ASTC "error" color, a disgusting magenta
329 // that's not supposed to appear in natural images.
330 static inline void write_error_color(uint8_t* dst, int blockDimX, int blockDimY,
332 static const SkColor kASTCErrorColor = SkColorSetRGB(0xFF, 0, 0xFF);
334 #if ASSERT_ASTC_DECODE_ERROR
335 SkDEBUGFAIL("ASTC decoding error!\n");
338 write_constant_color(dst, blockDimX, blockDimY, dstRowBytes, kASTCErrorColor);
341 // Reads up to 64 bits of the ASTC block starting from bit
342 // 'from' and going up to but not including bit 'to'. 'from' starts
343 // counting from the LSB, counting up to the MSB. Returns -1 on
345 static uint64_t read_astc_bits(const ASTCBlock &block, int from, int to) {
346 SkASSERT(0 <= from && from <= 128);
347 SkASSERT(0 <= to && to <= 128);
349 const int nBits = to - from;
354 if (nBits < 0 || 64 <= nBits) {
355 SkDEBUGFAIL("ASTC -- shouldn't read more than 64 bits");
359 // Remember, the 'to' bit isn't read.
362 // All desired bits are in the low 64-bits.
363 result = (block.fLow >> from) & ((1ULL << nBits) - 1);
364 } else if (from >= 64) {
365 // All desired bits are in the high 64-bits.
366 result = (block.fHigh >> (from - 64)) & ((1ULL << nBits) - 1);
368 // from < 64 && to > 64
369 SkASSERT(nBits > (64 - from));
370 const int nLow = 64 - from;
371 const int nHigh = nBits - nLow;
373 ((block.fLow >> from) & ((1ULL << nLow) - 1)) |
374 ((block.fHigh & ((1ULL << nHigh) - 1)) << nLow);
380 // Returns the number of bits needed to represent a number
381 // in the given power-of-two range (excluding the power of two itself).
382 static inline int bits_for_range(int x) {
383 SkASSERT(SkIsPow2(x));
385 // Since we know it's a power of two, there should only be one bit set,
386 // meaning the number of trailing zeros is 31 minus the number of leading
388 return 31 - SkCLZ(x);
391 // Clamps an integer to the range [0, 255]
392 static inline int clamp_byte(int x) {
393 return SkClampMax(x, 255);
396 // Helper function defined in the ASTC spec, section C.2.14
397 // It transfers a few bits of precision from one value to another.
398 static inline void bit_transfer_signed(int *a, int *b) {
403 if ( (*a & 0x20) != 0 ) {
408 // Helper function defined in the ASTC spec, section C.2.14
409 // It uses the value in the blue channel to tint the red and green
410 static inline SkColor blue_contract(int a, int r, int g, int b) {
411 return SkColorSetARGB(a, (r + b) >> 1, (g + b) >> 1, b);
414 // Helper function that decodes two colors from eight values. If isRGB is true,
415 // then the pointer 'v' contains six values and the last two are considered to be
416 // 0xFF. If isRGB is false, then all eight values come from the pointer 'v'. This
417 // corresponds to the decode procedure for the following endpoint modes:
418 // kLDR_RGB_Direct_ColorEndpointMode
419 // kLDR_RGBA_Direct_ColorEndpointMode
420 static inline void decode_rgba_direct(const int *v, SkColor *endpoints, bool isRGB) {
429 const int s0 = v[0] + v[2] + v[4];
430 const int s1 = v[1] + v[3] + v[5];
433 endpoints[0] = SkColorSetARGB(v6, v[0], v[2], v[4]);
434 endpoints[1] = SkColorSetARGB(v7, v[1], v[3], v[5]);
436 endpoints[0] = blue_contract(v7, v[1], v[3], v[5]);
437 endpoints[1] = blue_contract(v6, v[0], v[2], v[4]);
441 // Helper function that decodes two colors from six values. If isRGB is true,
442 // then the pointer 'v' contains four values and the last two are considered to be
443 // 0xFF. If isRGB is false, then all six values come from the pointer 'v'. This
444 // corresponds to the decode procedure for the following endpoint modes:
445 // kLDR_RGB_BaseScale_ColorEndpointMode
446 // kLDR_RGB_BaseScaleWithAlpha_ColorEndpointMode
447 static inline void decode_rgba_basescale(const int *v, SkColor *endpoints, bool isRGB) {
456 endpoints[0] = SkColorSetARGB(v4,
460 endpoints[1] = SkColorSetARGB(v5, v[0], v[1], v[2]);
463 // Helper function that decodes two colors from eight values. If isRGB is true,
464 // then the pointer 'v' contains six values and the last two are considered to be
465 // 0xFF. If isRGB is false, then all eight values come from the pointer 'v'. This
466 // corresponds to the decode procedure for the following endpoint modes:
467 // kLDR_RGB_BaseOffset_ColorEndpointMode
468 // kLDR_RGBA_BaseOffset_ColorEndpointMode
470 // If isRGB is true, then treat this as if v6 and v7 are meant to encode full alpha values.
471 static inline void decode_rgba_baseoffset(const int *v, SkColor *endpoints, bool isRGB) {
478 int v6 = isRGB ? 0xFF : v[6];
479 // The 0 is here because this is an offset, not a direct value
480 int v7 = isRGB ? 0 : v[7];
482 bit_transfer_signed(&v1, &v0);
483 bit_transfer_signed(&v3, &v2);
484 bit_transfer_signed(&v5, &v4);
486 bit_transfer_signed(&v7, &v6);
490 if ((v1 + v3 + v5) >= 0) {
502 c[0][1] = (v0 + v1 + v4 + v5) >> 1;
503 c[0][2] = (v2 + v3 + v4 + v5) >> 1;
507 c[1][1] = (v0 + v4) >> 1;
508 c[1][2] = (v2 + v4) >> 1;
512 endpoints[0] = SkColorSetARGB(clamp_byte(c[0][0]),
515 clamp_byte(c[0][3]));
517 endpoints[1] = SkColorSetARGB(clamp_byte(c[1][0]),
520 clamp_byte(c[1][3]));
524 // A helper class used to decode bit values from standard integer values.
525 // We can't use this class with ASTCBlock because then it would need to
526 // handle multi-value ranges, and it's non-trivial to lookup a range of bits
527 // that splits across two different ints.
528 template <typename T>
531 SkTBits(const T val) : fVal(val) { }
533 // Returns the bit at the given position
534 T operator [](const int idx) const {
535 return (fVal >> idx) & 1;
538 // Returns the bits in the given range, inclusive
539 T operator ()(const int end, const int start) const {
540 SkASSERT(end >= start);
541 return (fVal >> start) & ((1ULL << ((end - start) + 1)) - 1);
548 // This algorithm matches the trit block decoding in the spec (Table C.2.14)
549 static void decode_trit_block(int* dst, int nBits, const uint64_t &block) {
551 SkTBits<uint64_t> blockBits(block);
553 // According to the spec, a trit block, which contains five values,
554 // has the following layout:
556 // 27 26 25 24 23 22 21 20 19 18 17 16
557 // -----------------------------------------------
558 // |T7 | m4 |T6 T5 | m3 |T4 |
559 // -----------------------------------------------
561 // 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
562 // --------------------------------------------------------------
563 // | m2 |T3 T2 | m1 |T1 T0 | m0 |
564 // --------------------------------------------------------------
566 // Where the m's are variable width depending on the number of bits used
567 // to encode the values (anywhere from 0 to 6). Since 3^5 = 243, the extra
568 // byte labeled T (whose bits are interleaved where 0 is the LSB and 7 is
569 // the MSB), contains five trit values. To decode the trit values, the spec
570 // says that we need to follow the following algorithm:
573 // C = { T[7:5], T[1:0] }; t4 = t3 = 2
580 // t4 = T[7]; t3 = T[6:5]
583 // t2 = 2; t1 = C[4]; t0 = { C[3], C[2]&~C[3] }
584 // else if C[3:2] = 11
585 // t2 = 2; t1 = 2; t0 = C[1:0]
587 // t2 = C[4]; t1 = C[3:2]; t0 = { C[1], C[0]&~C[1] }
589 // The following C++ code is meant to mirror this layout and algorithm as
590 // closely as possible.
594 memset(m, 0, sizeof(m));
597 m[0] = static_cast<int>(blockBits(nBits - 1, 0));
598 m[1] = static_cast<int>(blockBits(2*nBits - 1 + 2, nBits + 2));
599 m[2] = static_cast<int>(blockBits(3*nBits - 1 + 4, 2*nBits + 4));
600 m[3] = static_cast<int>(blockBits(4*nBits - 1 + 5, 3*nBits + 5));
601 m[4] = static_cast<int>(blockBits(5*nBits - 1 + 7, 4*nBits + 7));
605 static_cast<int>(blockBits(nBits + 1, nBits)) |
606 (static_cast<int>(blockBits(2*nBits + 2 + 1, 2*nBits + 2)) << 2) |
607 (static_cast<int>(blockBits[3*nBits + 4] << 4)) |
608 (static_cast<int>(blockBits(4*nBits + 5 + 1, 4*nBits + 5)) << 5) |
609 (static_cast<int>(blockBits[5*nBits + 7] << 7));
614 SkTBits<int> Tbits(T);
615 if (0x7 == Tbits(4, 2)) {
616 C = (Tbits(7, 5) << 2) | Tbits(1, 0);
620 if (Tbits(6, 5) == 0x3) {
621 t[4] = 2; t[3] = Tbits[7];
623 t[4] = Tbits[7]; t[3] = Tbits(6, 5);
627 SkTBits<int> Cbits(C);
628 if (Cbits(1, 0) == 0x3) {
631 t[0] = (Cbits[3] << 1) | (Cbits[2] & (0x1 & ~(Cbits[3])));
632 } else if (Cbits(3, 2) == 0x3) {
639 t[0] = (Cbits[1] << 1) | (Cbits[0] & (0x1 & ~(Cbits[1])));
643 // Make sure all of the decoded values have a trit less than three
644 // and a bit value within the range of the allocated bits.
645 for (int i = 0; i < 5; ++i) {
647 SkASSERT(m[i] < (1 << nBits));
651 for (int i = 0; i < 5; ++i) {
652 *dst = (t[i] << nBits) + m[i];
657 // This algorithm matches the quint block decoding in the spec (Table C.2.15)
658 static void decode_quint_block(int* dst, int nBits, const uint64_t &block) {
659 SkTBits<uint64_t> blockBits(block);
661 // According to the spec, a quint block, which contains three values,
662 // has the following layout:
665 // 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
666 // --------------------------------------------------------------------------
667 // |Q6 Q5 | m2 |Q4 Q3 | m1 |Q2 Q1 Q0 | m0 |
668 // --------------------------------------------------------------------------
670 // Where the m's are variable width depending on the number of bits used
671 // to encode the values (anywhere from 0 to 4). Since 5^3 = 125, the extra
672 // 7-bit value labeled Q (whose bits are interleaved where 0 is the LSB and 6 is
673 // the MSB), contains three quint values. To decode the quint values, the spec
674 // says that we need to follow the following algorithm:
676 // if Q[2:1] = 11 and Q[6:5] = 00
677 // q2 = { Q[0], Q[4]&~Q[0], Q[3]&~Q[0] }; q1 = q0 = 4
680 // q2 = 4; C = { Q[4:3], ~Q[6:5], Q[0] }
682 // q2 = T[6:5]; C = Q[4:0]
685 // q1 = 4; q0 = C[4:3]
687 // q1 = C[4:3]; q0 = C[2:0]
689 // The following C++ code is meant to mirror this layout and algorithm as
690 // closely as possible.
694 memset(m, 0, sizeof(m));
697 m[0] = static_cast<int>(blockBits(nBits - 1, 0));
698 m[1] = static_cast<int>(blockBits(2*nBits - 1 + 3, nBits + 3));
699 m[2] = static_cast<int>(blockBits(3*nBits - 1 + 5, 2*nBits + 5));
703 static_cast<int>(blockBits(nBits + 2, nBits)) |
704 (static_cast<int>(blockBits(2*nBits + 3 + 1, 2*nBits + 3)) << 3) |
705 (static_cast<int>(blockBits(3*nBits + 5 + 1, 3*nBits + 5)) << 5);
708 SkTBits<int> Qbits(Q); // quantum?
710 if (Qbits(2, 1) == 0x3 && Qbits(6, 5) == 0) {
711 const int notBitZero = (0x1 & ~(Qbits[0]));
712 q[2] = (Qbits[0] << 2) | ((Qbits[4] & notBitZero) << 1) | (Qbits[3] & notBitZero);
717 if (Qbits(2, 1) == 0x3) {
719 C = (Qbits(4, 3) << 3) | ((0x3 & ~(Qbits(6, 5))) << 1) | Qbits[0];
725 SkTBits<int> Cbits(C);
726 if (Cbits(2, 0) == 0x5) {
736 for (int i = 0; i < 3; ++i) {
738 SkASSERT(m[i] < (1 << nBits));
742 for (int i = 0; i < 3; ++i) {
743 *dst = (q[i] << nBits) + m[i];
748 // Function that decodes a sequence of integers stored as an ISE (Integer
749 // Sequence Encoding) bit stream. The full details of this function are outlined
750 // in section C.2.12 of the ASTC spec. A brief overview is as follows:
752 // - Each integer in the sequence is bounded by a specific range r.
753 // - The range of each value determines the way the bit stream is interpreted,
754 // - If the range is a power of two, then the sequence is a sequence of bits
755 // - If the range is of the form 3*2^n, then the sequence is stored as a
756 // sequence of blocks, each block contains 5 trits and 5 bit sequences, which
757 // decodes into 5 values.
758 // - Similarly, if the range is of the form 5*2^n, then the sequence is stored as a
759 // sequence of blocks, each block contains 3 quints and 3 bit sequences, which
760 // decodes into 3 values.
761 static bool decode_integer_sequence(
762 int* dst, // The array holding the destination bits
763 int dstSize, // The maximum size of the array
764 int nVals, // The number of values that we'd like to decode
765 const ASTCBlock &block, // The block that we're decoding from
766 int startBit, // The bit from which we're going to do the reading
767 int endBit, // The bit at which we stop reading (not inclusive)
768 bool bReadForward, // If true, then read LSB -> MSB, else read MSB -> LSB
769 int nBits, // The number of bits representing this encoding
770 int nTrits, // The number of trits representing this encoding
771 int nQuints // The number of quints representing this encoding
773 // If we want more values than we have, then fail.
774 if (nVals > dstSize) {
778 ASTCBlock src = block;
782 startBit = 128 - startBit;
783 endBit = 128 - endBit;
789 SkASSERT(0 == nQuints);
791 int endBlockBit = startBit + 8 + 5*nBits;
792 if (endBlockBit > endBit) {
793 endBlockBit = endBit;
796 // Trit blocks are three values large.
798 decode_trit_block(trits, nBits, read_astc_bits(src, startBit, endBlockBit));
799 memcpy(dst, trits, SkMin32(nVals, 5)*sizeof(int));
803 startBit = endBlockBit;
805 } else if (nQuints > 0) {
806 SkASSERT(0 == nTrits);
808 int endBlockBit = startBit + 7 + 3*nBits;
809 if (endBlockBit > endBit) {
810 endBlockBit = endBit;
813 // Quint blocks are three values large
815 decode_quint_block(quints, nBits, read_astc_bits(src, startBit, endBlockBit));
816 memcpy(dst, quints, SkMin32(nVals, 3)*sizeof(int));
820 startBit = endBlockBit;
823 // Just read the bits, but don't read more than we have...
824 int endValBit = startBit + nBits;
825 if (endValBit > endBit) {
829 SkASSERT(endValBit - startBit < 31);
830 *dst = static_cast<int>(read_astc_bits(src, startBit, endValBit));
833 startBit = endValBit;
840 // Helper function that unquantizes some (seemingly random) generated
841 // numbers... meant to match the ASTC hardware. This function is used
842 // to unquantize both colors (Table C.2.16) and weights (Table C.2.26)
843 static inline int unquantize_value(unsigned mask, int A, int B, int C, int D) {
846 T = (A & mask) | (T >> 2);
851 // Helper function to replicate the bits in x that represents an oldPrec
852 // precision integer into a prec precision integer. For example:
853 // 255 == replicate_bits(7, 3, 8);
854 static inline int replicate_bits(int x, int oldPrec, int prec) {
855 while (oldPrec < prec) {
856 const int toShift = SkMin32(prec-oldPrec, oldPrec);
857 x = (x << toShift) | (x >> (oldPrec - toShift));
861 // Make sure that no bits are set outside the desired precision.
862 SkASSERT((-(1 << prec) & x) == 0);
866 // Returns the unquantized value of a color that's represented only as
868 static inline int unquantize_bits_color(int val, int nBits) {
869 return replicate_bits(val, nBits, 8);
872 // Returns the unquantized value of a color that's represented as a
873 // trit followed by nBits bits. This algorithm follows the sequence
874 // defined in section C.2.13 of the ASTC spec.
875 static inline int unquantize_trit_color(int val, int nBits) {
879 const int D = (val >> nBits) & 0x3;
882 const int A = -(val & 0x1) & 0x1FF;
884 static const int Cvals[6] = { 204, 93, 44, 22, 11, 5 };
885 const int C = Cvals[nBits - 1];
888 const SkTBits<int> valBits(val);
895 const int b = valBits[1];
896 B = (b << 1) | (b << 2) | (b << 4) | (b << 8);
901 const int cb = valBits(2, 1);
902 B = cb | (cb << 2) | (cb << 7);
907 const int dcb = valBits(3, 1);
908 B = dcb | (dcb << 6);
913 const int edcb = valBits(4, 1);
914 B = (edcb << 5) | (edcb >> 2);
919 const int fedcb = valBits(5, 1);
920 B = (fedcb << 4) | (fedcb >> 4);
925 return unquantize_value(0x80, A, B, C, D);
928 // Returns the unquantized value of a color that's represented as a
929 // quint followed by nBits bits. This algorithm follows the sequence
930 // defined in section C.2.13 of the ASTC spec.
931 static inline int unquantize_quint_color(int val, int nBits) {
932 const int D = (val >> nBits) & 0x7;
935 const int A = -(val & 0x1) & 0x1FF;
937 static const int Cvals[5] = { 113, 54, 26, 13, 6 };
941 const int C = Cvals[nBits - 1];
944 const SkTBits<int> valBits(val);
951 const int b = valBits[1];
952 B = (b << 2) | (b << 3) | (b << 8);
957 const int cb = valBits(2, 1);
958 B = (cb >> 1) | (cb << 1) | (cb << 7);
963 const int dcb = valBits(3, 1);
964 B = (dcb >> 1) | (dcb << 6);
969 const int edcb = valBits(4, 1);
970 B = (edcb << 5) | (edcb >> 3);
975 return unquantize_value(0x80, A, B, C, D);
978 // This algorithm takes a list of integers, stored in vals, and unquantizes them
979 // in place. This follows the algorithm laid out in section C.2.13 of the ASTC spec.
980 static void unquantize_colors(int *vals, int nVals, int nBits, int nTrits, int nQuints) {
981 for (int i = 0; i < nVals; ++i) {
983 SkASSERT(nQuints == 0);
984 vals[i] = unquantize_trit_color(vals[i], nBits);
985 } else if (nQuints > 0) {
986 SkASSERT(nTrits == 0);
987 vals[i] = unquantize_quint_color(vals[i], nBits);
989 SkASSERT(nQuints == 0 && nTrits == 0);
990 vals[i] = unquantize_bits_color(vals[i], nBits);
995 // Returns an interpolated value between c0 and c1 based on the weight. This
996 // follows the algorithm laid out in section C.2.19 of the ASTC spec.
997 static int interpolate_channel(int c0, int c1, int weight) {
998 SkASSERT(0 <= c0 && c0 < 256);
999 SkASSERT(0 <= c1 && c1 < 256);
1001 c0 = (c0 << 8) | c0;
1002 c1 = (c1 << 8) | c1;
1004 const int result = ((c0*(64 - weight) + c1*weight + 32) / 64) >> 8;
1010 SkASSERT(result >= 0);
1014 // Returns an interpolated color between the two endpoints based on the weight.
1015 static SkColor interpolate_endpoints(const SkColor endpoints[2], int weight) {
1016 return SkColorSetARGB(
1017 interpolate_channel(SkColorGetA(endpoints[0]), SkColorGetA(endpoints[1]), weight),
1018 interpolate_channel(SkColorGetR(endpoints[0]), SkColorGetR(endpoints[1]), weight),
1019 interpolate_channel(SkColorGetG(endpoints[0]), SkColorGetG(endpoints[1]), weight),
1020 interpolate_channel(SkColorGetB(endpoints[0]), SkColorGetB(endpoints[1]), weight));
1023 // Returns an interpolated color between the two endpoints based on the weight.
1024 // It uses separate weights for the channel depending on the value of the 'plane'
1025 // variable. By default, all channels will use weight 0, and the value of plane
1026 // means that weight1 will be used for:
1031 static SkColor interpolate_dual_endpoints(
1032 const SkColor endpoints[2], int weight0, int weight1, int plane) {
1033 int a = interpolate_channel(SkColorGetA(endpoints[0]), SkColorGetA(endpoints[1]), weight0);
1034 int r = interpolate_channel(SkColorGetR(endpoints[0]), SkColorGetR(endpoints[1]), weight0);
1035 int g = interpolate_channel(SkColorGetG(endpoints[0]), SkColorGetG(endpoints[1]), weight0);
1036 int b = interpolate_channel(SkColorGetB(endpoints[0]), SkColorGetB(endpoints[1]), weight0);
1041 r = interpolate_channel(
1042 SkColorGetR(endpoints[0]), SkColorGetR(endpoints[1]), weight1);
1046 g = interpolate_channel(
1047 SkColorGetG(endpoints[0]), SkColorGetG(endpoints[1]), weight1);
1051 b = interpolate_channel(
1052 SkColorGetB(endpoints[0]), SkColorGetB(endpoints[1]), weight1);
1056 a = interpolate_channel(
1057 SkColorGetA(endpoints[0]), SkColorGetA(endpoints[1]), weight1);
1061 SkDEBUGFAIL("Plane should be 0-3");
1065 return SkColorSetARGB(a, r, g, b);
1068 // A struct of decoded values that we use to carry around information
1069 // about the block. dimX and dimY are the dimension in texels of the block,
1070 // for which there is only a limited subset of valid values:
1072 // 4x4, 5x4, 5x5, 6x5, 6x6, 8x5, 8x6, 8x8, 10x5, 10x6, 10x8, 10x10, 12x10, 12x12
1074 struct ASTCDecompressionData {
1075 ASTCDecompressionData(int dimX, int dimY) : fDimX(dimX), fDimY(dimY) { }
1076 const int fDimX; // the X dimension of the decompressed block
1077 const int fDimY; // the Y dimension of the decompressed block
1078 ASTCBlock fBlock; // the block data
1079 int fBlockMode; // the block header that contains the block mode.
1081 bool fDualPlaneEnabled; // is this block compressing dual weight planes?
1082 int fDualPlane; // the independent plane in dual plane mode.
1084 bool fVoidExtent; // is this block a single color?
1085 bool fError; // does this block have an error encoding?
1087 int fWeightDimX; // the x dimension of the weight grid
1088 int fWeightDimY; // the y dimension of the weight grid
1090 int fWeightBits; // the number of bits used for each weight value
1091 int fWeightTrits; // the number of trits used for each weight value
1092 int fWeightQuints; // the number of quints used for each weight value
1094 int fPartCount; // the number of partitions in this block
1095 int fPartIndex; // the partition index: only relevant if fPartCount > 0
1097 // CEM values can be anything in the range 0-15, and each corresponds to a different
1098 // mode that represents the color data. We only support LDR modes.
1099 enum ColorEndpointMode {
1100 kLDR_Luminance_Direct_ColorEndpointMode = 0,
1101 kLDR_Luminance_BaseOffset_ColorEndpointMode = 1,
1102 kHDR_Luminance_LargeRange_ColorEndpointMode = 2,
1103 kHDR_Luminance_SmallRange_ColorEndpointMode = 3,
1104 kLDR_LuminanceAlpha_Direct_ColorEndpointMode = 4,
1105 kLDR_LuminanceAlpha_BaseOffset_ColorEndpointMode = 5,
1106 kLDR_RGB_BaseScale_ColorEndpointMode = 6,
1107 kHDR_RGB_BaseScale_ColorEndpointMode = 7,
1108 kLDR_RGB_Direct_ColorEndpointMode = 8,
1109 kLDR_RGB_BaseOffset_ColorEndpointMode = 9,
1110 kLDR_RGB_BaseScaleWithAlpha_ColorEndpointMode = 10,
1111 kHDR_RGB_ColorEndpointMode = 11,
1112 kLDR_RGBA_Direct_ColorEndpointMode = 12,
1113 kLDR_RGBA_BaseOffset_ColorEndpointMode = 13,
1114 kHDR_RGB_LDRAlpha_ColorEndpointMode = 14,
1115 kHDR_RGB_HDRAlpha_ColorEndpointMode = 15
1117 static const int kMaxColorEndpointModes = 16;
1119 // the color endpoint modes for this block.
1120 static const int kMaxPartitions = 4;
1121 ColorEndpointMode fCEM[kMaxPartitions];
1123 int fColorStartBit; // The bit position of the first bit of the color data
1124 int fColorEndBit; // The bit position of the last *possible* bit of the color data
1126 // Returns the number of partitions for this block.
1127 int numPartitions() const {
1131 // Returns the total number of weight values that are stored in this block
1132 int numWeights() const {
1133 return fWeightDimX * fWeightDimY * (fDualPlaneEnabled ? 2 : 1);
1137 // Returns the maximum value that any weight can take. We really only use
1138 // this function for debugging.
1139 int maxWeightValue() const {
1140 int maxVal = (1 << fWeightBits);
1141 if (fWeightTrits > 0) {
1142 SkASSERT(0 == fWeightQuints);
1144 } else if (fWeightQuints > 0) {
1145 SkASSERT(0 == fWeightTrits);
1152 // The number of bits needed to represent the texel weight data. This
1153 // comes from the 'data size determination' section of the ASTC spec (C.2.22)
1154 int numWeightBits() const {
1155 const int nWeights = this->numWeights();
1157 ((nWeights*8*fWeightTrits + 4) / 5) +
1158 ((nWeights*7*fWeightQuints + 2) / 3) +
1159 (nWeights*fWeightBits);
1162 // Returns the number of color values stored in this block. The number of
1163 // values stored is directly a function of the color endpoint modes.
1164 int numColorValues() const {
1166 for (int i = 0; i < this->numPartitions(); ++i) {
1167 int cemInt = static_cast<int>(fCEM[i]);
1168 numValues += ((cemInt >> 2) + 1) * 2;
1174 // Figures out the number of bits available for color values, and fills
1175 // in the maximum encoding that will fit the number of color values that
1176 // we need. Returns false on error. (See section C.2.22 of the spec)
1177 bool getColorValueEncoding(int *nBits, int *nTrits, int *nQuints) const {
1178 if (NULL == nBits || NULL == nTrits || NULL == nQuints) {
1182 const int nColorVals = this->numColorValues();
1183 if (nColorVals <= 0) {
1187 const int colorBits = fColorEndBit - fColorStartBit;
1188 SkASSERT(colorBits > 0);
1190 // This is the minimum amount of accuracy required by the spec.
1191 if (colorBits < ((13 * nColorVals + 4) / 5)) {
1195 // Values can be represented as at most 8-bit values.
1196 // !SPEED! place this in a lookup table based on colorBits and nColorVals
1197 for (int i = 255; i > 0; --i) {
1199 int bits = 0, trits = 0, quints = 0;
1201 if (SkIsPow2(range)) {
1202 bits = bits_for_range(range);
1204 } else if ((range % 3) == 0 && SkIsPow2(range/3)) {
1206 bits = bits_for_range(range/3);
1208 } else if ((range % 5) == 0 && SkIsPow2(range/5)) {
1210 bits = bits_for_range(range/5);
1215 const int actualColorBits =
1216 ((nColorVals*8*trits + 4) / 5) +
1217 ((nColorVals*7*quints + 2) / 3) +
1219 if (actualColorBits <= colorBits) {
1231 // Converts the sequence of color values into endpoints. The algorithm here
1232 // corresponds to the values determined by section C.2.14 of the ASTC spec
1233 void colorEndpoints(SkColor endpoints[4][2], const int* colorValues) const {
1234 for (int i = 0; i < this->numPartitions(); ++i) {
1236 case kLDR_Luminance_Direct_ColorEndpointMode: {
1237 const int* v = colorValues;
1238 endpoints[i][0] = SkColorSetARGB(0xFF, v[0], v[0], v[0]);
1239 endpoints[i][1] = SkColorSetARGB(0xFF, v[1], v[1], v[1]);
1245 case kLDR_Luminance_BaseOffset_ColorEndpointMode: {
1246 const int* v = colorValues;
1247 const int L0 = (v[0] >> 2) | (v[1] & 0xC0);
1248 const int L1 = clamp_byte(L0 + (v[1] & 0x3F));
1250 endpoints[i][0] = SkColorSetARGB(0xFF, L0, L0, L0);
1251 endpoints[i][1] = SkColorSetARGB(0xFF, L1, L1, L1);
1257 case kLDR_LuminanceAlpha_Direct_ColorEndpointMode: {
1258 const int* v = colorValues;
1260 endpoints[i][0] = SkColorSetARGB(v[2], v[0], v[0], v[0]);
1261 endpoints[i][1] = SkColorSetARGB(v[3], v[1], v[1], v[1]);
1267 case kLDR_LuminanceAlpha_BaseOffset_ColorEndpointMode: {
1268 int v0 = colorValues[0];
1269 int v1 = colorValues[1];
1270 int v2 = colorValues[2];
1271 int v3 = colorValues[3];
1273 bit_transfer_signed(&v1, &v0);
1274 bit_transfer_signed(&v3, &v2);
1276 endpoints[i][0] = SkColorSetARGB(v2, v0, v0, v0);
1277 endpoints[i][1] = SkColorSetARGB(
1287 case kLDR_RGB_BaseScale_ColorEndpointMode: {
1288 decode_rgba_basescale(colorValues, endpoints[i], true);
1293 case kLDR_RGB_Direct_ColorEndpointMode: {
1294 decode_rgba_direct(colorValues, endpoints[i], true);
1299 case kLDR_RGB_BaseOffset_ColorEndpointMode: {
1300 decode_rgba_baseoffset(colorValues, endpoints[i], true);
1305 case kLDR_RGB_BaseScaleWithAlpha_ColorEndpointMode: {
1306 decode_rgba_basescale(colorValues, endpoints[i], false);
1311 case kLDR_RGBA_Direct_ColorEndpointMode: {
1312 decode_rgba_direct(colorValues, endpoints[i], false);
1317 case kLDR_RGBA_BaseOffset_ColorEndpointMode: {
1318 decode_rgba_baseoffset(colorValues, endpoints[i], false);
1324 SkDEBUGFAIL("HDR mode unsupported! This should be caught sooner.");
1330 // Follows the procedure from section C.2.17 of the ASTC specification
1331 int unquantizeWeight(int x) const {
1332 SkASSERT(x <= this->maxWeightValue());
1334 const int D = (x >> fWeightBits) & 0x7;
1335 const int A = -(x & 0x1) & 0x7F;
1337 SkTBits<int> xbits(x);
1340 if (fWeightTrits > 0) {
1341 SkASSERT(0 == fWeightQuints);
1342 switch (fWeightBits) {
1344 // x is a single trit
1347 static const int kUnquantizationTable[3] = { 0, 32, 63 };
1348 T = kUnquantizationTable[x];
1355 T = unquantize_value(0x20, A, B, C, D);
1360 const int b = xbits[1];
1361 const int B = b | (b << 2) | (b << 6);
1363 T = unquantize_value(0x20, A, B, C, D);
1368 const int cb = xbits(2, 1);
1369 const int B = cb | (cb << 5);
1371 T = unquantize_value(0x20, A, B, C, D);
1376 SkDEBUGFAIL("Too many bits for trit encoding");
1380 } else if (fWeightQuints > 0) {
1381 SkASSERT(0 == fWeightTrits);
1382 switch (fWeightBits) {
1384 // x is a single quint
1387 static const int kUnquantizationTable[5] = { 0, 16, 32, 47, 63 };
1388 T = kUnquantizationTable[x];
1395 T = unquantize_value(0x20, A, B, C, D);
1400 const int b = xbits[1];
1401 const int B = (b << 1) | (b << 6);
1403 T = unquantize_value(0x20, A, B, C, D);
1408 SkDEBUGFAIL("Too many bits for quint encoding");
1412 SkASSERT(0 == fWeightTrits);
1413 SkASSERT(0 == fWeightQuints);
1415 T = replicate_bits(x, fWeightBits, 6);
1418 // This should bring the value within [0, 63]..
1430 // Returns the weight at the associated index. If the index is out of bounds, it
1431 // returns zero. It also chooses the weight appropriately based on the given dual
1433 int getWeight(const int* unquantizedWeights, int idx, bool dualPlane) const {
1434 const int maxIdx = (fDualPlaneEnabled ? 2 : 1) * fWeightDimX * fWeightDimY - 1;
1435 if (fDualPlaneEnabled) {
1436 const int effectiveIdx = 2*idx + (dualPlane ? 1 : 0);
1437 if (effectiveIdx > maxIdx) {
1440 return unquantizedWeights[effectiveIdx];
1443 SkASSERT(!dualPlane);
1448 return unquantizedWeights[idx];
1452 // This computes the effective weight at location (s, t) of the block. This
1453 // weight is computed by sampling the texel weight grid (it's usually not 1-1), and
1454 // then applying a bilerp. The algorithm outlined here follows the algorithm
1455 // defined in section C.2.18 of the ASTC spec.
1456 int infillWeight(const int* unquantizedValues, int s, int t, bool dualPlane) const {
1457 const int Ds = (1024 + fDimX/2) / (fDimX - 1);
1458 const int Dt = (1024 + fDimY/2) / (fDimY - 1);
1460 const int cs = Ds * s;
1461 const int ct = Dt * t;
1463 const int gs = (cs*(fWeightDimX - 1) + 32) >> 6;
1464 const int gt = (ct*(fWeightDimY - 1) + 32) >> 6;
1466 const int js = gs >> 4;
1467 const int jt = gt >> 4;
1469 const int fs = gs & 0xF;
1470 const int ft = gt & 0xF;
1472 const int idx = js + jt*fWeightDimX;
1473 const int p00 = this->getWeight(unquantizedValues, idx, dualPlane);
1474 const int p01 = this->getWeight(unquantizedValues, idx + 1, dualPlane);
1475 const int p10 = this->getWeight(unquantizedValues, idx + fWeightDimX, dualPlane);
1476 const int p11 = this->getWeight(unquantizedValues, idx + fWeightDimX + 1, dualPlane);
1478 const int w11 = (fs*ft + 8) >> 4;
1479 const int w10 = ft - w11;
1480 const int w01 = fs - w11;
1481 const int w00 = 16 - fs - ft + w11;
1483 const int weight = (p00*w00 + p01*w01 + p10*w10 + p11*w11 + 8) >> 4;
1484 SkASSERT(weight <= 64);
1488 // Unquantizes the decoded texel weights as described in section C.2.17 of
1489 // the ASTC specification. Additionally, it populates texelWeights with
1490 // the expanded weight grid, which is computed according to section C.2.18
1491 void texelWeights(int texelWeights[2][12][12], const int* texelValues) const {
1492 // Unquantized texel weights...
1493 int unquantizedValues[144*2]; // 12x12 blocks with dual plane decoding...
1494 SkASSERT(this->numWeights() <= 144*2);
1496 // Unquantize the weights and cache them
1497 for (int j = 0; j < this->numWeights(); ++j) {
1498 unquantizedValues[j] = this->unquantizeWeight(texelValues[j]);
1501 // Do weight infill...
1502 for (int y = 0; y < fDimY; ++y) {
1503 for (int x = 0; x < fDimX; ++x) {
1504 texelWeights[0][x][y] = this->infillWeight(unquantizedValues, x, y, false);
1505 if (fDualPlaneEnabled) {
1506 texelWeights[1][x][y] = this->infillWeight(unquantizedValues, x, y, true);
1512 // Returns the partition for the texel located at position (x, y).
1513 // Adapted from C.2.21 of the ASTC specification
1514 int getPartition(int x, int y) const {
1515 const int partitionCount = this->numPartitions();
1516 int seed = fPartIndex;
1517 if ((fDimX * fDimY) < 31) {
1522 seed += (partitionCount - 1) * 1024;
1525 p ^= p >> 15; p -= p << 17; p += p << 7; p += p << 4;
1526 p ^= p >> 5; p += p << 16; p ^= p >> 7; p ^= p >> 3;
1527 p ^= p << 6; p ^= p >> 17;
1530 uint8_t seed1 = rnum & 0xF;
1531 uint8_t seed2 = (rnum >> 4) & 0xF;
1532 uint8_t seed3 = (rnum >> 8) & 0xF;
1533 uint8_t seed4 = (rnum >> 12) & 0xF;
1534 uint8_t seed5 = (rnum >> 16) & 0xF;
1535 uint8_t seed6 = (rnum >> 20) & 0xF;
1536 uint8_t seed7 = (rnum >> 24) & 0xF;
1537 uint8_t seed8 = (rnum >> 28) & 0xF;
1538 uint8_t seed9 = (rnum >> 18) & 0xF;
1539 uint8_t seed10 = (rnum >> 22) & 0xF;
1540 uint8_t seed11 = (rnum >> 26) & 0xF;
1541 uint8_t seed12 = ((rnum >> 30) | (rnum << 2)) & 0xF;
1543 seed1 *= seed1; seed2 *= seed2;
1544 seed3 *= seed3; seed4 *= seed4;
1545 seed5 *= seed5; seed6 *= seed6;
1546 seed7 *= seed7; seed8 *= seed8;
1547 seed9 *= seed9; seed10 *= seed10;
1548 seed11 *= seed11; seed12 *= seed12;
1551 if (0 != (seed & 1)) {
1552 sh1 = (0 != (seed & 2))? 4 : 5;
1553 sh2 = (partitionCount == 3)? 6 : 5;
1555 sh1 = (partitionCount==3)? 6 : 5;
1556 sh2 = (0 != (seed & 2))? 4 : 5;
1558 sh3 = (0 != (seed & 0x10))? sh1 : sh2;
1560 seed1 >>= sh1; seed2 >>= sh2; seed3 >>= sh1; seed4 >>= sh2;
1561 seed5 >>= sh1; seed6 >>= sh2; seed7 >>= sh1; seed8 >>= sh2;
1562 seed9 >>= sh3; seed10 >>= sh3; seed11 >>= sh3; seed12 >>= sh3;
1565 int a = seed1*x + seed2*y + seed11*z + (rnum >> 14);
1566 int b = seed3*x + seed4*y + seed12*z + (rnum >> 10);
1567 int c = seed5*x + seed6*y + seed9 *z + (rnum >> 6);
1568 int d = seed7*x + seed8*y + seed10*z + (rnum >> 2);
1575 if (partitionCount < 4) {
1579 if (partitionCount < 3) {
1583 if (a >= b && a >= c && a >= d) {
1585 } else if (b >= c && b >= d) {
1587 } else if (c >= d) {
1594 // Performs the proper interpolation of the texel based on the
1595 // endpoints and weights.
1596 SkColor getTexel(const SkColor endpoints[4][2],
1597 const int weights[2][12][12],
1598 int x, int y) const {
1600 if (this->numPartitions() > 1) {
1601 part = this->getPartition(x, y);
1605 if (fDualPlaneEnabled) {
1606 result = interpolate_dual_endpoints(
1607 endpoints[part], weights[0][x][y], weights[1][x][y], fDualPlane);
1609 result = interpolate_endpoints(endpoints[part], weights[0][x][y]);
1613 // !FIXME! if we're writing directly to a bitmap, then we don't need
1614 // to swap the red and blue channels, but since we're usually being used
1615 // by the SkImageDecoder_astc module, the results are expected to be in RGBA.
1616 result = SkColorSetARGB(
1617 SkColorGetA(result), SkColorGetB(result), SkColorGetG(result), SkColorGetR(result));
1624 // First decode the block mode.
1625 this->decodeBlockMode();
1627 // Now we can decode the partition information.
1628 fPartIndex = static_cast<int>(read_astc_bits(fBlock, 11, 23));
1629 fPartCount = (fPartIndex & 0x3) + 1;
1633 if (fDualPlaneEnabled && this->numPartitions() == 4) {
1638 // Based on the partition info, we can decode the color information.
1639 this->decodeColorData();
1642 // Decodes the dual plane based on the given bit location. The final
1643 // location, if the dual plane is enabled, is also the end of our color data.
1644 // This function is only meant to be used from this->decodeColorData()
1645 void decodeDualPlane(int bitLoc) {
1646 if (fDualPlaneEnabled) {
1647 fDualPlane = static_cast<int>(read_astc_bits(fBlock, bitLoc - 2, bitLoc));
1648 fColorEndBit = bitLoc - 2;
1650 fColorEndBit = bitLoc;
1654 // Decodes the color information based on the ASTC spec.
1655 void decodeColorData() {
1657 // By default, the last color bit is at the end of the texel weights
1658 const int lastWeight = 128 - this->numWeightBits();
1660 // If we have a dual plane then it will be at this location, too.
1661 int dualPlaneBitLoc = lastWeight;
1663 // If there's only one partition, then our job is (relatively) easy.
1664 if (this->numPartitions() == 1) {
1665 fCEM[0] = static_cast<ColorEndpointMode>(read_astc_bits(fBlock, 13, 17));
1666 fColorStartBit = 17;
1668 // Handle dual plane mode...
1669 this->decodeDualPlane(dualPlaneBitLoc);
1674 // If we have more than one partition, then we need to make
1675 // room for the partition index.
1676 fColorStartBit = 29;
1678 // Read the base CEM. If it's zero, then we have no additional
1679 // CEM data and the endpoints for each partition share the same CEM.
1680 const int baseCEM = static_cast<int>(read_astc_bits(fBlock, 23, 25));
1683 const ColorEndpointMode sameCEM =
1684 static_cast<ColorEndpointMode>(read_astc_bits(fBlock, 25, 29));
1686 for (int i = 0; i < kMaxPartitions; ++i) {
1690 // Handle dual plane mode...
1691 this->decodeDualPlane(dualPlaneBitLoc);
1696 // Move the dual plane selector bits down based on how many
1697 // partitions the block contains.
1698 switch (this->numPartitions()) {
1700 dualPlaneBitLoc -= 2;
1704 dualPlaneBitLoc -= 5;
1708 dualPlaneBitLoc -= 8;
1712 SkDEBUGFAIL("Internal ASTC decoding error.");
1716 // The rest of the CEM config will be between the dual plane bit selector
1717 // and the texel weight grid.
1718 const int lowCEM = static_cast<int>(read_astc_bits(fBlock, 23, 29));
1719 SkASSERT(lastWeight >= dualPlaneBitLoc);
1720 SkASSERT(lastWeight - dualPlaneBitLoc < 31);
1721 int fullCEM = static_cast<int>(read_astc_bits(fBlock, dualPlaneBitLoc, lastWeight));
1723 // Attach the config at the end of the weight grid to the CEM values
1724 // in the beginning of the block.
1725 fullCEM = (fullCEM << 6) | lowCEM;
1727 // Ignore the two least significant bits, since those are our baseCEM above.
1728 fullCEM = fullCEM >> 2;
1730 int C[kMaxPartitions]; // Next, decode C and M from the spec (Table C.2.12)
1731 for (int i = 0; i < this->numPartitions(); ++i) {
1733 fullCEM = fullCEM >> 1;
1736 int M[kMaxPartitions];
1737 for (int i = 0; i < this->numPartitions(); ++i) {
1738 M[i] = fullCEM & 0x3;
1739 fullCEM = fullCEM >> 2;
1742 // Construct our CEMs..
1743 SkASSERT(baseCEM > 0);
1744 for (int i = 0; i < this->numPartitions(); ++i) {
1745 int cem = (baseCEM - 1) * 4;
1746 cem += (0 == C[i])? 0 : 4;
1750 fCEM[i] = static_cast<ColorEndpointMode>(cem);
1753 // Finally, if we have dual plane mode, then read the plane selector.
1754 this->decodeDualPlane(dualPlaneBitLoc);
1757 // Decodes the block mode. This function determines whether or not we use
1758 // dual plane encoding, the size of the texel weight grid, and the number of
1759 // bits, trits and quints that are used to encode it. For more information,
1760 // see section C.2.10 of the ASTC spec.
1762 // For 2D blocks, the Block Mode field is laid out as follows:
1764 // -------------------------------------------------------------------------
1765 // 10 9 8 7 6 5 4 3 2 1 0 Width Height Notes
1766 // -------------------------------------------------------------------------
1767 // D H B A R0 0 0 R2 R1 B+4 A+2
1768 // D H B A R0 0 1 R2 R1 B+8 A+2
1769 // D H B A R0 1 0 R2 R1 A+2 B+8
1770 // D H 0 B A R0 1 1 R2 R1 A+2 B+6
1771 // D H 1 B A R0 1 1 R2 R1 B+2 A+2
1772 // D H 0 0 A R0 R2 R1 0 0 12 A+2
1773 // D H 0 1 A R0 R2 R1 0 0 A+2 12
1774 // D H 1 1 0 0 R0 R2 R1 0 0 6 10
1775 // D H 1 1 0 1 R0 R2 R1 0 0 10 6
1776 // B 1 0 A R0 R2 R1 0 0 A+6 B+6 D=0, H=0
1777 // x x 1 1 1 1 1 1 1 0 0 - - Void-extent
1778 // x x 1 1 1 x x x x 0 0 - - Reserved*
1779 // x x x x x x x 0 0 0 0 - - Reserved
1780 // -------------------------------------------------------------------------
1782 // D - dual plane enabled
1783 // H, R - used to determine the number of bits/trits/quints in texel weight encoding
1784 // R is a three bit value whose LSB is R0 and MSB is R1
1785 // Width, Height - dimensions of the texel weight grid (determined by A and B)
1787 void decodeBlockMode() {
1788 const int blockMode = static_cast<int>(read_astc_bits(fBlock, 0, 11));
1790 // Check for special void extent encoding
1791 fVoidExtent = (blockMode & 0x1FF) == 0x1FC;
1793 // Check for reserved block modes
1794 fError = ((blockMode & 0x1C3) == 0x1C0) || ((blockMode & 0xF) == 0);
1796 // Neither reserved nor void-extent, decode as usual
1797 // This code corresponds to table C.2.8 of the ASTC spec
1798 bool highPrecision = false;
1800 if ((blockMode & 0x3) == 0) {
1801 R = ((0xC & blockMode) >> 1) | ((0x10 & blockMode) >> 4);
1802 const int bitsSevenAndEight = (blockMode & 0x180) >> 7;
1803 SkASSERT(0 <= bitsSevenAndEight && bitsSevenAndEight < 4);
1805 const int A = (blockMode >> 5) & 0x3;
1806 const int B = (blockMode >> 9) & 0x3;
1808 fDualPlaneEnabled = (blockMode >> 10) & 0x1;
1809 highPrecision = (blockMode >> 9) & 0x1;
1811 switch (bitsSevenAndEight) {
1815 fWeightDimY = A + 2;
1819 fWeightDimX = A + 2;
1824 fWeightDimX = A + 6;
1825 fWeightDimY = B + 6;
1826 fDualPlaneEnabled = false;
1827 highPrecision = false;
1840 } else { // (blockMode & 0x3) != 0
1841 R = ((blockMode & 0x3) << 1) | ((blockMode & 0x10) >> 4);
1843 const int bitsTwoAndThree = (blockMode >> 2) & 0x3;
1844 SkASSERT(0 <= bitsTwoAndThree && bitsTwoAndThree < 4);
1846 const int A = (blockMode >> 5) & 0x3;
1847 const int B = (blockMode >> 7) & 0x3;
1849 fDualPlaneEnabled = (blockMode >> 10) & 0x1;
1850 highPrecision = (blockMode >> 9) & 0x1;
1852 switch (bitsTwoAndThree) {
1854 fWeightDimX = B + 4;
1855 fWeightDimY = A + 2;
1858 fWeightDimX = B + 8;
1859 fWeightDimY = A + 2;
1862 fWeightDimX = A + 2;
1863 fWeightDimY = B + 8;
1866 if ((B & 0x2) == 0) {
1867 fWeightDimX = A + 2;
1868 fWeightDimY = (B & 1) + 6;
1870 fWeightDimX = (B & 1) + 2;
1871 fWeightDimY = A + 2;
1877 // We should have set the values of R and highPrecision
1878 // from decoding the block mode, these are used to determine
1879 // the proper dimensions of our weight grid.
1880 if ((R & 0x6) == 0) {
1883 static const int kBitAllocationTable[2][6][3] = {
1902 fWeightBits = kBitAllocationTable[highPrecision][R - 2][0];
1903 fWeightTrits = kBitAllocationTable[highPrecision][R - 2][1];
1904 fWeightQuints = kBitAllocationTable[highPrecision][R - 2][2];
1909 // Reads an ASTC block from the given pointer.
1910 static inline void read_astc_block(ASTCDecompressionData *dst, const uint8_t* src) {
1911 const uint64_t* qword = reinterpret_cast<const uint64_t*>(src);
1912 dst->fBlock.fLow = SkEndian_SwapLE64(qword[0]);
1913 dst->fBlock.fHigh = SkEndian_SwapLE64(qword[1]);
1917 // Take a known void-extent block, and write out the values as a constant color.
1918 static void decompress_void_extent(uint8_t* dst, int dstRowBytes,
1919 const ASTCDecompressionData &data) {
1920 // The top 64 bits contain 4 16-bit RGBA values.
1921 int a = (static_cast<int>(read_astc_bits(data.fBlock, 112, 128)) + 255) >> 8;
1922 int b = (static_cast<int>(read_astc_bits(data.fBlock, 96, 112)) + 255) >> 8;
1923 int g = (static_cast<int>(read_astc_bits(data.fBlock, 80, 96)) + 255) >> 8;
1924 int r = (static_cast<int>(read_astc_bits(data.fBlock, 64, 80)) + 255) >> 8;
1926 write_constant_color(dst, data.fDimX, data.fDimY, dstRowBytes, SkColorSetARGB(a, r, g, b));
1929 // Decompresses a single ASTC block. It's assumed that data.fDimX and data.fDimY are
1930 // set and that the block has already been decoded (i.e. data.decode() has been called)
1931 static void decompress_astc_block(uint8_t* dst, int dstRowBytes,
1932 const ASTCDecompressionData &data) {
1934 write_error_color(dst, data.fDimX, data.fDimY, dstRowBytes);
1938 if (data.fVoidExtent) {
1939 decompress_void_extent(dst, dstRowBytes, data);
1943 // According to the spec, any more than 64 values is illegal. (C.2.24)
1944 static const int kMaxTexelValues = 64;
1946 // Decode the texel weights.
1947 int texelValues[kMaxTexelValues];
1948 bool success = decode_integer_sequence(
1949 texelValues, kMaxTexelValues, data.numWeights(),
1950 // texel data goes to the end of the 128 bit block.
1951 data.fBlock, 128, 128 - data.numWeightBits(), false,
1952 data.fWeightBits, data.fWeightTrits, data.fWeightQuints);
1955 write_error_color(dst, data.fDimX, data.fDimY, dstRowBytes);
1959 // Decode the color endpoints
1960 int colorBits, colorTrits, colorQuints;
1961 if (!data.getColorValueEncoding(&colorBits, &colorTrits, &colorQuints)) {
1962 write_error_color(dst, data.fDimX, data.fDimY, dstRowBytes);
1966 // According to the spec, any more than 18 color values is illegal. (C.2.24)
1967 static const int kMaxColorValues = 18;
1969 int colorValues[kMaxColorValues];
1970 success = decode_integer_sequence(
1971 colorValues, kMaxColorValues, data.numColorValues(),
1972 data.fBlock, data.fColorStartBit, data.fColorEndBit, true,
1973 colorBits, colorTrits, colorQuints);
1976 write_error_color(dst, data.fDimX, data.fDimY, dstRowBytes);
1980 // Unquantize the color values after they've been decoded.
1981 unquantize_colors(colorValues, data.numColorValues(), colorBits, colorTrits, colorQuints);
1983 // Decode the colors into the appropriate endpoints.
1984 SkColor endpoints[4][2];
1985 data.colorEndpoints(endpoints, colorValues);
1987 // Do texel infill and decode the texel values.
1988 int texelWeights[2][12][12];
1989 data.texelWeights(texelWeights, texelValues);
1991 // Write the texels by interpolating them based on the information
1992 // stored in the block.
1993 dst += data.fDimY * dstRowBytes;
1994 for (int y = 0; y < data.fDimY; ++y) {
1996 SkColor* colorPtr = reinterpret_cast<SkColor*>(dst);
1997 for (int x = 0; x < data.fDimX; ++x) {
1998 colorPtr[x] = data.getTexel(endpoints, texelWeights, x, y);
2003 ////////////////////////////////////////////////////////////////////////////////
2005 // ASTC Comrpession Struct
2007 ////////////////////////////////////////////////////////////////////////////////
2009 // This is the type passed as the CompressorType argument of the compressed
2010 // blitter for the ASTC format. The static functions required to be in this
2011 // struct are documented in SkTextureCompressor_Blitter.h
2012 struct CompressorASTC {
2013 static inline void CompressA8Vertical(uint8_t* dst, const uint8_t* src) {
2014 compress_a8_astc_block<GetAlphaTranspose>(&dst, src, 12);
2017 static inline void CompressA8Horizontal(uint8_t* dst, const uint8_t* src,
2019 compress_a8_astc_block<GetAlpha>(&dst, src, srcRowBytes);
2022 #if PEDANTIC_BLIT_RECT
2023 static inline void UpdateBlock(uint8_t* dst, const uint8_t* src, int srcRowBytes,
2024 const uint8_t* mask) {
2026 // This is kind of difficult for ASTC because the weight values are calculated
2027 // as an average of the actual weights. The best we can do is decompress the
2028 // weights and recalculate them based on the new texel values. This should
2029 // be "not too bad" since we know that anytime we hit this function, we're
2030 // compressing 12x12 block dimension alpha-only, and we know the layout
2032 SkFAIL("Implement me!");
2037 ////////////////////////////////////////////////////////////////////////////////
2039 namespace SkTextureCompressor {
2041 bool CompressA8To12x12ASTC(uint8_t* dst, const uint8_t* src,
2042 int width, int height, int rowBytes) {
2043 if (width < 0 || ((width % 12) != 0) || height < 0 || ((height % 12) != 0)) {
2047 uint8_t** dstPtr = &dst;
2048 for (int y = 0; y < height; y += 12) {
2049 for (int x = 0; x < width; x += 12) {
2050 compress_a8_astc_block<GetAlpha>(dstPtr, src + y*rowBytes + x, rowBytes);
2057 SkBlitter* CreateASTCBlitter(int width, int height, void* outputBuffer,
2058 SkTBlitterAllocator* allocator) {
2059 if ((width % 12) != 0 || (height % 12) != 0) {
2063 // Memset the output buffer to an encoding that decodes to zero. We must do this
2064 // in order to avoid having uninitialized values in the buffer if the blitter
2065 // decides not to write certain scanlines (and skip entire rows of blocks).
2066 // In the case of ASTC, if everything index is zero, then the interpolated value
2067 // will decode to zero provided we have the right header. We use the encoding
2068 // from recognizing all zero blocks from above.
2069 const int nBlocks = (width * height / 144);
2070 uint8_t *dst = reinterpret_cast<uint8_t *>(outputBuffer);
2071 for (int i = 0; i < nBlocks; ++i) {
2072 send_packing(&dst, SkTEndian_SwapLE64(0x0000000001FE000173ULL), 0);
2075 return allocator->createT<
2076 SkTCompressedAlphaBlitter<12, 16, CompressorASTC>, int, int, void* >
2077 (width, height, outputBuffer);
2080 void DecompressASTC(uint8_t* dst, int dstRowBytes, const uint8_t* src,
2081 int width, int height, int blockDimX, int blockDimY) {
2082 // ASTC is encoded in what they call "raster order", so that the first
2083 // block is the bottom-left block in the image, and the first pixel
2084 // is the bottom-left pixel of the image
2085 dst += height * dstRowBytes;
2087 ASTCDecompressionData data(blockDimX, blockDimY);
2088 for (int y = 0; y < height; y += blockDimY) {
2089 dst -= blockDimY * dstRowBytes;
2090 SkColor *colorPtr = reinterpret_cast<SkColor*>(dst);
2091 for (int x = 0; x < width; x += blockDimX) {
2092 read_astc_block(&data, src);
2093 decompress_astc_block(reinterpret_cast<uint8_t*>(colorPtr + x), dstRowBytes, data);
2095 // ASTC encoded blocks are 16 bytes (128 bits) large.
2101 } // SkTextureCompressor