blob: 12621e118f9275f394500008d6a29e2ace4ac369 [file] [log] [blame]
krajcevskiae614402014-06-10 14:52:28 -07001/*
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"
krajcevskib2ef1812014-07-25 07:33:01 -07009#include "SkTextureCompressor_ASTC.h"
krajcevski6c354882014-07-22 07:44:00 -070010#include "SkTextureCompressor_LATC.h"
krajcevskib2ef1812014-07-25 07:33:01 -070011#include "SkTextureCompressor_R11EAC.h"
krajcevskiae614402014-06-10 14:52:28 -070012
13#include "SkBitmap.h"
krajcevskib8ccc2f2014-08-07 08:15:14 -070014#include "SkBitmapProcShader.h"
krajcevskiae614402014-06-10 14:52:28 -070015#include "SkData.h"
16#include "SkEndian.h"
17
krajcevski630598c2014-07-14 12:00:04 -070018#include "SkTextureCompression_opts.h"
19
krajcevskie90c9002014-08-05 07:37:26 -070020#ifndef SK_IGNORE_ETC1_SUPPORT
21# include "etc1.h"
22#endif
23
24// Convert ETC1 functions to our function signatures
25static bool compress_etc1_565(uint8_t* dst, const uint8_t* src,
bsalomon98806072014-12-12 15:11:17 -080026 int width, int height, size_t rowBytes) {
krajcevskie90c9002014-08-05 07:37:26 -070027#ifndef SK_IGNORE_ETC1_SUPPORT
bsalomon98806072014-12-12 15:11:17 -080028 return 0 == etc1_encode_image(src, width, height, 2, SkToInt(rowBytes), dst);
krajcevskie90c9002014-08-05 07:37:26 -070029#else
30 return false;
31#endif
32}
33
krajcevskiae614402014-06-10 14:52:28 -070034////////////////////////////////////////////////////////////////////////////////
krajcevskiae614402014-06-10 14:52:28 -070035
36namespace SkTextureCompressor {
37
krajcevski4ad76e32014-07-31 14:12:50 -070038void GetBlockDimensions(Format format, int* dimX, int* dimY, bool matchSpec) {
krajcevski25a67bc2014-07-29 11:44:26 -070039 if (NULL == dimX || NULL == dimY) {
40 return;
41 }
42
krajcevski4ad76e32014-07-31 14:12:50 -070043 if (!matchSpec && SkTextureCompressorGetPlatformDims(format, dimX, dimY)) {
krajcevski25a67bc2014-07-29 11:44:26 -070044 return;
45 }
46
krajcevski4ad76e32014-07-31 14:12:50 -070047 // No specialized arguments, return the dimensions as they are in the spec.
krajcevski95b1b3d2014-08-07 12:58:38 -070048 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 };
krajcevski25a67bc2014-07-29 11:44:26 -070070
krajcevski95b1b3d2014-08-07 12:58:38 -070071 *dimX = kFormatDimensions[format].fBlockSizeX;
72 *dimY = kFormatDimensions[format].fBlockSizeY;
krajcevski25a67bc2014-07-29 11:44:26 -070073}
74
krajcevski6c354882014-07-22 07:44:00 -070075int GetCompressedDataSize(Format fmt, int width, int height) {
krajcevski25a67bc2014-07-29 11:44:26 -070076 int dimX, dimY;
krajcevski4ad76e32014-07-31 14:12:50 -070077 GetBlockDimensions(fmt, &dimX, &dimY, true);
78
krajcevskib2ef1812014-07-25 07:33:01 -070079 int encodedBlockSize = 0;
80
krajcevskieecc35f2014-06-20 11:43:00 -070081 switch (fmt) {
krajcevski1459be52014-07-09 09:15:45 -070082 // These formats are 64 bits per 4x4 block.
krajcevski50495572014-08-04 09:47:31 -070083 case kLATC_Format:
krajcevskie90c9002014-08-05 07:37:26 -070084 case kR11_EAC_Format:
85 case kETC1_Format:
krajcevskib2ef1812014-07-25 07:33:01 -070086 encodedBlockSize = 8;
87 break;
krajcevskieecc35f2014-06-20 11:43:00 -070088
krajcevski95b1b3d2014-08-07 12:58:38 -070089 // 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:
krajcevskib2ef1812014-07-25 07:33:01 -0700103 case kASTC_12x12_Format:
krajcevskib2ef1812014-07-25 07:33:01 -0700104 encodedBlockSize = 16;
105 break;
krajcevskieecc35f2014-06-20 11:43:00 -0700106
107 default:
108 SkFAIL("Unknown compressed format!");
krajcevski6c354882014-07-22 07:44:00 -0700109 return -1;
krajcevskieecc35f2014-06-20 11:43:00 -0700110 }
krajcevskib2ef1812014-07-25 07:33:01 -0700111
krajcevski25a67bc2014-07-29 11:44:26 -0700112 if(((width % dimX) == 0) && ((height % dimY) == 0)) {
113 const int blocksX = width / dimX;
114 const int blocksY = height / dimY;
krajcevskib2ef1812014-07-25 07:33:01 -0700115
116 return blocksX * blocksY * encodedBlockSize;
117 }
118
119 return -1;
krajcevskieecc35f2014-06-20 11:43:00 -0700120}
121
krajcevskieecc35f2014-06-20 11:43:00 -0700122bool CompressBufferToFormat(uint8_t* dst, const uint8_t* src, SkColorType srcColorType,
bsalomon98806072014-12-12 15:11:17 -0800123 int width, int height, size_t rowBytes, Format format, bool opt) {
krajcevski630598c2014-07-14 12:00:04 -0700124 CompressionProc proc = NULL;
125 if (opt) {
126 proc = SkTextureCompressorGetPlatformProc(srcColorType, format);
127 }
krajcevskieecc35f2014-06-20 11:43:00 -0700128
krajcevski630598c2014-07-14 12:00:04 -0700129 if (NULL == proc) {
130 switch (srcColorType) {
131 case kAlpha_8_SkColorType:
132 {
133 switch (format) {
134 case kLATC_Format:
krajcevski6c354882014-07-22 07:44:00 -0700135 proc = CompressA8ToLATC;
krajcevski630598c2014-07-14 12:00:04 -0700136 break;
137 case kR11_EAC_Format:
krajcevski6c354882014-07-22 07:44:00 -0700138 proc = CompressA8ToR11EAC;
krajcevski630598c2014-07-14 12:00:04 -0700139 break;
krajcevskib2ef1812014-07-25 07:33:01 -0700140 case kASTC_12x12_Format:
141 proc = CompressA8To12x12ASTC;
142 break;
krajcevski630598c2014-07-14 12:00:04 -0700143 default:
144 // Do nothing...
145 break;
146 }
147 }
148 break;
krajcevskieecc35f2014-06-20 11:43:00 -0700149
krajcevskie90c9002014-08-05 07:37:26 -0700150 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
krajcevski630598c2014-07-14 12:00:04 -0700163 default:
164 // Do nothing...
165 break;
166 }
167 }
krajcevski1459be52014-07-09 09:15:45 -0700168
bsalomon49f085d2014-09-05 13:34:00 -0700169 if (proc) {
krajcevskieecc35f2014-06-20 11:43:00 -0700170 return proc(dst, src, width, height, rowBytes);
171 }
172
173 return false;
174}
krajcevskiae614402014-06-10 14:52:28 -0700175
reed33a30502014-09-11 08:42:36 -0700176SkData* CompressBitmapToFormat(const SkBitmap &bitmap, Format format) {
krajcevski2b310e42014-06-11 12:26:49 -0700177 SkAutoLockPixels alp(bitmap);
178
krajcevski6c354882014-07-22 07:44:00 -0700179 int compressedDataSize = GetCompressedDataSize(format, bitmap.width(), bitmap.height());
180 if (compressedDataSize < 0) {
181 return NULL;
182 }
183
krajcevskieecc35f2014-06-20 11:43:00 -0700184 const uint8_t* src = reinterpret_cast<const uint8_t*>(bitmap.getPixels());
reed33a30502014-09-11 08:42:36 -0700185 SkData* dst = SkData::NewUninitialized(compressedDataSize);
krajcevski6c354882014-07-22 07:44:00 -0700186
reed33a30502014-09-11 08:42:36 -0700187 if (!CompressBufferToFormat((uint8_t*)dst->writable_data(), src, bitmap.colorType(),
188 bitmap.width(), bitmap.height(), bitmap.rowBytes(), format)) {
189 dst->unref();
190 dst = NULL;
krajcevskiae614402014-06-10 14:52:28 -0700191 }
reed33a30502014-09-11 08:42:36 -0700192 return dst;
krajcevskiae614402014-06-10 14:52:28 -0700193}
194
krajcevskib8ccc2f2014-08-07 08:15:14 -0700195SkBlitter* CreateBlitterForFormat(int width, int height, void* compressedBuffer,
196 SkTBlitterAllocator *allocator, Format format) {
krajcevski6c354882014-07-22 07:44:00 -0700197 switch(format) {
198 case kLATC_Format:
krajcevskib8ccc2f2014-08-07 08:15:14 -0700199 return CreateLATCBlitter(width, height, compressedBuffer, allocator);
krajcevskiad1df152014-07-21 11:44:37 -0700200
krajcevski6c354882014-07-22 07:44:00 -0700201 case kR11_EAC_Format:
krajcevskib8ccc2f2014-08-07 08:15:14 -0700202 return CreateR11EACBlitter(width, height, compressedBuffer, allocator);
krajcevski6c354882014-07-22 07:44:00 -0700203
krajcevski10a350c2014-07-29 07:24:58 -0700204 case kASTC_12x12_Format:
krajcevskib8ccc2f2014-08-07 08:15:14 -0700205 return CreateASTCBlitter(width, height, compressedBuffer, allocator);
krajcevski10a350c2014-07-29 07:24:58 -0700206
krajcevski6c354882014-07-22 07:44:00 -0700207 default:
208 return NULL;
krajcevskiad1df152014-07-21 11:44:37 -0700209 }
210
krajcevski6c354882014-07-22 07:44:00 -0700211 return NULL;
krajcevskiad1df152014-07-21 11:44:37 -0700212}
213
krajcevski4ad76e32014-07-31 14:12:50 -0700214bool 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
krajcevskie90c9002014-08-05 07:37:26 -0700232#ifndef SK_IGNORE_ETC1_SUPPORT
233 case kETC1_Format:
234 return 0 == etc1_decode_image(src, dst, width, height, 3, dstRowBytes);
235#endif
krajcevski95b1b3d2014-08-07 12:58:38 -0700236
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:
krajcevski4ad76e32014-07-31 14:12:50 -0700250 case kASTC_12x12_Format:
krajcevski95b1b3d2014-08-07 12:58:38 -0700251 DecompressASTC(dst, dstRowBytes, src, width, height, dimX, dimY);
252 return true;
krajcevskie90c9002014-08-05 07:37:26 -0700253
254 default:
255 // Do nothing...
256 break;
krajcevski4ad76e32014-07-31 14:12:50 -0700257 }
258
259 return false;
260}
261
krajcevskiae614402014-06-10 14:52:28 -0700262} // namespace SkTextureCompressor