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

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

Issue 358973004: Add a preliminary R11 EAC compressor (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Make everything uint16_t Created 6 years, 5 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.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
1 /* 1 /*
2 * Copyright 2014 Google Inc. 2 * Copyright 2014 Google Inc.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license that can be 4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file. 5 * found in the LICENSE file.
6 */ 6 */
7 7
8 #include "SkTextureCompressor.h" 8 #include "SkTextureCompressor.h"
9 9
10 #include "SkBitmap.h" 10 #include "SkBitmap.h"
11 #include "SkData.h" 11 #include "SkData.h"
12 #include "SkEndian.h" 12 #include "SkEndian.h"
13 13
14 //////////////////////////////////////////////////////////////////////////////// 14 ////////////////////////////////////////////////////////////////////////////////
15 // 15 //
16 // Utility Functions 16 // Utility Functions
17 // 17 //
18 //////////////////////////////////////////////////////////////////////////////// 18 ////////////////////////////////////////////////////////////////////////////////
19 19
20 // Absolute difference between two values. More correct than SkTAbs(a - b) 20 // Absolute difference between two values. More correct than SkTAbs(a - b)
21 // because it works on unsigned values. 21 // because it works on unsigned values.
22 template <typename T> inline T abs_diff(const T &a, const T &b) { 22 template <typename T> inline T abs_diff(const T &a, const T &b) {
23 return (a > b) ? (a - b) : (b - a); 23 return (a > b) ? (a - b) : (b - a);
24 } 24 }
25 25
26 static bool is_extremal(uint8_t pixel) {
27 return 0 == pixel || 255 == pixel;
28 }
29
30 typedef uint64_t (*A84x4To64BitProc)(const uint8_t block[]);
31
32 // This function is used by both R11 EAC and LATC to compress 4x4 blocks
33 // of 8-bit alpha into 64-bit values that comprise the compressed data.
34 // For both formats, we need to make sure that the dimensions of the
35 // src pixels are divisible by 4, and copy 4x4 blocks one at a time
36 // for compression.
37 static bool compress_4x4_a8_to_64bit(uint8_t* dst, const uint8_t* src,
38 int width, int height, int rowBytes,
39 A84x4To64BitProc proc) {
40 // Make sure that our data is well-formed enough to be considered for compre ssion
41 if (0 == width || 0 == height || (width % 4) != 0 || (height % 4) != 0) {
42 return false;
43 }
44
45 int blocksX = width >> 2;
46 int blocksY = height >> 2;
47
48 uint8_t block[16];
49 uint64_t* encPtr = reinterpret_cast<uint64_t*>(dst);
50 for (int y = 0; y < blocksY; ++y) {
51 for (int x = 0; x < blocksX; ++x) {
52 // Load block
53 for (int k = 0; k < 4; ++k) {
54 memcpy(block + k*4, src + k*rowBytes + 4*x, 4);
55 }
56
57 // Compress it
58 *encPtr = proc(block);
59 ++encPtr;
60 }
61 src += 4 * rowBytes;
62 }
63
64 return true;
65 }
66
26 //////////////////////////////////////////////////////////////////////////////// 67 ////////////////////////////////////////////////////////////////////////////////
27 // 68 //
28 // LATC compressor 69 // LATC compressor
29 // 70 //
30 //////////////////////////////////////////////////////////////////////////////// 71 ////////////////////////////////////////////////////////////////////////////////
31 72
32 // LATC compressed texels down into square 4x4 blocks 73 // LATC compressed texels down into square 4x4 blocks
33 static const int kPaletteSize = 8; 74 static const int kLATCPaletteSize = 8;
34 static const int kLATCBlockSize = 4; 75 static const int kLATCBlockSize = 4;
35 static const int kPixelsPerBlock = kLATCBlockSize * kLATCBlockSize; 76 static const int kLATCPixelsPerBlock = kLATCBlockSize * kLATCBlockSize;
36 77
37 // Generates an LATC palette. LATC constructs 78 // Generates an LATC palette. LATC constructs
38 // a palette of eight colors from LUM0 and LUM1 using the algorithm: 79 // a palette of eight colors from LUM0 and LUM1 using the algorithm:
39 // 80 //
40 // LUM0, if lum0 > lum1 and code(x,y) == 0 81 // LUM0, if lum0 > lum1 and code(x,y) == 0
41 // LUM1, if lum0 > lum1 and code(x,y) == 1 82 // LUM1, if lum0 > lum1 and code(x,y) == 1
42 // (6*LUM0+ LUM1)/7, if lum0 > lum1 and code(x,y) == 2 83 // (6*LUM0+ LUM1)/7, if lum0 > lum1 and code(x,y) == 2
43 // (5*LUM0+2*LUM1)/7, if lum0 > lum1 and code(x,y) == 3 84 // (5*LUM0+2*LUM1)/7, if lum0 > lum1 and code(x,y) == 3
44 // (4*LUM0+3*LUM1)/7, if lum0 > lum1 and code(x,y) == 4 85 // (4*LUM0+3*LUM1)/7, if lum0 > lum1 and code(x,y) == 4
45 // (3*LUM0+4*LUM1)/7, if lum0 > lum1 and code(x,y) == 5 86 // (3*LUM0+4*LUM1)/7, if lum0 > lum1 and code(x,y) == 5
46 // (2*LUM0+5*LUM1)/7, if lum0 > lum1 and code(x,y) == 6 87 // (2*LUM0+5*LUM1)/7, if lum0 > lum1 and code(x,y) == 6
47 // ( LUM0+6*LUM1)/7, if lum0 > lum1 and code(x,y) == 7 88 // ( LUM0+6*LUM1)/7, if lum0 > lum1 and code(x,y) == 7
48 // 89 //
49 // LUM0, if lum0 <= lum1 and code(x,y) == 0 90 // LUM0, if lum0 <= lum1 and code(x,y) == 0
50 // LUM1, if lum0 <= lum1 and code(x,y) == 1 91 // LUM1, if lum0 <= lum1 and code(x,y) == 1
51 // (4*LUM0+ LUM1)/5, if lum0 <= lum1 and code(x,y) == 2 92 // (4*LUM0+ LUM1)/5, if lum0 <= lum1 and code(x,y) == 2
52 // (3*LUM0+2*LUM1)/5, if lum0 <= lum1 and code(x,y) == 3 93 // (3*LUM0+2*LUM1)/5, if lum0 <= lum1 and code(x,y) == 3
53 // (2*LUM0+3*LUM1)/5, if lum0 <= lum1 and code(x,y) == 4 94 // (2*LUM0+3*LUM1)/5, if lum0 <= lum1 and code(x,y) == 4
54 // ( LUM0+4*LUM1)/5, if lum0 <= lum1 and code(x,y) == 5 95 // ( LUM0+4*LUM1)/5, if lum0 <= lum1 and code(x,y) == 5
55 // 0, if lum0 <= lum1 and code(x,y) == 6 96 // 0, if lum0 <= lum1 and code(x,y) == 6
56 // 255, if lum0 <= lum1 and code(x,y) == 7 97 // 255, if lum0 <= lum1 and code(x,y) == 7
57 98
58 static void generate_palette(uint8_t palette[], uint8_t lum0, uint8_t lum1) { 99 static void generate_latc_palette(uint8_t palette[], uint8_t lum0, uint8_t lum1) {
59 palette[0] = lum0; 100 palette[0] = lum0;
60 palette[1] = lum1; 101 palette[1] = lum1;
61 if (lum0 > lum1) { 102 if (lum0 > lum1) {
62 for (int i = 1; i < 7; i++) { 103 for (int i = 1; i < 7; i++) {
63 palette[i+1] = ((7-i)*lum0 + i*lum1) / 7; 104 palette[i+1] = ((7-i)*lum0 + i*lum1) / 7;
64 } 105 }
65 } else { 106 } else {
66 for (int i = 1; i < 5; i++) { 107 for (int i = 1; i < 5; i++) {
67 palette[i+1] = ((5-i)*lum0 + i*lum1) / 5; 108 palette[i+1] = ((5-i)*lum0 + i*lum1) / 5;
68 } 109 }
69 palette[6] = 0; 110 palette[6] = 0;
70 palette[7] = 255; 111 palette[7] = 255;
71 } 112 }
72 } 113 }
73 114
74 static bool is_extremal(uint8_t pixel) {
75 return 0 == pixel || 255 == pixel;
76 }
77
78 // Compress a block by using the bounding box of the pixels. It is assumed that 115 // Compress a block by using the bounding box of the pixels. It is assumed that
79 // there are no extremal pixels in this block otherwise we would have used 116 // there are no extremal pixels in this block otherwise we would have used
80 // compressBlockBBIgnoreExtremal. 117 // compressBlockBBIgnoreExtremal.
81 static uint64_t compress_block_bb(const uint8_t pixels[]) { 118 static uint64_t compress_latc_block_bb(const uint8_t pixels[]) {
82 uint8_t minVal = 255; 119 uint8_t minVal = 255;
83 uint8_t maxVal = 0; 120 uint8_t maxVal = 0;
84 for (int i = 0; i < kPixelsPerBlock; ++i) { 121 for (int i = 0; i < kLATCPixelsPerBlock; ++i) {
85 minVal = SkTMin(pixels[i], minVal); 122 minVal = SkTMin(pixels[i], minVal);
86 maxVal = SkTMax(pixels[i], maxVal); 123 maxVal = SkTMax(pixels[i], maxVal);
87 } 124 }
88 125
89 SkASSERT(!is_extremal(minVal)); 126 SkASSERT(!is_extremal(minVal));
90 SkASSERT(!is_extremal(maxVal)); 127 SkASSERT(!is_extremal(maxVal));
91 128
92 uint8_t palette[kPaletteSize]; 129 uint8_t palette[kLATCPaletteSize];
93 generate_palette(palette, maxVal, minVal); 130 generate_latc_palette(palette, maxVal, minVal);
94 131
95 uint64_t indices = 0; 132 uint64_t indices = 0;
96 for (int i = kPixelsPerBlock - 1; i >= 0; --i) { 133 for (int i = kLATCPixelsPerBlock - 1; i >= 0; --i) {
97 134
98 // Find the best palette index 135 // Find the best palette index
99 uint8_t bestError = abs_diff(pixels[i], palette[0]); 136 uint8_t bestError = abs_diff(pixels[i], palette[0]);
100 uint8_t idx = 0; 137 uint8_t idx = 0;
101 for (int j = 1; j < kPaletteSize; ++j) { 138 for (int j = 1; j < kLATCPaletteSize; ++j) {
102 uint8_t error = abs_diff(pixels[i], palette[j]); 139 uint8_t error = abs_diff(pixels[i], palette[j]);
103 if (error < bestError) { 140 if (error < bestError) {
104 bestError = error; 141 bestError = error;
105 idx = j; 142 idx = j;
106 } 143 }
107 } 144 }
108 145
109 indices <<= 3; 146 indices <<= 3;
110 indices |= idx; 147 indices |= idx;
111 } 148 }
112 149
113 return 150 return
114 SkEndian_SwapLE64( 151 SkEndian_SwapLE64(
115 static_cast<uint64_t>(maxVal) | 152 static_cast<uint64_t>(maxVal) |
116 (static_cast<uint64_t>(minVal) << 8) | 153 (static_cast<uint64_t>(minVal) << 8) |
117 (indices << 16)); 154 (indices << 16));
118 } 155 }
119 156
120 // Compress a block by using the bounding box of the pixels without taking into 157 // Compress a block by using the bounding box of the pixels without taking into
121 // account the extremal values. The generated palette will contain extremal valu es 158 // account the extremal values. The generated palette will contain extremal valu es
122 // and fewer points along the line segment to interpolate. 159 // and fewer points along the line segment to interpolate.
123 static uint64_t compress_block_bb_ignore_extremal(const uint8_t pixels[]) { 160 static uint64_t compress_latc_block_bb_ignore_extremal(const uint8_t pixels[]) {
124 uint8_t minVal = 255; 161 uint8_t minVal = 255;
125 uint8_t maxVal = 0; 162 uint8_t maxVal = 0;
126 for (int i = 0; i < kPixelsPerBlock; ++i) { 163 for (int i = 0; i < kLATCPixelsPerBlock; ++i) {
127 if (is_extremal(pixels[i])) { 164 if (is_extremal(pixels[i])) {
128 continue; 165 continue;
129 } 166 }
130 167
131 minVal = SkTMin(pixels[i], minVal); 168 minVal = SkTMin(pixels[i], minVal);
132 maxVal = SkTMax(pixels[i], maxVal); 169 maxVal = SkTMax(pixels[i], maxVal);
133 } 170 }
134 171
135 SkASSERT(!is_extremal(minVal)); 172 SkASSERT(!is_extremal(minVal));
136 SkASSERT(!is_extremal(maxVal)); 173 SkASSERT(!is_extremal(maxVal));
137 174
138 uint8_t palette[kPaletteSize]; 175 uint8_t palette[kLATCPaletteSize];
139 generate_palette(palette, minVal, maxVal); 176 generate_latc_palette(palette, minVal, maxVal);
140 177
141 uint64_t indices = 0; 178 uint64_t indices = 0;
142 for (int i = kPixelsPerBlock - 1; i >= 0; --i) { 179 for (int i = kLATCPixelsPerBlock - 1; i >= 0; --i) {
143 180
144 // Find the best palette index 181 // Find the best palette index
145 uint8_t idx = 0; 182 uint8_t idx = 0;
146 if (is_extremal(pixels[i])) { 183 if (is_extremal(pixels[i])) {
147 if (0xFF == pixels[i]) { 184 if (0xFF == pixels[i]) {
148 idx = 7; 185 idx = 7;
149 } else if (0 == pixels[i]) { 186 } else if (0 == pixels[i]) {
150 idx = 6; 187 idx = 6;
151 } else { 188 } else {
152 SkFAIL("Pixel is extremal but not really?!"); 189 SkFAIL("Pixel is extremal but not really?!");
153 } 190 }
154 } else { 191 } else {
155 uint8_t bestError = abs_diff(pixels[i], palette[0]); 192 uint8_t bestError = abs_diff(pixels[i], palette[0]);
156 for (int j = 1; j < kPaletteSize - 2; ++j) { 193 for (int j = 1; j < kLATCPaletteSize - 2; ++j) {
157 uint8_t error = abs_diff(pixels[i], palette[j]); 194 uint8_t error = abs_diff(pixels[i], palette[j]);
158 if (error < bestError) { 195 if (error < bestError) {
159 bestError = error; 196 bestError = error;
160 idx = j; 197 idx = j;
161 } 198 }
162 } 199 }
163 } 200 }
164 201
165 indices <<= 3; 202 indices <<= 3;
166 indices |= idx; 203 indices |= idx;
167 } 204 }
168 205
169 return 206 return
170 SkEndian_SwapLE64( 207 SkEndian_SwapLE64(
171 static_cast<uint64_t>(minVal) | 208 static_cast<uint64_t>(minVal) |
172 (static_cast<uint64_t>(maxVal) << 8) | 209 (static_cast<uint64_t>(maxVal) << 8) |
173 (indices << 16)); 210 (indices << 16));
174 } 211 }
175 212
176 213
177 // Compress LATC block. Each 4x4 block of pixels is decompressed by LATC from tw o 214 // Compress LATC block. Each 4x4 block of pixels is decompressed by LATC from tw o
178 // values LUM0 and LUM1, and an index into the generated palette. Details of how 215 // values LUM0 and LUM1, and an index into the generated palette. Details of how
179 // the palette is generated can be found in the comments of generatePalette abov e. 216 // the palette is generated can be found in the comments of generatePalette abov e.
180 // 217 //
181 // We choose which palette type to use based on whether or not 'pixels' contains 218 // We choose which palette type to use based on whether or not 'pixels' contains
182 // any extremal values (0 or 255). If there are extremal values, then we use the 219 // any extremal values (0 or 255). If there are extremal values, then we use the
183 // palette that has the extremal values built in. Otherwise, we use the full bou nding 220 // palette that has the extremal values built in. Otherwise, we use the full bou nding
184 // box. 221 // box.
185 222
186 static uint64_t compress_block(const uint8_t pixels[]) { 223 static uint64_t compress_latc_block(const uint8_t pixels[]) {
187 // Collect unique pixels 224 // Collect unique pixels
188 int nUniquePixels = 0; 225 int nUniquePixels = 0;
189 uint8_t uniquePixels[kPixelsPerBlock]; 226 uint8_t uniquePixels[kLATCPixelsPerBlock];
190 for (int i = 0; i < kPixelsPerBlock; ++i) { 227 for (int i = 0; i < kLATCPixelsPerBlock; ++i) {
191 bool foundPixel = false; 228 bool foundPixel = false;
192 for (int j = 0; j < nUniquePixels; ++j) { 229 for (int j = 0; j < nUniquePixels; ++j) {
193 foundPixel = foundPixel || uniquePixels[j] == pixels[i]; 230 foundPixel = foundPixel || uniquePixels[j] == pixels[i];
194 } 231 }
195 232
196 if (!foundPixel) { 233 if (!foundPixel) {
197 uniquePixels[nUniquePixels] = pixels[i]; 234 uniquePixels[nUniquePixels] = pixels[i];
198 ++nUniquePixels; 235 ++nUniquePixels;
199 } 236 }
200 } 237 }
201 238
202 // If there's only one unique pixel, then our compression is easy. 239 // If there's only one unique pixel, then our compression is easy.
203 if (1 == nUniquePixels) { 240 if (1 == nUniquePixels) {
204 return SkEndian_SwapLE64(pixels[0] | (pixels[0] << 8)); 241 return SkEndian_SwapLE64(pixels[0] | (pixels[0] << 8));
205 242
206 // Similarly, if there are only two unique pixels, then our compression is 243 // Similarly, if there are only two unique pixels, then our compression is
207 // easy again: place the pixels in the block header, and assign the indices 244 // easy again: place the pixels in the block header, and assign the indices
208 // with one or zero depending on which pixel they belong to. 245 // with one or zero depending on which pixel they belong to.
209 } else if (2 == nUniquePixels) { 246 } else if (2 == nUniquePixels) {
210 uint64_t outBlock = 0; 247 uint64_t outBlock = 0;
211 for (int i = kPixelsPerBlock - 1; i >= 0; --i) { 248 for (int i = kLATCPixelsPerBlock - 1; i >= 0; --i) {
212 int idx = 0; 249 int idx = 0;
213 if (pixels[i] == uniquePixels[1]) { 250 if (pixels[i] == uniquePixels[1]) {
214 idx = 1; 251 idx = 1;
215 } 252 }
216 253
217 outBlock <<= 3; 254 outBlock <<= 3;
218 outBlock |= idx; 255 outBlock |= idx;
219 } 256 }
220 outBlock <<= 16; 257 outBlock <<= 16;
221 outBlock |= (uniquePixels[0] | (uniquePixels[1] << 8)); 258 outBlock |= (uniquePixels[0] | (uniquePixels[1] << 8));
222 return SkEndian_SwapLE64(outBlock); 259 return SkEndian_SwapLE64(outBlock);
223 } 260 }
224 261
225 // Count non-maximal pixel values 262 // Count non-maximal pixel values
226 int nonExtremalPixels = 0; 263 int nonExtremalPixels = 0;
227 for (int i = 0; i < nUniquePixels; ++i) { 264 for (int i = 0; i < nUniquePixels; ++i) {
228 if (!is_extremal(uniquePixels[i])) { 265 if (!is_extremal(uniquePixels[i])) {
229 ++nonExtremalPixels; 266 ++nonExtremalPixels;
230 } 267 }
231 } 268 }
232 269
233 // If all the pixels are nonmaximal then compute the palette using 270 // If all the pixels are nonmaximal then compute the palette using
234 // the bounding box of all the pixels. 271 // the bounding box of all the pixels.
235 if (nonExtremalPixels == nUniquePixels) { 272 if (nonExtremalPixels == nUniquePixels) {
236 // This is really just for correctness, in all of my tests we 273 // This is really just for correctness, in all of my tests we
237 // never take this step. We don't lose too much perf here because 274 // never take this step. We don't lose too much perf here because
238 // most of the processing in this function is worth it for the 275 // most of the processing in this function is worth it for the
239 // 1 == nUniquePixels optimization. 276 // 1 == nUniquePixels optimization.
240 return compress_block_bb(pixels); 277 return compress_latc_block_bb(pixels);
241 } else { 278 } else {
242 return compress_block_bb_ignore_extremal(pixels); 279 return compress_latc_block_bb_ignore_extremal(pixels);
243 } 280 }
244 } 281 }
245 282
246 static bool compress_a8_to_latc(uint8_t* dst, const uint8_t* src, 283 static bool compress_a8_to_latc(uint8_t* dst, const uint8_t* src,
247 int width, int height, int rowBytes) { 284 int width, int height, int rowBytes) {
248 // Make sure that our data is well-formed enough to be 285 return compress_4x4_a8_to_64bit(dst, src, width, height, rowBytes, compress_ latc_block);
249 // considered for LATC compression 286 }
250 if (0 == width || 0 == height || 287
251 (width % kLATCBlockSize) != 0 || (height % kLATCBlockSize) != 0) { 288 ////////////////////////////////////////////////////////////////////////////////
252 return false; 289 //
253 } 290 // R11 EAC Compressor
254 291 //
255 int blocksX = width / kLATCBlockSize; 292 ////////////////////////////////////////////////////////////////////////////////
256 int blocksY = height / kLATCBlockSize; 293
257 294 // Blocks compressed into R11 EAC are represented as follows:
258 uint8_t block[16]; 295 // 0000000000000000000000000000000000000000000000000000000000000000
259 uint64_t* encPtr = reinterpret_cast<uint64_t*>(dst); 296 // |base_cw|mod|mul| ----------------- indices -------------------
260 for (int y = 0; y < blocksY; ++y) { 297 //
261 for (int x = 0; x < blocksX; ++x) { 298 // To reconstruct the value of a given pixel, we use the formula:
262 // Load block 299 // clamp[0, 2047](base_cw * 8 + 4 + mod_val*mul*8)
263 static const int kBS = kLATCBlockSize; 300 //
264 for (int k = 0; k < kBS; ++k) { 301 // mod_val is chosen from a palette of values based on the index of the
265 memcpy(block + k*kBS, src + k*rowBytes + (kBS * x), kBS); 302 // given pixel. The palette is chosen by the value stored in mod.
303 // This formula returns a value between 0 and 2047, which is converted
304 // to a float from 0 to 1 in OpenGL.
305 //
306 // If mul is zero, then we set mul = 1/8, so that the formula becomes
307 // clamp[0, 2047](base_cw * 8 + 4 + mod_val)
308
309 static const int kNumR11EACPalettes = 16;
310 static const int kR11EACPaletteSize = 8;
311 static const int kR11EACModifierPalettes[kNumR11EACPalettes][kR11EACPaletteSize] = {
312 {-3, -6, -9, -15, 2, 5, 8, 14},
313 {-3, -7, -10, -13, 2, 6, 9, 12},
314 {-2, -5, -8, -13, 1, 4, 7, 12},
315 {-2, -4, -6, -13, 1, 3, 5, 12},
316 {-3, -6, -8, -12, 2, 5, 7, 11},
317 {-3, -7, -9, -11, 2, 6, 8, 10},
318 {-4, -7, -8, -11, 3, 6, 7, 10},
319 {-3, -5, -8, -11, 2, 4, 7, 10},
320 {-2, -6, -8, -10, 1, 5, 7, 9},
321 {-2, -5, -8, -10, 1, 4, 7, 9},
322 {-2, -4, -8, -10, 1, 3, 7, 9},
323 {-2, -5, -7, -10, 1, 4, 6, 9},
324 {-3, -4, -7, -10, 2, 3, 6, 9},
325 {-1, -2, -3, -10, 0, 1, 2, 9},
326 {-4, -6, -8, -9, 3, 5, 7, 8},
327 {-3, -5, -7, -9, 2, 4, 6, 8}
328 };
329
330 // Pack the base codeword, palette, and multiplier into the 64 bits necessary
331 // to decode it.
332 static uint64_t pack_r11eac_block(uint16_t base_cw, uint16_t palette, uint16_t m ultiplier,
333 uint64_t indices) {
334 SkASSERT(palette < 16);
335 SkASSERT(multiplier < 16);
336 SkASSERT(indices < (static_cast<uint64_t>(1) << 48));
337
338 const uint64_t b = static_cast<uint64_t>(base_cw) << 56;
339 const uint64_t m = static_cast<uint64_t>(multiplier) << 52;
340 const uint64_t p = static_cast<uint64_t>(palette) << 48;
341 return SkEndian_SwapBE64(b | m | p | indices);
342 }
343
344 // Given a base codeword, a modifier, and a multiplier, compute the proper
345 // pixel value in the range [0, 2047].
346 static uint16_t compute_r11eac_pixel(int base_cw, int modifier, int multiplier) {
347 int ret = (base_cw * 8 + 4) + (modifier * multiplier * 8);
348 return (ret > 2047)? 2047 : ((ret < 0)? 0 : ret);
349 }
350
351 // Compress a block into R11 EAC format.
352 // The compression works as follows:
353 // 1. Find the center of the span of the block's values. Use this as the base co deword.
354 // 2. Choose a multiplier based roughly on the size of the span of block values
355 // 3. Iterate through each palette and choose the one with the most accurate
356 // modifiers.
357 static uint64_t compress_heterogeneous_r11eac_block(const uint8_t block[16]) {
358 // Find the center of the data...
359 uint16_t bmin = block[0];
360 uint16_t bmax = block[0];
361 for (int i = 1; i < 16; ++i) {
362 bmin = SkTMin<uint16_t>(bmin, block[i]);
363 bmax = SkTMax<uint16_t>(bmax, block[i]);
364 }
365
366 uint16_t center = (bmax + bmin) >> 1;
367 SkASSERT(center <= 255);
368
369 // Based on the min and max, we can guesstimate a proper multiplier
370 // This is kind of a magic choice to start with.
371 uint16_t multiplier = (bmax - center) / 10;
372
373 // Now convert the block to 11 bits and transpose it to match
374 // the proper layout
375 uint16_t cblock[16];
376 for (int i = 0; i < 4; ++i) {
377 for (int j = 0; j < 4; ++j) {
378 int srcIdx = i*4+j;
379 int dstIdx = j*4+i;
380 cblock[dstIdx] = (block[srcIdx] << 3) | (block[srcIdx] >> 5);
381 }
382 }
383
384 // Finally, choose the proper palette and indices
385 uint32_t bestError = static_cast<uint32_t>(-1);
386 uint64_t bestIndices = 0;
387 uint16_t bestPalette = 0;
388 for (uint16_t paletteIdx = 0; paletteIdx < kNumR11EACPalettes; ++paletteIdx) {
389 const int *palette = kR11EACModifierPalettes[paletteIdx];
tfarina 2014/07/12 02:07:28 clang is warning on me: ../../src/utils/SkTexture
390
391 // Iterate through each pixel to find the best palette index
392 // and update the indices with the choice. Also store the error
393 // for this palette to be compared against the best error...
394 uint32_t error = 0;
395 uint64_t indices = 0;
396 for (int pixelIdx = 0; pixelIdx < 16; ++pixelIdx) {
397 const uint16_t pixel = cblock[pixelIdx];
398
399 // Iterate through each palette value to find the best index
400 // for this particular pixel for this particular palette.
401 uint16_t bestPixelError =
402 abs_diff(pixel, compute_r11eac_pixel(center, palette[0], multipl ier));
403 int bestIndex = 0;
404 for (int i = 1; i < kR11EACPaletteSize; ++i) {
405 const uint16_t p = compute_r11eac_pixel(center, palette[i], mult iplier);
406 const uint16_t perror = abs_diff(pixel, p);
407
408 // Is this index better?
409 if (perror < bestPixelError) {
410 bestIndex = i;
411 bestPixelError = perror;
412 }
266 } 413 }
267 414
268 // Compress it 415 SkASSERT(bestIndex < 8);
269 *encPtr = compress_block(block); 416
270 ++encPtr; 417 error += bestPixelError;
271 } 418 indices <<= 3;
272 src += kLATCBlockSize * rowBytes; 419 indices |= bestIndex;
273 } 420 }
274 421
275 return true; 422 SkASSERT(indices < (static_cast<uint64_t>(1) << 48));
423
424 // Is this palette better?
425 if (error < bestError) {
426 bestPalette = paletteIdx;
427 bestIndices = indices;
428 bestError = error;
429 }
430 }
431
432 // Finally, pack everything together...
433 return pack_r11eac_block(center, bestPalette, multiplier, bestIndices);
434 }
435
436 static uint64_t compress_r11eac_block(const uint8_t block[16]) {
437 // Are all blocks a solid color?
438 bool solid = true;
439 for (int i = 1; i < 16; ++i) {
440 if (block[i] != block[0]) {
441 solid = false;
442 break;
443 }
444 }
445
446 // Fully transparent? We know the encoding...
447 if (solid && 0 == block[0]) {
448 // (0x0060 << 48) produces the following:
449 // basw_cw: 0
450 // mod: 6, palette: {-4, -7, -8, -11, 3, 6, 7, 10}
451 // mod_val: -3
452 //
453 // this gives the following formula:
454 // clamp[0, 2047](0*8+4+(-4)) = 0
455 return SkEndian_SwapBE64(static_cast<uint64_t>(0x0060) << 48);
456
457 // Fully opaque? We know this encoding too...
458 } else if (solid && 255 == block[0]) {
459 // -1 produces the following:
460 // basw_cw: 255
461 // mod: 15, palette: {-3, -5, -7, -9, 2, 4, 6, 8}
462 // mod_val: 8
463 //
464 // this gives the following formula:
465 // clamp[0, 2047](255*8+4+8*8*8) = clamp[0, 2047](2556) = 2047
466 return static_cast<uint64_t>(-1);
467 }
468
469 #if 0
470 else if (solid) {
471 // !TODO! krajcevski:
472 // This will probably never happen, since we're using this format
473 // primarily for compressing alpha maps. Usually the only
474 // non-fullly opaque or fully transparent blocks are not a solid
475 // intermediate color. If we notice that they are, then we can
476 // add another optimization...
477 }
478 #endif
479
480 return compress_heterogeneous_r11eac_block(block);
481 }
482
483 static bool compress_a8_to_r11eac(uint8_t* dst, const uint8_t* src,
484 int width, int height, int rowBytes) {
485 return compress_4x4_a8_to_64bit(dst, src, width, height, rowBytes, compress_ r11eac_block);
276 } 486 }
277 487
278 //////////////////////////////////////////////////////////////////////////////// 488 ////////////////////////////////////////////////////////////////////////////////
279 489
280 namespace SkTextureCompressor { 490 namespace SkTextureCompressor {
281 491
282 static size_t get_compressed_data_size(Format fmt, int width, int height) { 492 static size_t get_compressed_data_size(Format fmt, int width, int height) {
283 switch (fmt) { 493 switch (fmt) {
494 case kR11_EAC_Format:
284 case kLATC_Format: 495 case kLATC_Format:
285 { 496 {
286 // The LATC format is 64 bits per 4x4 block. 497 // The LATC format is 64 bits per 4x4 block.
287 static const int kLATCEncodedBlockSize = 8; 498 static const int kLATCEncodedBlockSize = 8;
288 499
289 int blocksX = width / kLATCBlockSize; 500 int blocksX = width / kLATCBlockSize;
290 int blocksY = height / kLATCBlockSize; 501 int blocksY = height / kLATCBlockSize;
291 502
292 return blocksX * blocksY * kLATCEncodedBlockSize; 503 return blocksX * blocksY * kLATCEncodedBlockSize;
293 } 504 }
294 505
295 default: 506 default:
296 SkFAIL("Unknown compressed format!"); 507 SkFAIL("Unknown compressed format!");
297 return 0; 508 return 0;
298 } 509 }
299 } 510 }
300 511
301 typedef bool (*CompressBitmapProc)(uint8_t* dst, const uint8_t* src, 512 typedef bool (*CompressBitmapProc)(uint8_t* dst, const uint8_t* src,
302 int width, int height, int rowBytes); 513 int width, int height, int rowBytes);
303 514
304 bool CompressBufferToFormat(uint8_t* dst, const uint8_t* src, SkColorType srcCol orType, 515 bool CompressBufferToFormat(uint8_t* dst, const uint8_t* src, SkColorType srcCol orType,
305 int width, int height, int rowBytes, Format format) { 516 int width, int height, int rowBytes, Format format) {
306 517
307 CompressBitmapProc kProcMap[kFormatCnt][kLastEnum_SkColorType + 1]; 518 CompressBitmapProc kProcMap[kFormatCnt][kLastEnum_SkColorType + 1];
308 memset(kProcMap, 0, sizeof(kProcMap)); 519 memset(kProcMap, 0, sizeof(kProcMap));
309 520
310 kProcMap[kLATC_Format][kAlpha_8_SkColorType] = compress_a8_to_latc; 521 kProcMap[kLATC_Format][kAlpha_8_SkColorType] = compress_a8_to_latc;
522 kProcMap[kR11_EAC_Format][kAlpha_8_SkColorType] = compress_a8_to_r11eac;
311 523
312 CompressBitmapProc proc = kProcMap[format][srcColorType]; 524 CompressBitmapProc proc = kProcMap[format][srcColorType];
313 if (NULL != proc) { 525 if (NULL != proc) {
314 return proc(dst, src, width, height, rowBytes); 526 return proc(dst, src, width, height, rowBytes);
315 } 527 }
316 528
317 return false; 529 return false;
318 } 530 }
319 531
320 SkData *CompressBitmapToFormat(const SkBitmap &bitmap, Format format) { 532 SkData *CompressBitmapToFormat(const SkBitmap &bitmap, Format format) {
321 SkAutoLockPixels alp(bitmap); 533 SkAutoLockPixels alp(bitmap);
322 534
323 int compressedDataSize = get_compressed_data_size(format, bitmap.width(), bi tmap.height()); 535 int compressedDataSize = get_compressed_data_size(format, bitmap.width(), bi tmap.height());
324 const uint8_t* src = reinterpret_cast<const uint8_t*>(bitmap.getPixels()); 536 const uint8_t* src = reinterpret_cast<const uint8_t*>(bitmap.getPixels());
325 uint8_t* dst = reinterpret_cast<uint8_t*>(sk_malloc_throw(compressedDataSize )); 537 uint8_t* dst = reinterpret_cast<uint8_t*>(sk_malloc_throw(compressedDataSize ));
326 if (CompressBufferToFormat(dst, src, bitmap.colorType(), bitmap.width(), bit map.height(), 538 if (CompressBufferToFormat(dst, src, bitmap.colorType(), bitmap.width(), bit map.height(),
327 bitmap.rowBytes(), format)) { 539 bitmap.rowBytes(), format)) {
328 return SkData::NewFromMalloc(dst, compressedDataSize); 540 return SkData::NewFromMalloc(dst, compressedDataSize);
329 } 541 }
330 542
331 sk_free(dst); 543 sk_free(dst);
332 return NULL; 544 return NULL;
333 } 545 }
334 546
335 } // namespace SkTextureCompressor 547 } // namespace SkTextureCompressor
OLDNEW
« no previous file with comments | « src/utils/SkTextureCompressor.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698