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.h"
9 #include "SkTextureCompressor_ASTC.h"
10 #include "SkTextureCompressor_LATC.h"
11 #include "SkTextureCompressor_R11EAC.h"
12
13 #include "SkBitmap.h"
14 #include "SkBitmapProcShader.h"
15 #include "SkData.h"
16 #include "SkEndian.h"
17
18 #include "SkTextureCompression_opts.h"
19
20 #ifndef SK_IGNORE_ETC1_SUPPORT
21 # include "etc1.h"
22 #endif
23
24 // Convert ETC1 functions to our function signatures
compress_etc1_565(uint8_t * dst,const uint8_t * src,int width,int height,size_t rowBytes)25 static bool compress_etc1_565(uint8_t* dst, const uint8_t* src,
26 int width, int height, size_t rowBytes) {
27 #ifndef SK_IGNORE_ETC1_SUPPORT
28 return 0 == etc1_encode_image(src, width, height, 2, SkToInt(rowBytes), dst);
29 #else
30 return false;
31 #endif
32 }
33
34 ////////////////////////////////////////////////////////////////////////////////
35
36 namespace SkTextureCompressor {
37
GetBlockDimensions(Format format,int * dimX,int * dimY,bool matchSpec)38 void GetBlockDimensions(Format format, int* dimX, int* dimY, bool matchSpec) {
39 if (NULL == dimX || NULL == dimY) {
40 return;
41 }
42
43 if (!matchSpec && SkTextureCompressorGetPlatformDims(format, dimX, dimY)) {
44 return;
45 }
46
47 // No specialized arguments, return the dimensions as they are in the spec.
48 static const struct FormatDimensions {
49 const int fBlockSizeX;
50 const int fBlockSizeY;
51 } kFormatDimensions[kFormatCnt] = {
52 { 4, 4 }, // kLATC_Format
53 { 4, 4 }, // kR11_EAC_Format
54 { 4, 4 }, // kETC1_Format
55 { 4, 4 }, // kASTC_4x4_Format
56 { 5, 4 }, // kASTC_5x4_Format
57 { 5, 5 }, // kASTC_5x5_Format
58 { 6, 5 }, // kASTC_6x5_Format
59 { 6, 6 }, // kASTC_6x6_Format
60 { 8, 5 }, // kASTC_8x5_Format
61 { 8, 6 }, // kASTC_8x6_Format
62 { 8, 8 }, // kASTC_8x8_Format
63 { 10, 5 }, // kASTC_10x5_Format
64 { 10, 6 }, // kASTC_10x6_Format
65 { 10, 8 }, // kASTC_10x8_Format
66 { 10, 10 }, // kASTC_10x10_Format
67 { 12, 10 }, // kASTC_12x10_Format
68 { 12, 12 }, // kASTC_12x12_Format
69 };
70
71 *dimX = kFormatDimensions[format].fBlockSizeX;
72 *dimY = kFormatDimensions[format].fBlockSizeY;
73 }
74
GetCompressedDataSize(Format fmt,int width,int height)75 int GetCompressedDataSize(Format fmt, int width, int height) {
76 int dimX, dimY;
77 GetBlockDimensions(fmt, &dimX, &dimY, true);
78
79 int encodedBlockSize = 0;
80
81 switch (fmt) {
82 // These formats are 64 bits per 4x4 block.
83 case kLATC_Format:
84 case kR11_EAC_Format:
85 case kETC1_Format:
86 encodedBlockSize = 8;
87 break;
88
89 // This format is 128 bits.
90 case kASTC_4x4_Format:
91 case kASTC_5x4_Format:
92 case kASTC_5x5_Format:
93 case kASTC_6x5_Format:
94 case kASTC_6x6_Format:
95 case kASTC_8x5_Format:
96 case kASTC_8x6_Format:
97 case kASTC_8x8_Format:
98 case kASTC_10x5_Format:
99 case kASTC_10x6_Format:
100 case kASTC_10x8_Format:
101 case kASTC_10x10_Format:
102 case kASTC_12x10_Format:
103 case kASTC_12x12_Format:
104 encodedBlockSize = 16;
105 break;
106
107 default:
108 SkFAIL("Unknown compressed format!");
109 return -1;
110 }
111
112 if(((width % dimX) == 0) && ((height % dimY) == 0)) {
113 const int blocksX = width / dimX;
114 const int blocksY = height / dimY;
115
116 return blocksX * blocksY * encodedBlockSize;
117 }
118
119 return -1;
120 }
121
CompressBufferToFormat(uint8_t * dst,const uint8_t * src,SkColorType srcColorType,int width,int height,size_t rowBytes,Format format,bool opt)122 bool CompressBufferToFormat(uint8_t* dst, const uint8_t* src, SkColorType srcColorType,
123 int width, int height, size_t rowBytes, Format format, bool opt) {
124 CompressionProc proc = NULL;
125 if (opt) {
126 proc = SkTextureCompressorGetPlatformProc(srcColorType, format);
127 }
128
129 if (NULL == proc) {
130 switch (srcColorType) {
131 case kAlpha_8_SkColorType:
132 {
133 switch (format) {
134 case kLATC_Format:
135 proc = CompressA8ToLATC;
136 break;
137 case kR11_EAC_Format:
138 proc = CompressA8ToR11EAC;
139 break;
140 case kASTC_12x12_Format:
141 proc = CompressA8To12x12ASTC;
142 break;
143 default:
144 // Do nothing...
145 break;
146 }
147 }
148 break;
149
150 case kRGB_565_SkColorType:
151 {
152 switch (format) {
153 case kETC1_Format:
154 proc = compress_etc1_565;
155 break;
156 default:
157 // Do nothing...
158 break;
159 }
160 }
161 break;
162
163 default:
164 // Do nothing...
165 break;
166 }
167 }
168
169 if (proc) {
170 return proc(dst, src, width, height, rowBytes);
171 }
172
173 return false;
174 }
175
CompressBitmapToFormat(const SkBitmap & bitmap,Format format)176 SkData* CompressBitmapToFormat(const SkBitmap &bitmap, Format format) {
177 SkAutoLockPixels alp(bitmap);
178
179 int compressedDataSize = GetCompressedDataSize(format, bitmap.width(), bitmap.height());
180 if (compressedDataSize < 0) {
181 return NULL;
182 }
183
184 const uint8_t* src = reinterpret_cast<const uint8_t*>(bitmap.getPixels());
185 SkData* dst = SkData::NewUninitialized(compressedDataSize);
186
187 if (!CompressBufferToFormat((uint8_t*)dst->writable_data(), src, bitmap.colorType(),
188 bitmap.width(), bitmap.height(), bitmap.rowBytes(), format)) {
189 dst->unref();
190 dst = NULL;
191 }
192 return dst;
193 }
194
CreateBlitterForFormat(int width,int height,void * compressedBuffer,SkTBlitterAllocator * allocator,Format format)195 SkBlitter* CreateBlitterForFormat(int width, int height, void* compressedBuffer,
196 SkTBlitterAllocator *allocator, Format format) {
197 switch(format) {
198 case kLATC_Format:
199 return CreateLATCBlitter(width, height, compressedBuffer, allocator);
200
201 case kR11_EAC_Format:
202 return CreateR11EACBlitter(width, height, compressedBuffer, allocator);
203
204 case kASTC_12x12_Format:
205 return CreateASTCBlitter(width, height, compressedBuffer, allocator);
206
207 default:
208 return NULL;
209 }
210
211 return NULL;
212 }
213
DecompressBufferFromFormat(uint8_t * dst,int dstRowBytes,const uint8_t * src,int width,int height,Format format)214 bool DecompressBufferFromFormat(uint8_t* dst, int dstRowBytes, const uint8_t* src,
215 int width, int height, Format format) {
216 int dimX, dimY;
217 GetBlockDimensions(format, &dimX, &dimY, true);
218
219 if (width < 0 || ((width % dimX) != 0) || height < 0 || ((height % dimY) != 0)) {
220 return false;
221 }
222
223 switch(format) {
224 case kLATC_Format:
225 DecompressLATC(dst, dstRowBytes, src, width, height);
226 return true;
227
228 case kR11_EAC_Format:
229 DecompressR11EAC(dst, dstRowBytes, src, width, height);
230 return true;
231
232 #ifndef SK_IGNORE_ETC1_SUPPORT
233 case kETC1_Format:
234 return 0 == etc1_decode_image(src, dst, width, height, 3, dstRowBytes);
235 #endif
236
237 case kASTC_4x4_Format:
238 case kASTC_5x4_Format:
239 case kASTC_5x5_Format:
240 case kASTC_6x5_Format:
241 case kASTC_6x6_Format:
242 case kASTC_8x5_Format:
243 case kASTC_8x6_Format:
244 case kASTC_8x8_Format:
245 case kASTC_10x5_Format:
246 case kASTC_10x6_Format:
247 case kASTC_10x8_Format:
248 case kASTC_10x10_Format:
249 case kASTC_12x10_Format:
250 case kASTC_12x12_Format:
251 DecompressASTC(dst, dstRowBytes, src, width, height, dimX, dimY);
252 return true;
253
254 default:
255 // Do nothing...
256 break;
257 }
258
259 return false;
260 }
261
262 } // namespace SkTextureCompressor
263