blob: 019fa97678f8fa23275395068f7466afdf2d3a56 [file] [log] [blame]
krajcevski99ffe242014-06-03 13:04:35 -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 "SkColorPriv.h"
9#include "SkImageDecoder.h"
msarett8715d472016-02-17 10:02:29 -080010#include "SkImageGenerator.h"
krajcevskic250d2e2014-06-06 06:16:28 -070011#include "SkPixelRef.h"
krajcevski99ffe242014-06-03 13:04:35 -070012#include "SkScaledBitmapSampler.h"
13#include "SkStream.h"
halcanary67ec1f82014-06-27 11:36:20 -070014#include "SkStreamPriv.h"
krajcevski99ffe242014-06-03 13:04:35 -070015#include "SkTypes.h"
16
17#include "ktx.h"
18#include "etc1.h"
19
20/////////////////////////////////////////////////////////////////////////////////////////
21
22
23/////////////////////////////////////////////////////////////////////////////////////////
24
25// KTX Image decoder
26// ---
27// KTX is a general texture data storage file format ratified by the Khronos Group. As an
28// overview, a KTX file contains all of the appropriate values needed to fully specify a
29// texture in an OpenGL application, including the use of compressed data.
30//
31// This decoder is meant to be used with an SkDiscardablePixelRef so that GPU backends
32// can sniff the data before creating a texture. If they encounter a compressed format
33// that they understand, they can then upload the data directly to the GPU. Otherwise,
34// they will decode the data into a format that Skia supports.
35
36class SkKTXImageDecoder : public SkImageDecoder {
37public:
38 SkKTXImageDecoder() { }
39
mtklein36352bf2015-03-25 18:17:31 -070040 Format getFormat() const override {
krajcevski99ffe242014-06-03 13:04:35 -070041 return kKTX_Format;
42 }
43
44protected:
mtklein36352bf2015-03-25 18:17:31 -070045 Result onDecode(SkStream* stream, SkBitmap* bm, Mode) override;
krajcevski99ffe242014-06-03 13:04:35 -070046
47private:
48 typedef SkImageDecoder INHERITED;
49};
50
scroggo2a120802014-10-22 12:07:00 -070051SkImageDecoder::Result SkKTXImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) {
krajcevski99ffe242014-06-03 13:04:35 -070052 // TODO: Implement SkStream::copyToData() that's cheap for memory and file streams
halcanary67ec1f82014-06-27 11:36:20 -070053 SkAutoDataUnref data(SkCopyStreamToData(stream));
halcanary96fcdcc2015-08-27 07:41:13 -070054 if (nullptr == data) {
scroggo2a120802014-10-22 12:07:00 -070055 return kFailure;
krajcevski99ffe242014-06-03 13:04:35 -070056 }
57
58 SkKTXFile ktxFile(data);
59 if (!ktxFile.valid()) {
scroggo2a120802014-10-22 12:07:00 -070060 return kFailure;
krajcevski99ffe242014-06-03 13:04:35 -070061 }
62
63 const unsigned short width = ktxFile.width();
64 const unsigned short height = ktxFile.height();
65
krajcevski3b570c62014-06-10 09:17:48 -070066 // Set a flag if our source is premultiplied alpha
67 const SkString premulKey("KTXPremultipliedAlpha");
68 const bool bSrcIsPremul = ktxFile.getValueForKey(premulKey) == SkString("True");
69
krajcevski99ffe242014-06-03 13:04:35 -070070 // Setup the sampler...
71 SkScaledBitmapSampler sampler(width, height, this->getSampleSize());
72
krajcevski3b570c62014-06-10 09:17:48 -070073 // Determine the alpha of the bitmap...
74 SkAlphaType alphaType = kOpaque_SkAlphaType;
75 if (ktxFile.isRGBA8()) {
76 if (this->getRequireUnpremultipliedColors()) {
77 alphaType = kUnpremul_SkAlphaType;
78 // If the client wants unpremul colors and we only have
79 // premul, then we cannot honor their wish.
80 if (bSrcIsPremul) {
scroggo2a120802014-10-22 12:07:00 -070081 return kFailure;
krajcevski3b570c62014-06-10 09:17:48 -070082 }
83 } else {
84 alphaType = kPremul_SkAlphaType;
85 }
86 }
87
krajcevski86bc1242014-08-07 10:58:43 -070088 // Search through the compressed formats to see if the KTX file is holding
89 // compressed data
90 bool ktxIsCompressed = false;
91 SkTextureCompressor::Format ktxCompressedFormat;
92 for (int i = 0; i < SkTextureCompressor::kFormatCnt; ++i) {
93 SkTextureCompressor::Format fmt = static_cast<SkTextureCompressor::Format>(i);
94 if (ktxFile.isCompressedFormat(fmt)) {
95 ktxIsCompressed = true;
96 ktxCompressedFormat = fmt;
97 break;
98 }
99 }
100
101 // If the compressed format is a grayscale image, then setup the bitmap properly...
102 bool isCompressedAlpha = ktxIsCompressed &&
103 ((SkTextureCompressor::kLATC_Format == ktxCompressedFormat) ||
104 (SkTextureCompressor::kR11_EAC_Format == ktxCompressedFormat));
105
106 // Set the image dimensions and underlying pixel type.
107 if (isCompressedAlpha) {
108 const int w = sampler.scaledWidth();
109 const int h = sampler.scaledHeight();
110 bm->setInfo(SkImageInfo::MakeA8(w, h));
111 } else {
112 const int w = sampler.scaledWidth();
113 const int h = sampler.scaledHeight();
114 bm->setInfo(SkImageInfo::MakeN32(w, h, alphaType));
115 }
116
krajcevski99ffe242014-06-03 13:04:35 -0700117 if (SkImageDecoder::kDecodeBounds_Mode == mode) {
scroggo2a120802014-10-22 12:07:00 -0700118 return kSuccess;
krajcevski99ffe242014-06-03 13:04:35 -0700119 }
krajcevski86bc1242014-08-07 10:58:43 -0700120
krajcevski99ffe242014-06-03 13:04:35 -0700121 // If we've made it this far, then we know how to grok the data.
halcanary96fcdcc2015-08-27 07:41:13 -0700122 if (!this->allocPixelRef(bm, nullptr)) {
scroggo2a120802014-10-22 12:07:00 -0700123 return kFailure;
krajcevski99ffe242014-06-03 13:04:35 -0700124 }
125
126 // Lock the pixels, since we're about to write to them...
127 SkAutoLockPixels alp(*bm);
128
krajcevski86bc1242014-08-07 10:58:43 -0700129 if (isCompressedAlpha) {
130 if (!sampler.begin(bm, SkScaledBitmapSampler::kGray, *this)) {
scroggo2a120802014-10-22 12:07:00 -0700131 return kFailure;
krajcevski86bc1242014-08-07 10:58:43 -0700132 }
133
134 // Alpha data is only a single byte per pixel.
135 int nPixels = width * height;
136 SkAutoMalloc outRGBData(nPixels);
137 uint8_t *outRGBDataPtr = reinterpret_cast<uint8_t *>(outRGBData.get());
138
139 // Decode the compressed format
140 const uint8_t *buf = reinterpret_cast<const uint8_t *>(ktxFile.pixelData());
141 if (!SkTextureCompressor::DecompressBufferFromFormat(
142 outRGBDataPtr, width, buf, width, height, ktxCompressedFormat)) {
scroggo2a120802014-10-22 12:07:00 -0700143 return kFailure;
krajcevski86bc1242014-08-07 10:58:43 -0700144 }
145
146 // Set each of the pixels...
147 const int srcRowBytes = width;
148 const int dstHeight = sampler.scaledHeight();
149 const uint8_t *srcRow = reinterpret_cast<uint8_t *>(outRGBDataPtr);
150 srcRow += sampler.srcY0() * srcRowBytes;
151 for (int y = 0; y < dstHeight; ++y) {
152 sampler.next(srcRow);
153 srcRow += sampler.srcDY() * srcRowBytes;
154 }
155
scroggo2a120802014-10-22 12:07:00 -0700156 return kSuccess;
krajcevski86bc1242014-08-07 10:58:43 -0700157
158 } else if (ktxFile.isCompressedFormat(SkTextureCompressor::kETC1_Format)) {
krajcevski99ffe242014-06-03 13:04:35 -0700159 if (!sampler.begin(bm, SkScaledBitmapSampler::kRGB, *this)) {
scroggo2a120802014-10-22 12:07:00 -0700160 return kFailure;
krajcevski99ffe242014-06-03 13:04:35 -0700161 }
162
163 // ETC1 Data is encoded as RGB pixels, so we should extract it as such
164 int nPixels = width * height;
165 SkAutoMalloc outRGBData(nPixels * 3);
krajcevski40a1e112014-08-05 14:13:36 -0700166 uint8_t *outRGBDataPtr = reinterpret_cast<uint8_t *>(outRGBData.get());
krajcevski99ffe242014-06-03 13:04:35 -0700167
168 // Decode ETC1
krajcevski40a1e112014-08-05 14:13:36 -0700169 const uint8_t *buf = reinterpret_cast<const uint8_t *>(ktxFile.pixelData());
170 if (!SkTextureCompressor::DecompressBufferFromFormat(
171 outRGBDataPtr, width*3, buf, width, height, SkTextureCompressor::kETC1_Format)) {
scroggo2a120802014-10-22 12:07:00 -0700172 return kFailure;
krajcevski99ffe242014-06-03 13:04:35 -0700173 }
174
175 // Set each of the pixels...
176 const int srcRowBytes = width * 3;
177 const int dstHeight = sampler.scaledHeight();
178 const uint8_t *srcRow = reinterpret_cast<uint8_t *>(outRGBDataPtr);
179 srcRow += sampler.srcY0() * srcRowBytes;
180 for (int y = 0; y < dstHeight; ++y) {
181 sampler.next(srcRow);
182 srcRow += sampler.srcDY() * srcRowBytes;
183 }
184
scroggo2a120802014-10-22 12:07:00 -0700185 return kSuccess;
krajcevski99ffe242014-06-03 13:04:35 -0700186
187 } else if (ktxFile.isRGB8()) {
188
189 // Uncompressed RGB data (without alpha)
190 if (!sampler.begin(bm, SkScaledBitmapSampler::kRGB, *this)) {
scroggo2a120802014-10-22 12:07:00 -0700191 return kFailure;
krajcevski99ffe242014-06-03 13:04:35 -0700192 }
193
194 // Just need to read RGB pixels
195 const int srcRowBytes = width * 3;
196 const int dstHeight = sampler.scaledHeight();
197 const uint8_t *srcRow = reinterpret_cast<const uint8_t *>(ktxFile.pixelData());
198 srcRow += sampler.srcY0() * srcRowBytes;
199 for (int y = 0; y < dstHeight; ++y) {
200 sampler.next(srcRow);
201 srcRow += sampler.srcDY() * srcRowBytes;
202 }
203
scroggo2a120802014-10-22 12:07:00 -0700204 return kSuccess;
krajcevski99ffe242014-06-03 13:04:35 -0700205
206 } else if (ktxFile.isRGBA8()) {
207
208 // Uncompressed RGBA data
krajcevski3b570c62014-06-10 09:17:48 -0700209
210 // If we know that the image contains premultiplied alpha, then
211 // we need to turn off the premultiplier
212 SkScaledBitmapSampler::Options opts (*this);
213 if (bSrcIsPremul) {
214 SkASSERT(bm->alphaType() == kPremul_SkAlphaType);
215 SkASSERT(!this->getRequireUnpremultipliedColors());
216
217 opts.fPremultiplyAlpha = false;
218 }
219
220 if (!sampler.begin(bm, SkScaledBitmapSampler::kRGBA, opts)) {
scroggo2a120802014-10-22 12:07:00 -0700221 return kFailure;
krajcevski99ffe242014-06-03 13:04:35 -0700222 }
223
224 // Just need to read RGBA pixels
225 const int srcRowBytes = width * 4;
226 const int dstHeight = sampler.scaledHeight();
227 const uint8_t *srcRow = reinterpret_cast<const uint8_t *>(ktxFile.pixelData());
228 srcRow += sampler.srcY0() * srcRowBytes;
229 for (int y = 0; y < dstHeight; ++y) {
230 sampler.next(srcRow);
231 srcRow += sampler.srcDY() * srcRowBytes;
232 }
233
scroggo2a120802014-10-22 12:07:00 -0700234 return kSuccess;
krajcevski99ffe242014-06-03 13:04:35 -0700235 }
236
scroggo2a120802014-10-22 12:07:00 -0700237 return kFailure;
krajcevski99ffe242014-06-03 13:04:35 -0700238}
239
krajcevskic250d2e2014-06-06 06:16:28 -0700240///////////////////////////////////////////////////////////////////////////////
241
242// KTX Image Encoder
243//
244// This encoder takes a best guess at how to encode the bitmap passed to it. If
245// there is an installed discardable pixel ref with existing PKM data, then we
246// will repurpose the existing ETC1 data into a KTX file. If the data contains
247// KTX data, then we simply return a copy of the same data. For all other files,
248// the underlying KTX library tries to do its best to encode the appropriate
249// data specified by the bitmap based on the config. (i.e. kAlpha8_Config will
250// be represented as a full resolution 8-bit image dump with the appropriate
251// OpenGL defines in the header).
252
253class SkKTXImageEncoder : public SkImageEncoder {
254protected:
mtklein36352bf2015-03-25 18:17:31 -0700255 bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality) override;
krajcevskic250d2e2014-06-06 06:16:28 -0700256
257private:
258 virtual bool encodePKM(SkWStream* stream, const SkData *data);
259 typedef SkImageEncoder INHERITED;
260};
261
262bool SkKTXImageEncoder::onEncode(SkWStream* stream, const SkBitmap& bitmap, int) {
scroggoc2dcf4a2014-07-02 15:00:07 -0700263 if (!bitmap.pixelRef()) {
264 return false;
265 }
reedc9e190d2015-09-28 09:58:41 -0700266 SkAutoDataUnref data(bitmap.pixelRef()->refEncodedData());
krajcevskic250d2e2014-06-06 06:16:28 -0700267
reedc9e190d2015-09-28 09:58:41 -0700268 // Is this even encoded data?
269 if (data) {
270 const uint8_t *bytes = data->bytes();
271 if (etc1_pkm_is_valid(bytes)) {
272 return this->encodePKM(stream, data);
krajcevskic250d2e2014-06-06 06:16:28 -0700273 }
reedc9e190d2015-09-28 09:58:41 -0700274
275 // Is it a KTX file??
276 if (SkKTXFile::is_ktx(bytes)) {
277 return stream->write(bytes, data->size());
278 }
279
280 // If it's neither a KTX nor a PKM, then we need to
281 // get at the actual pixels, so fall through and decompress...
krajcevskic250d2e2014-06-06 06:16:28 -0700282 }
reedc9e190d2015-09-28 09:58:41 -0700283
krajcevskic250d2e2014-06-06 06:16:28 -0700284 return SkKTXFile::WriteBitmapToKTX(stream, bitmap);
285}
286
287bool SkKTXImageEncoder::encodePKM(SkWStream* stream, const SkData *data) {
288 const uint8_t* bytes = data->bytes();
289 SkASSERT(etc1_pkm_is_valid(bytes));
290
291 etc1_uint32 width = etc1_pkm_get_width(bytes);
292 etc1_uint32 height = etc1_pkm_get_height(bytes);
293
294 // ETC1 Data is stored as compressed 4x4 pixel blocks, so we must make sure
295 // that our dimensions are valid.
296 if (width == 0 || (width & 3) != 0 || height == 0 || (height & 3) != 0) {
297 return false;
298 }
299
300 // Advance pointer to etc1 data.
301 bytes += ETC_PKM_HEADER_SIZE;
302
303 return SkKTXFile::WriteETC1ToKTX(stream, bytes, width, height);
304}
305
krajcevski99ffe242014-06-03 13:04:35 -0700306/////////////////////////////////////////////////////////////////////////////////////////
307DEFINE_DECODER_CREATOR(KTXImageDecoder);
krajcevskic250d2e2014-06-06 06:16:28 -0700308DEFINE_ENCODER_CREATOR(KTXImageEncoder);
krajcevski99ffe242014-06-03 13:04:35 -0700309/////////////////////////////////////////////////////////////////////////////////////////
310
311static SkImageDecoder* sk_libktx_dfactory(SkStreamRewindable* stream) {
312 if (SkKTXFile::is_ktx(stream)) {
halcanary385fe4d2015-08-26 13:07:48 -0700313 return new SkKTXImageDecoder;
krajcevski99ffe242014-06-03 13:04:35 -0700314 }
halcanary96fcdcc2015-08-27 07:41:13 -0700315 return nullptr;
krajcevski99ffe242014-06-03 13:04:35 -0700316}
317
krajcevski99ffe242014-06-03 13:04:35 -0700318static SkImageDecoder::Format get_format_ktx(SkStreamRewindable* stream) {
319 if (SkKTXFile::is_ktx(stream)) {
320 return SkImageDecoder::kKTX_Format;
321 }
322 return SkImageDecoder::kUnknown_Format;
323}
324
krajcevskic250d2e2014-06-06 06:16:28 -0700325SkImageEncoder* sk_libktx_efactory(SkImageEncoder::Type t) {
halcanary96fcdcc2015-08-27 07:41:13 -0700326 return (SkImageEncoder::kKTX_Type == t) ? new SkKTXImageEncoder : nullptr;
krajcevskic250d2e2014-06-06 06:16:28 -0700327}
328
329static SkImageDecoder_DecodeReg gReg(sk_libktx_dfactory);
krajcevski99ffe242014-06-03 13:04:35 -0700330static SkImageDecoder_FormatReg gFormatReg(get_format_ktx);
krajcevskic250d2e2014-06-06 06:16:28 -0700331static SkImageEncoder_EncodeReg gEReg(sk_libktx_efactory);
msarett8715d472016-02-17 10:02:29 -0800332
333/////////////////////////////////////////////////////////////////////////////////////////
334// Old implementation of SkImageGenerator::NewFromEncoded which uses SkImageDecoder.
335// Here because it is only needed by DM and tests for Ktx.
336class BareMemoryAllocator : public SkBitmap::Allocator {
337 const SkImageInfo fInfo;
338 void* const fMemory;
339 const size_t fRowBytes;
340
341public:
342 BareMemoryAllocator(const SkImageInfo& info, void* memory, size_t rowBytes)
343 : fInfo(info), fMemory(memory), fRowBytes(rowBytes)
344 {}
345
346protected:
347 bool allocPixelRef(SkBitmap* bm, SkColorTable* ctable) override {
348 const SkImageInfo bmi = bm->info();
349 if (bmi.width() != fInfo.width() || bmi.height() != fInfo.height() ||
350 bmi.colorType() != fInfo.colorType())
351 {
352 return false;
353 }
354 return bm->installPixels(bmi, fMemory, fRowBytes, ctable, nullptr, nullptr);
355 }
356};
357
358class SkImageDecoderGenerator : public SkImageGenerator {
359 const SkImageInfo fInfo;
360 SkAutoTDelete<SkImageDecoder> fDecoder;
361 SkAutoTUnref<SkData> fData;
362
363public:
364 SkImageDecoderGenerator(const SkImageInfo& info, SkImageDecoder* decoder, SkData* data)
365 : INHERITED(info), fInfo(info), fDecoder(decoder), fData(SkRef(data))
366 {}
367
368protected:
369 SkData* onRefEncodedData(SK_REFENCODEDDATA_CTXPARAM) override {
370 return SkRef(fData.get());
371 }
372 bool onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes,
373 SkPMColor ctableEntries[], int* ctableCount) override {
374 SkMemoryStream stream(fData->data(), fData->size(), false);
375 SkAutoTUnref<BareMemoryAllocator> allocator(
376 new BareMemoryAllocator(info, pixels, rowBytes));
377 fDecoder->setAllocator(allocator);
378 fDecoder->setRequireUnpremultipliedColors(kUnpremul_SkAlphaType == info.alphaType());
379
380 SkBitmap bm;
381 const SkImageDecoder::Result result = fDecoder->decode(&stream, &bm, info.colorType(),
382 SkImageDecoder::kDecodePixels_Mode);
383 if (SkImageDecoder::kFailure == result) {
384 return false;
385 }
386
387 SkASSERT(info.colorType() == bm.info().colorType());
388
389 if (kIndex_8_SkColorType == info.colorType()) {
390 SkASSERT(ctableEntries);
391
392 SkColorTable* ctable = bm.getColorTable();
393 if (nullptr == ctable) {
394 return false;
395 }
396 const int count = ctable->count();
397 memcpy(ctableEntries, ctable->readColors(), count * sizeof(SkPMColor));
398 *ctableCount = count;
399 }
400 return true;
401 }
402
403 bool onGetYUV8Planes(SkISize sizes[3], void* planes[3], size_t rowBytes[3],
404 SkYUVColorSpace* colorSpace) override {
405 SkMemoryStream stream(fData->data(), fData->size(), false);
406 return fDecoder->decodeYUV8Planes(&stream, sizes, planes, rowBytes, colorSpace);
407 }
408
409private:
410 typedef SkImageGenerator INHERITED;
411};
412
413SkImageGenerator* decoder_image_generator(SkData* data) {
414 SkMemoryStream stream(data->data(), data->size(), false);
415 SkImageDecoder* decoder = SkImageDecoder::Factory(&stream);
416 if (nullptr == decoder) {
417 return nullptr;
418 }
419
420 SkBitmap bm;
421 stream.rewind();
422 if (!decoder->decode(&stream, &bm, kUnknown_SkColorType, SkImageDecoder::kDecodeBounds_Mode)) {
423 delete decoder;
424 return nullptr;
425 }
426
427 return new SkImageDecoderGenerator(bm.info(), decoder, data);
428}
429