Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(181)

Side by Side Diff: src/utils/SkTextureCompressor_ASTC.cpp

Issue 417933005: Add preliminary ASTC encoder (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Optimize out constant colors Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/utils/SkTextureCompressor_ASTC.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /*
2 * Copyright 2014 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "SkTextureCompressor_ASTC.h"
9
10 #include "SkBlitter.h"
11 #include "SkEndian.h"
12
13 // This table contains the weight values for each texel. This is used in determi ning
14 // how to convert a 12x12 grid of alpha values into a 6x5 grid of index values. Since
15 // we have a 6x5 grid, that gives 30 values that we have to compute. For each in dex,
16 // we store up to 20 different triplets of values. In order the triplets are:
17 // weight, texel-x, texel-y
18 // The weight value corresponds to the amount that this index contributes to the final
19 // index value of the given texel. Hence, we need to reconstruct the 6x5 index g rid
20 // from their relative contribution to the 12x12 texel grid.
21 //
22 // The algorithm is something like this:
23 // foreach index i:
24 // total-weight = 0;
25 // total-alpha = 0;
26 // for w = 1 to 20:
27 // weight = table[i][w*3];
28 // texel-x = table[i][w*3 + 1];
29 // texel-y = table[i][w*3 + 2];
30 // if weight >= 0:
31 // total-weight += weight;
32 // total-alpha += weight * alphas[texel-x][texel-y];
33 //
34 // total-alpha /= total-weight;
35 // index = top three bits of total-alpha
36 //
37 // If the associated index does not contribute to 20 different texels (e.g. it's in
38 // a corner), then the extra texels are stored with -1's in the table.
39
40 static const int k6x5To12x12Table[30][60] = {
41 { 16, 0, 0, 9, 1, 0, 1, 2, 0, 10, 0, 1, 6, 1, 1, 1, 2, 1, 4, 0, 2, 2,
42 1, 2, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0,
43 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0}, // n = 20
44 { 7, 1, 0, 15, 2, 0, 10, 3, 0, 3, 4, 0, 4, 1, 1, 9, 2, 1, 6, 3, 1, 2,
45 4, 1, 2, 1, 2, 4, 2, 2, 3, 3, 2, 1, 4, 2, -1, 0, 0, -1, 0, 0, -1, 0,
46 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0}, // n = 20
47 { 6, 3, 0, 13, 4, 0, 12, 5, 0, 4, 6, 0, 4, 3, 1, 8, 4, 1, 8, 5, 1, 3,
48 6, 1, 1, 3, 2, 3, 4, 2, 3, 5, 2, 1, 6, 2, -1, 0, 0, -1, 0, 0, -1, 0,
49 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0}, // n = 20
50 { 4, 5, 0, 12, 6, 0, 13, 7, 0, 6, 8, 0, 2, 5, 1, 7, 6, 1, 8, 7, 1, 4,
51 8, 1, 1, 5, 2, 3, 6, 2, 3, 7, 2, 2, 8, 2, -1, 0, 0, -1, 0, 0, -1, 0,
52 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0}, // n = 20
53 { 3, 7, 0, 10, 8, 0, 15, 9, 0, 7, 10, 0, 2, 7, 1, 6, 8, 1, 9, 9, 1, 4,
54 10, 1, 1, 7, 2, 2, 8, 2, 4, 9, 2, 2, 10, 2, -1, 0, 0, -1, 0, 0, -1, 0,
55 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0}, // n = 20
56 { 1, 9, 0, 9, 10, 0, 16, 11, 0, 1, 9, 1, 6, 10, 1, 10, 11, 1, 2, 10, 2, 4,
57 11, 2, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0,
58 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0}, // n = 20
59 { 6, 0, 1, 3, 1, 1, 12, 0, 2, 7, 1, 2, 1, 2, 2, 15, 0, 3, 8, 1, 3, 1,
60 2, 3, 9, 0, 4, 5, 1, 4, 1, 2, 4, 3, 0, 5, 2, 1, 5, -1, 0, 0, -1, 0,
61 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0}, // n = 20
62 { 3, 1, 1, 6, 2, 1, 4, 3, 1, 1, 4, 1, 5, 1, 2, 11, 2, 2, 7, 3, 2, 2,
63 4, 2, 7, 1, 3, 14, 2, 3, 9, 3, 3, 3, 4, 3, 4, 1, 4, 8, 2, 4, 6, 3,
64 4, 2, 4, 4, 1, 1, 5, 3, 2, 5, 2, 3, 5, 1, 4, 5}, // n = 20
65 { 2, 3, 1, 5, 4, 1, 4, 5, 1, 1, 6, 1, 5, 3, 2, 10, 4, 2, 9, 5, 2, 3,
66 6, 2, 6, 3, 3, 12, 4, 3, 11, 5, 3, 4, 6, 3, 3, 3, 4, 7, 4, 4, 7, 5,
67 4, 2, 6, 4, 1, 3, 5, 2, 4, 5, 2, 5, 5, 1, 6, 5}, // n = 20
68 { 2, 5, 1, 5, 6, 1, 5, 7, 1, 2, 8, 1, 3, 5, 2, 9, 6, 2, 10, 7, 2, 4,
69 8, 2, 4, 5, 3, 11, 6, 3, 12, 7, 3, 6, 8, 3, 2, 5, 4, 7, 6, 4, 7, 7,
70 4, 3, 8, 4, 1, 5, 5, 2, 6, 5, 2, 7, 5, 1, 8, 5}, // n = 20
71 { 1, 7, 1, 4, 8, 1, 6, 9, 1, 3, 10, 1, 2, 7, 2, 8, 8, 2, 11, 9, 2, 5,
72 10, 2, 3, 7, 3, 9, 8, 3, 14, 9, 3, 7, 10, 3, 2, 7, 4, 6, 8, 4, 8, 9,
73 4, 4, 10, 4, 1, 7, 5, 2, 8, 5, 3, 9, 5, 1, 10, 5}, // n = 20
74 { 3, 10, 1, 6, 11, 1, 1, 9, 2, 7, 10, 2, 12, 11, 2, 1, 9, 3, 8, 10, 3, 15,
75 11, 3, 1, 9, 4, 5, 10, 4, 9, 11, 4, 2, 10, 5, 3, 11, 5, -1, 0, 0, -1, 0,
76 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0}, // n = 20
77 { 1, 0, 3, 1, 1, 3, 7, 0, 4, 4, 1, 4, 13, 0, 5, 7, 1, 5, 1, 2, 5, 13,
78 0, 6, 7, 1, 6, 1, 2, 6, 7, 0, 7, 4, 1, 7, 1, 0, 8, 1, 1, 8, -1, 0,
79 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0}, // n = 20
80 { 1, 2, 3, 1, 3, 3, 3, 1, 4, 7, 2, 4, 4, 3, 4, 1, 4, 4, 6, 1, 5, 12,
81 2, 5, 8, 3, 5, 2, 4, 5, 6, 1, 6, 12, 2, 6, 8, 3, 6, 2, 4, 6, 3, 1,
82 7, 7, 2, 7, 4, 3, 7, 1, 4, 7, 1, 2, 8, 1, 3, 8}, // n = 20
83 { 1, 4, 3, 1, 5, 3, 3, 3, 4, 6, 4, 4, 5, 5, 4, 2, 6, 4, 5, 3, 5, 11,
84 4, 5, 10, 5, 5, 3, 6, 5, 5, 3, 6, 11, 4, 6, 10, 5, 6, 3, 6, 6, 3, 3,
85 7, 6, 4, 7, 5, 5, 7, 2, 6, 7, 1, 4, 8, 1, 5, 8}, // n = 20
86 { 1, 6, 3, 1, 7, 3, 2, 5, 4, 5, 6, 4, 6, 7, 4, 3, 8, 4, 3, 5, 5, 10,
87 6, 5, 11, 7, 5, 5, 8, 5, 3, 5, 6, 10, 6, 6, 11, 7, 6, 5, 8, 6, 2, 5,
88 7, 5, 6, 7, 6, 7, 7, 3, 8, 7, 1, 6, 8, 1, 7, 8}, // n = 20
89 { 1, 8, 3, 1, 9, 3, 1, 7, 4, 4, 8, 4, 7, 9, 4, 3, 10, 4, 2, 7, 5, 8,
90 8, 5, 12, 9, 5, 6, 10, 5, 2, 7, 6, 8, 8, 6, 12, 9, 6, 6, 10, 6, 1, 7,
91 7, 4, 8, 7, 7, 9, 7, 3, 10, 7, 1, 8, 8, 1, 9, 8}, // n = 20
92 { 1, 10, 3, 1, 11, 3, 4, 10, 4, 7, 11, 4, 1, 9, 5, 7, 10, 5, 13, 11, 5, 1,
93 9, 6, 7, 10, 6, 13, 11, 6, 4, 10, 7, 7, 11, 7, 1, 10, 8, 1, 11, 8, -1, 0,
94 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0}, // n = 20
95 { 3, 0, 6, 2, 1, 6, 9, 0, 7, 5, 1, 7, 1, 2, 7, 15, 0, 8, 8, 1, 8, 1,
96 2, 8, 12, 0, 9, 7, 1, 9, 1, 2, 9, 6, 0, 10, 3, 1, 10, -1, 0, 0, -1, 0,
97 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0}, // n = 20
98 { 1, 1, 6, 3, 2, 6, 2, 3, 6, 1, 4, 6, 4, 1, 7, 8, 2, 7, 6, 3, 7, 2,
99 4, 7, 7, 1, 8, 14, 2, 8, 9, 3, 8, 3, 4, 8, 5, 1, 9, 11, 2, 9, 8, 3,
100 9, 2, 4, 9, 3, 1, 10, 6, 2, 10, 4, 3, 10, 1, 4, 10}, // n = 20
101 { 1, 3, 6, 2, 4, 6, 2, 5, 6, 1, 6, 6, 3, 3, 7, 7, 4, 7, 7, 5, 7, 2,
102 6, 7, 6, 3, 8, 12, 4, 8, 11, 5, 8, 4, 6, 8, 4, 3, 9, 10, 4, 9, 9, 5,
103 9, 3, 6, 9, 2, 3, 10, 5, 4, 10, 5, 5, 10, 2, 6, 10}, // n = 20
104 { 1, 5, 6, 2, 6, 6, 2, 7, 6, 1, 8, 6, 2, 5, 7, 7, 6, 7, 7, 7, 7, 3,
105 8, 7, 4, 5, 8, 11, 6, 8, 12, 7, 8, 6, 8, 8, 3, 5, 9, 9, 6, 9, 10, 7,
106 9, 5, 8, 9, 1, 5, 10, 4, 6, 10, 5, 7, 10, 2, 8, 10}, // n = 20
107 { 1, 7, 6, 2, 8, 6, 3, 9, 6, 1, 10, 6, 2, 7, 7, 6, 8, 7, 8, 9, 7, 4,
108 10, 7, 3, 7, 8, 9, 8, 8, 14, 9, 8, 7, 10, 8, 2, 7, 9, 7, 8, 9, 11, 9,
109 9, 5, 10, 9, 1, 7, 10, 4, 8, 10, 6, 9, 10, 3, 10, 10}, // n = 20
110 { 2, 10, 6, 3, 11, 6, 1, 9, 7, 5, 10, 7, 9, 11, 7, 1, 9, 8, 8, 10, 8, 15,
111 11, 8, 1, 9, 9, 7, 10, 9, 12, 11, 9, 3, 10, 10, 6, 11, 10, -1, 0, 0, -1, 0,
112 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0}, // n = 20
113 { 4, 0, 9, 2, 1, 9, 10, 0, 10, 6, 1, 10, 1, 2, 10, 16, 0, 11, 9, 1, 11, 1,
114 2, 11, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0,
115 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0}, // n = 20
116 { 2, 1, 9, 4, 2, 9, 2, 3, 9, 1, 4, 9, 4, 1, 10, 9, 2, 10, 6, 3, 10, 2,
117 4, 10, 7, 1, 11, 15, 2, 11, 10, 3, 11, 3, 4, 11, -1, 0, 0, -1, 0, 0, -1, 0,
118 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0}, // n = 20
119 { 2, 3, 9, 3, 4, 9, 3, 5, 9, 1, 6, 9, 4, 3, 10, 8, 4, 10, 7, 5, 10, 2,
120 6, 10, 6, 3, 11, 13, 4, 11, 12, 5, 11, 4, 6, 11, -1, 0, 0, -1, 0, 0, -1, 0,
121 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0}, // n = 20
122 { 1, 5, 9, 3, 6, 9, 3, 7, 9, 1, 8, 9, 3, 5, 10, 8, 6, 10, 8, 7, 10, 4,
123 8, 10, 4, 5, 11, 12, 6, 11, 13, 7, 11, 6, 8, 11, -1, 0, 0, -1, 0, 0, -1, 0,
124 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0}, // n = 20
125 { 1, 7, 9, 3, 8, 9, 4, 9, 9, 2, 10, 9, 2, 7, 10, 6, 8, 10, 9, 9, 10, 4,
126 10, 10, 3, 7, 11, 10, 8, 11, 15, 9, 11, 7, 10, 11, -1, 0, 0, -1, 0, 0, -1, 0,
127 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0}, // n = 20
128 { 2, 10, 9, 4, 11, 9, 1, 9, 10, 6, 10, 10, 10, 11, 10, 1, 9, 11, 9, 10, 11, 16,
129 11, 11, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0,
130 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0} // n = 20
131 };
132
133 // Returns the alpha value of a texel at position (x, y) from src.
134 // (x, y) are assumed to be in the range [0, 12).
135 uint8_t get_alpha(const uint8_t *src, int rowBytes, int x, int y) {
136 SkASSERT(x >= 0 && x < 12);
137 SkASSERT(y >= 0 && y < 12);
138 SkASSERT(rowBytes >= 12);
139 return *(src + y*rowBytes + x);
140 }
141
142 // Output the 16 bytes stored in top and bottom and advance the pointer. The byt es
143 // are stored as the integers are represented in memory, so they should be swapp ed
144 // if necessary.
145 static inline void send_packing(uint8_t** dst, const uint64_t top, const uint64_ t bottom) {
146 uint64_t* dst64 = reinterpret_cast<uint64_t*>(*dst);
147 dst64[0] = top;
148 dst64[1] = bottom;
149 *dst += 16;
150 }
151
152 // Compresses an ASTC block, by looking up the proper contributions from
153 // k6x5To12x12Table and computing an index from the associated values.
154 static void compress_a8_astc_block(uint8_t** dst, const uint8_t* src, int rowByt es) {
155 // Check for single color
156 bool constant = true;
157 const uint32_t firstInt = *(reinterpret_cast<const uint32_t*>(src));
158 for (int i = 0; i < 12; ++i) {
159 const uint32_t *rowInt = reinterpret_cast<const uint32_t *>(src + i*rowB ytes);
160 constant = constant && (rowInt[0] == firstInt);
161 constant = constant && (rowInt[1] == firstInt);
162 constant = constant && (rowInt[2] == firstInt);
163 }
164
165 if (constant) {
166 if (0 == firstInt) {
167 // All of the indices are set to zero, and the colors are
168 // v0 = 0, v1 = 255, so everything will be transparent.
169 send_packing(dst, SkTEndian_SwapLE64(0x0000000001FE000173ULL), 0);
170 return;
171 } else if (0xFFFFFFFF == firstInt) {
172 // All of the indices are set to zero, and the colors are
173 // v0 = 255, v1 = 0, so everything will be opaque.
174 send_packing(dst, SkTEndian_SwapLE64(0x000000000001FE0173ULL), 0);
175 return;
176 }
177 }
178
179 uint8_t indices[30]; // 6x5 index grid
180 for (int idx = 0; idx < 30; ++idx) {
181 int weightTot = 0;
182 int alphaTot = 0;
183 for (int w = 0; w < 20; ++w) {
184 const int weight = k6x5To12x12Table[idx][w*3];
robertphillips 2014/07/25 13:06:58 Can we move the x & y lookups inside the "if (weig
krajcevski 2014/07/25 14:20:14 Done.
185 const int x = k6x5To12x12Table[idx][w*3 + 1];
186 const int y = k6x5To12x12Table[idx][w*3 + 2];
187 if (weight > 0) {
188 weightTot += weight;
189 alphaTot += weight * get_alpha(src, rowBytes, x, y);
190 }
191 }
192
193 indices[idx] = (alphaTot + (weightTot/2)) / weightTot;
194 }
195
196 // Pack indices... The ASTC block layout is fairly complicated. An extensive
197 // description can be found here:
198 // https://www.opengl.org/registry/specs/KHR/texture_compression_astc_hdr.tx t
199 //
200 // Here is a summary of the options that we've chosen:
201 // 1. Block mode: 0b00101110011
202 // - 6x5 texel grid
203 // - Single plane
204 // - Low-precision index values
205 // - Index range 0-7 (three bits per index)
206 // 2. Partitions: 0b00
207 // - One partition
208 // 3. Color Endpoint Mode: 0b0000
209 // - Direct luminance -- e0=(v0,v0,v0,0xFF); e1=(v1,v1,v1,0xFF);
210 // 4. 8-bit endpoints:
211 // v0 = 0, v1 = 255
212 //
213 // The rest of the block contains the 30 index values from before, which
214 // are currently stored in the indices variable.
215
216 uint64_t top = 0x0000000001FE000173ULL;
217 uint64_t bottom = 0;
218
219 for (int idx = 0; idx <= 20; ++idx) {
220 const uint8_t index = (indices[idx] & 0xE0) >> 5;
221 bottom |= static_cast<uint64_t>(index) << (61-(idx*3));
222 }
223
224 // index 21 straddles top and bottom
225 {
226 const uint8_t index = (indices[21] & 0xE0) >> 5;
227 bottom |= index & 1;
228 top |= static_cast<uint64_t>((index >> 2) | (index & 2)) << 62;
229 }
230
231 for (int idx = 22; idx < 30; ++idx) {
232 const uint8_t index = (indices[idx] & 0xE0) >> 5;
233 top |= static_cast<uint64_t>(index) << (59-(idx-22)*3);
234 }
235
236 // Reverse each 3-bit index since indices are read in reverse order...
237 uint64_t t = (bottom ^ (bottom >> 2)) & 0x2492492492492492ULL;
238 bottom = bottom ^ t ^ (t << 2);
239
240 t = (top ^ (top >> 2)) & 0x0924924000000000ULL;
241 top = top ^ t ^ (t << 2);
242
243 send_packing(dst, SkEndian_SwapLE64(top), SkEndian_SwapLE64(bottom));
244 }
245
246 ////////////////////////////////////////////////////////////////////////////////
247
248 namespace SkTextureCompressor {
249
250 bool CompressA8To12x12ASTC(uint8_t* dst, const uint8_t* src, int width, int heig ht, int rowBytes) {
251 if (width < 0 || ((width % 12) != 0) || height < 0 || ((height % 12) != 0)) {
252 return false;
253 }
254
255 uint8_t** dstPtr = &dst;
robertphillips 2014/07/25 13:06:58 j,i -> y,x ?
krajcevski 2014/07/25 14:20:14 Done.
256 for (int j = 0; j < height; j+=12) {
257 for (int i = 0; i < width; i+=12) {
258 compress_a8_astc_block(dstPtr, src + j*rowBytes + i, rowBytes);
259 }
260 }
261
262 return true;
263 }
264
265 SkBlitter* CreateASTCBlitter(int width, int height, void* outputBuffer) {
266 // TODO (krajcevski)
267 return NULL;
268 }
269
270 } // SkTextureCompressor
OLDNEW
« no previous file with comments | « src/utils/SkTextureCompressor_ASTC.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698