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

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