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 "SkColorPriv.h"
9#include "SkImageDecoder.h"
10#include "SkPixelRef.h"
11#include "SkScaledBitmapSampler.h"
12#include "SkStream.h"
13#include "SkStreamPriv.h"
14#include "SkTypes.h"
15
16#include "ktx.h"
17#include "etc1.h"
18
19/////////////////////////////////////////////////////////////////////////////////////////
20
21
22/////////////////////////////////////////////////////////////////////////////////////////
23
24// KTX Image decoder
25// ---
26// KTX is a general texture data storage file format ratified by the Khronos Group. As an
27// overview, a KTX file contains all of the appropriate values needed to fully specify a
28// texture in an OpenGL application, including the use of compressed data.
29//
30// This decoder is meant to be used with an SkDiscardablePixelRef so that GPU backends
31// can sniff the data before creating a texture. If they encounter a compressed format
32// that they understand, they can then upload the data directly to the GPU. Otherwise,
33// they will decode the data into a format that Skia supports.
34
35class SkKTXImageDecoder : public SkImageDecoder {
36public:
37    SkKTXImageDecoder() { }
38
39    virtual Format getFormat() const SK_OVERRIDE {
40        return kKTX_Format;
41    }
42
43protected:
44    virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode) SK_OVERRIDE;
45
46private:
47    typedef SkImageDecoder INHERITED;
48};
49
50bool SkKTXImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) {
51    // TODO: Implement SkStream::copyToData() that's cheap for memory and file streams
52    SkAutoDataUnref data(SkCopyStreamToData(stream));
53    if (NULL == data) {
54        return false;
55    }
56
57    SkKTXFile ktxFile(data);
58    if (!ktxFile.valid()) {
59        return false;
60    }
61
62    const unsigned short width = ktxFile.width();
63    const unsigned short height = ktxFile.height();
64
65#ifdef SK_SUPPORT_LEGACY_IMAGEDECODER_CHOOSER
66    // should we allow the Chooser (if present) to pick a config for us???
67    if (!this->chooseFromOneChoice(kN32_SkColorType, width, height)) {
68        return false;
69    }
70#endif
71
72    // Set a flag if our source is premultiplied alpha
73    const SkString premulKey("KTXPremultipliedAlpha");
74    const bool bSrcIsPremul = ktxFile.getValueForKey(premulKey) == SkString("True");
75
76    // Setup the sampler...
77    SkScaledBitmapSampler sampler(width, height, this->getSampleSize());
78
79    // Determine the alpha of the bitmap...
80    SkAlphaType alphaType = kOpaque_SkAlphaType;
81    if (ktxFile.isRGBA8()) {
82        if (this->getRequireUnpremultipliedColors()) {
83            alphaType = kUnpremul_SkAlphaType;
84            // If the client wants unpremul colors and we only have
85            // premul, then we cannot honor their wish.
86            if (bSrcIsPremul) {
87                return false;
88            }
89        } else {
90            alphaType = kPremul_SkAlphaType;
91        }
92    }
93
94    // Search through the compressed formats to see if the KTX file is holding
95    // compressed data
96    bool ktxIsCompressed = false;
97    SkTextureCompressor::Format ktxCompressedFormat;
98    for (int i = 0; i < SkTextureCompressor::kFormatCnt; ++i) {
99        SkTextureCompressor::Format fmt = static_cast<SkTextureCompressor::Format>(i);
100        if (ktxFile.isCompressedFormat(fmt)) {
101            ktxIsCompressed = true;
102            ktxCompressedFormat = fmt;
103            break;
104        }
105    }
106
107    // If the compressed format is a grayscale image, then setup the bitmap properly...
108    bool isCompressedAlpha = ktxIsCompressed &&
109        ((SkTextureCompressor::kLATC_Format == ktxCompressedFormat) ||
110         (SkTextureCompressor::kR11_EAC_Format == ktxCompressedFormat));
111
112    // Set the image dimensions and underlying pixel type.
113    if (isCompressedAlpha) {
114        const int w = sampler.scaledWidth();
115        const int h = sampler.scaledHeight();
116        bm->setInfo(SkImageInfo::MakeA8(w, h));
117    } else {
118        const int w = sampler.scaledWidth();
119        const int h = sampler.scaledHeight();
120        bm->setInfo(SkImageInfo::MakeN32(w, h, alphaType));
121    }
122
123    if (SkImageDecoder::kDecodeBounds_Mode == mode) {
124        return true;
125    }
126
127    // If we've made it this far, then we know how to grok the data.
128    if (!this->allocPixelRef(bm, NULL)) {
129        return false;
130    }
131
132    // Lock the pixels, since we're about to write to them...
133    SkAutoLockPixels alp(*bm);
134
135    if (isCompressedAlpha) {
136        if (!sampler.begin(bm, SkScaledBitmapSampler::kGray, *this)) {
137            return false;
138        }
139
140        // Alpha data is only a single byte per pixel.
141        int nPixels = width * height;
142        SkAutoMalloc outRGBData(nPixels);
143        uint8_t *outRGBDataPtr = reinterpret_cast<uint8_t *>(outRGBData.get());
144
145        // Decode the compressed format
146        const uint8_t *buf = reinterpret_cast<const uint8_t *>(ktxFile.pixelData());
147        if (!SkTextureCompressor::DecompressBufferFromFormat(
148                outRGBDataPtr, width, buf, width, height, ktxCompressedFormat)) {
149            return false;
150        }
151
152        // Set each of the pixels...
153        const int srcRowBytes = width;
154        const int dstHeight = sampler.scaledHeight();
155        const uint8_t *srcRow = reinterpret_cast<uint8_t *>(outRGBDataPtr);
156        srcRow += sampler.srcY0() * srcRowBytes;
157        for (int y = 0; y < dstHeight; ++y) {
158            sampler.next(srcRow);
159            srcRow += sampler.srcDY() * srcRowBytes;
160        }
161
162        return true;
163
164    } else if (ktxFile.isCompressedFormat(SkTextureCompressor::kETC1_Format)) {
165        if (!sampler.begin(bm, SkScaledBitmapSampler::kRGB, *this)) {
166            return false;
167        }
168
169        // ETC1 Data is encoded as RGB pixels, so we should extract it as such
170        int nPixels = width * height;
171        SkAutoMalloc outRGBData(nPixels * 3);
172        uint8_t *outRGBDataPtr = reinterpret_cast<uint8_t *>(outRGBData.get());
173
174        // Decode ETC1
175        const uint8_t *buf = reinterpret_cast<const uint8_t *>(ktxFile.pixelData());
176        if (!SkTextureCompressor::DecompressBufferFromFormat(
177                outRGBDataPtr, width*3, buf, width, height, SkTextureCompressor::kETC1_Format)) {
178            return false;
179        }
180
181        // Set each of the pixels...
182        const int srcRowBytes = width * 3;
183        const int dstHeight = sampler.scaledHeight();
184        const uint8_t *srcRow = reinterpret_cast<uint8_t *>(outRGBDataPtr);
185        srcRow += sampler.srcY0() * srcRowBytes;
186        for (int y = 0; y < dstHeight; ++y) {
187            sampler.next(srcRow);
188            srcRow += sampler.srcDY() * srcRowBytes;
189        }
190
191        return true;
192
193    } else if (ktxFile.isRGB8()) {
194
195        // Uncompressed RGB data (without alpha)
196        if (!sampler.begin(bm, SkScaledBitmapSampler::kRGB, *this)) {
197            return false;
198        }
199
200        // Just need to read RGB pixels
201        const int srcRowBytes = width * 3;
202        const int dstHeight = sampler.scaledHeight();
203        const uint8_t *srcRow = reinterpret_cast<const uint8_t *>(ktxFile.pixelData());
204        srcRow += sampler.srcY0() * srcRowBytes;
205        for (int y = 0; y < dstHeight; ++y) {
206            sampler.next(srcRow);
207            srcRow += sampler.srcDY() * srcRowBytes;
208        }
209
210        return true;
211
212    } else if (ktxFile.isRGBA8()) {
213
214        // Uncompressed RGBA data
215
216        // If we know that the image contains premultiplied alpha, then
217        // we need to turn off the premultiplier
218        SkScaledBitmapSampler::Options opts (*this);
219        if (bSrcIsPremul) {
220            SkASSERT(bm->alphaType() == kPremul_SkAlphaType);
221            SkASSERT(!this->getRequireUnpremultipliedColors());
222
223            opts.fPremultiplyAlpha = false;
224        }
225
226        if (!sampler.begin(bm, SkScaledBitmapSampler::kRGBA, opts)) {
227            return false;
228        }
229
230        // Just need to read RGBA pixels
231        const int srcRowBytes = width * 4;
232        const int dstHeight = sampler.scaledHeight();
233        const uint8_t *srcRow = reinterpret_cast<const uint8_t *>(ktxFile.pixelData());
234        srcRow += sampler.srcY0() * srcRowBytes;
235        for (int y = 0; y < dstHeight; ++y) {
236            sampler.next(srcRow);
237            srcRow += sampler.srcDY() * srcRowBytes;
238        }
239
240        return true;
241    }
242
243    return false;
244}
245
246///////////////////////////////////////////////////////////////////////////////
247
248// KTX Image Encoder
249//
250// This encoder takes a best guess at how to encode the bitmap passed to it. If
251// there is an installed discardable pixel ref with existing PKM data, then we
252// will repurpose the existing ETC1 data into a KTX file. If the data contains
253// KTX data, then we simply return a copy of the same data. For all other files,
254// the underlying KTX library tries to do its best to encode the appropriate
255// data specified by the bitmap based on the config. (i.e. kAlpha8_Config will
256// be represented as a full resolution 8-bit image dump with the appropriate
257// OpenGL defines in the header).
258
259class SkKTXImageEncoder : public SkImageEncoder {
260protected:
261    virtual bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality) SK_OVERRIDE;
262
263private:
264    virtual bool encodePKM(SkWStream* stream, const SkData *data);
265    typedef SkImageEncoder INHERITED;
266};
267
268bool SkKTXImageEncoder::onEncode(SkWStream* stream, const SkBitmap& bitmap, int) {
269    if (!bitmap.pixelRef()) {
270        return false;
271    }
272    SkAutoDataUnref data(bitmap.pixelRef()->refEncodedData());
273
274    // Is this even encoded data?
275    if (data) {
276        const uint8_t *bytes = data->bytes();
277        if (etc1_pkm_is_valid(bytes)) {
278            return this->encodePKM(stream, data);
279        }
280
281        // Is it a KTX file??
282        if (SkKTXFile::is_ktx(bytes)) {
283            return stream->write(bytes, data->size());
284        }
285
286        // If it's neither a KTX nor a PKM, then we need to
287        // get at the actual pixels, so fall through and decompress...
288    }
289
290    return SkKTXFile::WriteBitmapToKTX(stream, bitmap);
291}
292
293bool SkKTXImageEncoder::encodePKM(SkWStream* stream, const SkData *data) {
294    const uint8_t* bytes = data->bytes();
295    SkASSERT(etc1_pkm_is_valid(bytes));
296
297    etc1_uint32 width = etc1_pkm_get_width(bytes);
298    etc1_uint32 height = etc1_pkm_get_height(bytes);
299
300    // ETC1 Data is stored as compressed 4x4 pixel blocks, so we must make sure
301    // that our dimensions are valid.
302    if (width == 0 || (width & 3) != 0 || height == 0 || (height & 3) != 0) {
303        return false;
304    }
305
306    // Advance pointer to etc1 data.
307    bytes += ETC_PKM_HEADER_SIZE;
308
309    return SkKTXFile::WriteETC1ToKTX(stream, bytes, width, height);
310}
311
312/////////////////////////////////////////////////////////////////////////////////////////
313DEFINE_DECODER_CREATOR(KTXImageDecoder);
314DEFINE_ENCODER_CREATOR(KTXImageEncoder);
315/////////////////////////////////////////////////////////////////////////////////////////
316
317static SkImageDecoder* sk_libktx_dfactory(SkStreamRewindable* stream) {
318    if (SkKTXFile::is_ktx(stream)) {
319        return SkNEW(SkKTXImageDecoder);
320    }
321    return NULL;
322}
323
324static SkImageDecoder::Format get_format_ktx(SkStreamRewindable* stream) {
325    if (SkKTXFile::is_ktx(stream)) {
326        return SkImageDecoder::kKTX_Format;
327    }
328    return SkImageDecoder::kUnknown_Format;
329}
330
331SkImageEncoder* sk_libktx_efactory(SkImageEncoder::Type t) {
332    return (SkImageEncoder::kKTX_Type == t) ? SkNEW(SkKTXImageEncoder) : NULL;
333}
334
335static SkImageDecoder_DecodeReg gReg(sk_libktx_dfactory);
336static SkImageDecoder_FormatReg gFormatReg(get_format_ktx);
337static SkImageEncoder_EncodeReg gEReg(sk_libktx_efactory);
338