blob: 9d29d51d6084e02765ad0e13cdbc13f19cf2c6ee [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
reed41e010c2015-06-09 12:16:53 -0700176SkData* CompressBitmapToFormat(const SkPixmap& pixmap, Format format) {
177 int compressedDataSize = GetCompressedDataSize(format, pixmap.width(), pixmap.height());
krajcevski6c354882014-07-22 07:44:00 -0700178 if (compressedDataSize < 0) {
179 return NULL;
180 }
181
reed41e010c2015-06-09 12:16:53 -0700182 const uint8_t* src = reinterpret_cast<const uint8_t*>(pixmap.addr());
reed33a30502014-09-11 08:42:36 -0700183 SkData* dst = SkData::NewUninitialized(compressedDataSize);
krajcevski6c354882014-07-22 07:44:00 -0700184
reed41e010c2015-06-09 12:16:53 -0700185 if (!CompressBufferToFormat((uint8_t*)dst->writable_data(), src, pixmap.colorType(),
186 pixmap.width(), pixmap.height(), pixmap.rowBytes(), format)) {
reed33a30502014-09-11 08:42:36 -0700187 dst->unref();
188 dst = NULL;
krajcevskiae614402014-06-10 14:52:28 -0700189 }
reed33a30502014-09-11 08:42:36 -0700190 return dst;
krajcevskiae614402014-06-10 14:52:28 -0700191}
192
krajcevskib8ccc2f2014-08-07 08:15:14 -0700193SkBlitter* CreateBlitterForFormat(int width, int height, void* compressedBuffer,
194 SkTBlitterAllocator *allocator, Format format) {
krajcevski6c354882014-07-22 07:44:00 -0700195 switch(format) {
196 case kLATC_Format:
krajcevskib8ccc2f2014-08-07 08:15:14 -0700197 return CreateLATCBlitter(width, height, compressedBuffer, allocator);
krajcevskiad1df152014-07-21 11:44:37 -0700198
krajcevski6c354882014-07-22 07:44:00 -0700199 case kR11_EAC_Format:
krajcevskib8ccc2f2014-08-07 08:15:14 -0700200 return CreateR11EACBlitter(width, height, compressedBuffer, allocator);
krajcevski6c354882014-07-22 07:44:00 -0700201
krajcevski10a350c2014-07-29 07:24:58 -0700202 case kASTC_12x12_Format:
krajcevskib8ccc2f2014-08-07 08:15:14 -0700203 return CreateASTCBlitter(width, height, compressedBuffer, allocator);
krajcevski10a350c2014-07-29 07:24:58 -0700204
krajcevski6c354882014-07-22 07:44:00 -0700205 default:
206 return NULL;
krajcevskiad1df152014-07-21 11:44:37 -0700207 }
208
krajcevski6c354882014-07-22 07:44:00 -0700209 return NULL;
krajcevskiad1df152014-07-21 11:44:37 -0700210}
211
krajcevski4ad76e32014-07-31 14:12:50 -0700212bool DecompressBufferFromFormat(uint8_t* dst, int dstRowBytes, const uint8_t* src,
213 int width, int height, Format format) {
214 int dimX, dimY;
215 GetBlockDimensions(format, &dimX, &dimY, true);
216
217 if (width < 0 || ((width % dimX) != 0) || height < 0 || ((height % dimY) != 0)) {
218 return false;
219 }
220
221 switch(format) {
222 case kLATC_Format:
223 DecompressLATC(dst, dstRowBytes, src, width, height);
224 return true;
225
226 case kR11_EAC_Format:
227 DecompressR11EAC(dst, dstRowBytes, src, width, height);
228 return true;
229
krajcevskie90c9002014-08-05 07:37:26 -0700230#ifndef SK_IGNORE_ETC1_SUPPORT
231 case kETC1_Format:
232 return 0 == etc1_decode_image(src, dst, width, height, 3, dstRowBytes);
233#endif
krajcevski95b1b3d2014-08-07 12:58:38 -0700234
235 case kASTC_4x4_Format:
236 case kASTC_5x4_Format:
237 case kASTC_5x5_Format:
238 case kASTC_6x5_Format:
239 case kASTC_6x6_Format:
240 case kASTC_8x5_Format:
241 case kASTC_8x6_Format:
242 case kASTC_8x8_Format:
243 case kASTC_10x5_Format:
244 case kASTC_10x6_Format:
245 case kASTC_10x8_Format:
246 case kASTC_10x10_Format:
247 case kASTC_12x10_Format:
krajcevski4ad76e32014-07-31 14:12:50 -0700248 case kASTC_12x12_Format:
krajcevski95b1b3d2014-08-07 12:58:38 -0700249 DecompressASTC(dst, dstRowBytes, src, width, height, dimX, dimY);
250 return true;
krajcevskie90c9002014-08-05 07:37:26 -0700251
252 default:
253 // Do nothing...
254 break;
krajcevski4ad76e32014-07-31 14:12:50 -0700255 }
256
257 return false;
258}
259
krajcevskiae614402014-06-10 14:52:28 -0700260} // namespace SkTextureCompressor