199ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski/*
299ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski * Copyright 2014 Google Inc.
399ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski *
499ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski * Use of this source code is governed by a BSD-style license that can be
599ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski * found in the LICENSE file.
699ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski */
799ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski
899ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski#include "SkColorPriv.h"
999ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski#include "SkImageDecoder.h"
10c250d2e4abdbe8193357696518592af8a0b4555akrajcevski#include "SkPixelRef.h"
1199ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski#include "SkScaledBitmapSampler.h"
1299ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski#include "SkStream.h"
1367ec1f8eecfb48bc0a6ba04c0057f103c1c9696fhalcanary#include "SkStreamPriv.h"
1499ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski#include "SkTypes.h"
1599ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski
1699ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski#include "ktx.h"
1799ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski#include "etc1.h"
1899ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski
1999ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski/////////////////////////////////////////////////////////////////////////////////////////
2099ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski
2199ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski
2299ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski/////////////////////////////////////////////////////////////////////////////////////////
2399ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski
2499ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski// KTX Image decoder
2599ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski// ---
2699ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski// KTX is a general texture data storage file format ratified by the Khronos Group. As an
2799ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski// overview, a KTX file contains all of the appropriate values needed to fully specify a
2899ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski// texture in an OpenGL application, including the use of compressed data.
2999ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski//
3099ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski// This decoder is meant to be used with an SkDiscardablePixelRef so that GPU backends
3199ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski// can sniff the data before creating a texture. If they encounter a compressed format
3299ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski// that they understand, they can then upload the data directly to the GPU. Otherwise,
3399ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski// they will decode the data into a format that Skia supports.
3499ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski
3599ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevskiclass SkKTXImageDecoder : public SkImageDecoder {
3699ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevskipublic:
3799ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski    SkKTXImageDecoder() { }
3899ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski
3999ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski    virtual Format getFormat() const SK_OVERRIDE {
4099ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski        return kKTX_Format;
4199ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski    }
4299ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski
4399ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevskiprotected:
4499ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski    virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode) SK_OVERRIDE;
4599ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski
4699ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevskiprivate:
4799ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski    typedef SkImageDecoder INHERITED;
4899ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski};
4999ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski
5099ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevskibool SkKTXImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) {
5199ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski    // TODO: Implement SkStream::copyToData() that's cheap for memory and file streams
5267ec1f8eecfb48bc0a6ba04c0057f103c1c9696fhalcanary    SkAutoDataUnref data(SkCopyStreamToData(stream));
5399ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski    if (NULL == data) {
5499ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski        return false;
5599ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski    }
5699ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski
5799ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski    SkKTXFile ktxFile(data);
5899ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski    if (!ktxFile.valid()) {
5999ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski        return false;
6099ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski    }
6199ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski
6299ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski    const unsigned short width = ktxFile.width();
6399ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski    const unsigned short height = ktxFile.height();
6499ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski
655926b86b90c68bffefbdc8639e41b5bc9102cec6reed#ifdef SK_SUPPORT_LEGACY_IMAGEDECODER_CHOOSER
6699ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski    // should we allow the Chooser (if present) to pick a config for us???
676c22573edb234ad14df947278cfed010669a39a7reed    if (!this->chooseFromOneChoice(kN32_SkColorType, width, height)) {
6899ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski        return false;
6999ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski    }
705926b86b90c68bffefbdc8639e41b5bc9102cec6reed#endif
7199ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski
723b570c6b023c5556613f435400798d5df37a78e3krajcevski    // Set a flag if our source is premultiplied alpha
733b570c6b023c5556613f435400798d5df37a78e3krajcevski    const SkString premulKey("KTXPremultipliedAlpha");
743b570c6b023c5556613f435400798d5df37a78e3krajcevski    const bool bSrcIsPremul = ktxFile.getValueForKey(premulKey) == SkString("True");
753b570c6b023c5556613f435400798d5df37a78e3krajcevski
7699ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski    // Setup the sampler...
7799ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski    SkScaledBitmapSampler sampler(width, height, this->getSampleSize());
7899ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski
793b570c6b023c5556613f435400798d5df37a78e3krajcevski    // Determine the alpha of the bitmap...
803b570c6b023c5556613f435400798d5df37a78e3krajcevski    SkAlphaType alphaType = kOpaque_SkAlphaType;
813b570c6b023c5556613f435400798d5df37a78e3krajcevski    if (ktxFile.isRGBA8()) {
823b570c6b023c5556613f435400798d5df37a78e3krajcevski        if (this->getRequireUnpremultipliedColors()) {
833b570c6b023c5556613f435400798d5df37a78e3krajcevski            alphaType = kUnpremul_SkAlphaType;
843b570c6b023c5556613f435400798d5df37a78e3krajcevski            // If the client wants unpremul colors and we only have
853b570c6b023c5556613f435400798d5df37a78e3krajcevski            // premul, then we cannot honor their wish.
863b570c6b023c5556613f435400798d5df37a78e3krajcevski            if (bSrcIsPremul) {
873b570c6b023c5556613f435400798d5df37a78e3krajcevski                return false;
883b570c6b023c5556613f435400798d5df37a78e3krajcevski            }
893b570c6b023c5556613f435400798d5df37a78e3krajcevski        } else {
903b570c6b023c5556613f435400798d5df37a78e3krajcevski            alphaType = kPremul_SkAlphaType;
913b570c6b023c5556613f435400798d5df37a78e3krajcevski        }
923b570c6b023c5556613f435400798d5df37a78e3krajcevski    }
933b570c6b023c5556613f435400798d5df37a78e3krajcevski
9486bc1247d28c59f29eaf0df75c06636cab4f7d37krajcevski    // Search through the compressed formats to see if the KTX file is holding
9586bc1247d28c59f29eaf0df75c06636cab4f7d37krajcevski    // compressed data
9686bc1247d28c59f29eaf0df75c06636cab4f7d37krajcevski    bool ktxIsCompressed = false;
9786bc1247d28c59f29eaf0df75c06636cab4f7d37krajcevski    SkTextureCompressor::Format ktxCompressedFormat;
9886bc1247d28c59f29eaf0df75c06636cab4f7d37krajcevski    for (int i = 0; i < SkTextureCompressor::kFormatCnt; ++i) {
9986bc1247d28c59f29eaf0df75c06636cab4f7d37krajcevski        SkTextureCompressor::Format fmt = static_cast<SkTextureCompressor::Format>(i);
10086bc1247d28c59f29eaf0df75c06636cab4f7d37krajcevski        if (ktxFile.isCompressedFormat(fmt)) {
10186bc1247d28c59f29eaf0df75c06636cab4f7d37krajcevski            ktxIsCompressed = true;
10286bc1247d28c59f29eaf0df75c06636cab4f7d37krajcevski            ktxCompressedFormat = fmt;
10386bc1247d28c59f29eaf0df75c06636cab4f7d37krajcevski            break;
10486bc1247d28c59f29eaf0df75c06636cab4f7d37krajcevski        }
10586bc1247d28c59f29eaf0df75c06636cab4f7d37krajcevski    }
10686bc1247d28c59f29eaf0df75c06636cab4f7d37krajcevski
10786bc1247d28c59f29eaf0df75c06636cab4f7d37krajcevski    // If the compressed format is a grayscale image, then setup the bitmap properly...
10886bc1247d28c59f29eaf0df75c06636cab4f7d37krajcevski    bool isCompressedAlpha = ktxIsCompressed &&
10986bc1247d28c59f29eaf0df75c06636cab4f7d37krajcevski        ((SkTextureCompressor::kLATC_Format == ktxCompressedFormat) ||
11086bc1247d28c59f29eaf0df75c06636cab4f7d37krajcevski         (SkTextureCompressor::kR11_EAC_Format == ktxCompressedFormat));
11186bc1247d28c59f29eaf0df75c06636cab4f7d37krajcevski
11286bc1247d28c59f29eaf0df75c06636cab4f7d37krajcevski    // Set the image dimensions and underlying pixel type.
11386bc1247d28c59f29eaf0df75c06636cab4f7d37krajcevski    if (isCompressedAlpha) {
11486bc1247d28c59f29eaf0df75c06636cab4f7d37krajcevski        const int w = sampler.scaledWidth();
11586bc1247d28c59f29eaf0df75c06636cab4f7d37krajcevski        const int h = sampler.scaledHeight();
11686bc1247d28c59f29eaf0df75c06636cab4f7d37krajcevski        bm->setInfo(SkImageInfo::MakeA8(w, h));
11786bc1247d28c59f29eaf0df75c06636cab4f7d37krajcevski    } else {
11886bc1247d28c59f29eaf0df75c06636cab4f7d37krajcevski        const int w = sampler.scaledWidth();
11986bc1247d28c59f29eaf0df75c06636cab4f7d37krajcevski        const int h = sampler.scaledHeight();
12086bc1247d28c59f29eaf0df75c06636cab4f7d37krajcevski        bm->setInfo(SkImageInfo::MakeN32(w, h, alphaType));
12186bc1247d28c59f29eaf0df75c06636cab4f7d37krajcevski    }
12286bc1247d28c59f29eaf0df75c06636cab4f7d37krajcevski
12399ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski    if (SkImageDecoder::kDecodeBounds_Mode == mode) {
12499ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski        return true;
12599ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski    }
12686bc1247d28c59f29eaf0df75c06636cab4f7d37krajcevski
12799ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski    // If we've made it this far, then we know how to grok the data.
12899ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski    if (!this->allocPixelRef(bm, NULL)) {
12999ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski        return false;
13099ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski    }
13199ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski
13299ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski    // Lock the pixels, since we're about to write to them...
13399ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski    SkAutoLockPixels alp(*bm);
13499ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski
13586bc1247d28c59f29eaf0df75c06636cab4f7d37krajcevski    if (isCompressedAlpha) {
13686bc1247d28c59f29eaf0df75c06636cab4f7d37krajcevski        if (!sampler.begin(bm, SkScaledBitmapSampler::kGray, *this)) {
13786bc1247d28c59f29eaf0df75c06636cab4f7d37krajcevski            return false;
13886bc1247d28c59f29eaf0df75c06636cab4f7d37krajcevski        }
13986bc1247d28c59f29eaf0df75c06636cab4f7d37krajcevski
14086bc1247d28c59f29eaf0df75c06636cab4f7d37krajcevski        // Alpha data is only a single byte per pixel.
14186bc1247d28c59f29eaf0df75c06636cab4f7d37krajcevski        int nPixels = width * height;
14286bc1247d28c59f29eaf0df75c06636cab4f7d37krajcevski        SkAutoMalloc outRGBData(nPixels);
14386bc1247d28c59f29eaf0df75c06636cab4f7d37krajcevski        uint8_t *outRGBDataPtr = reinterpret_cast<uint8_t *>(outRGBData.get());
14486bc1247d28c59f29eaf0df75c06636cab4f7d37krajcevski
14586bc1247d28c59f29eaf0df75c06636cab4f7d37krajcevski        // Decode the compressed format
14686bc1247d28c59f29eaf0df75c06636cab4f7d37krajcevski        const uint8_t *buf = reinterpret_cast<const uint8_t *>(ktxFile.pixelData());
14786bc1247d28c59f29eaf0df75c06636cab4f7d37krajcevski        if (!SkTextureCompressor::DecompressBufferFromFormat(
14886bc1247d28c59f29eaf0df75c06636cab4f7d37krajcevski                outRGBDataPtr, width, buf, width, height, ktxCompressedFormat)) {
14986bc1247d28c59f29eaf0df75c06636cab4f7d37krajcevski            return false;
15086bc1247d28c59f29eaf0df75c06636cab4f7d37krajcevski        }
15186bc1247d28c59f29eaf0df75c06636cab4f7d37krajcevski
15286bc1247d28c59f29eaf0df75c06636cab4f7d37krajcevski        // Set each of the pixels...
15386bc1247d28c59f29eaf0df75c06636cab4f7d37krajcevski        const int srcRowBytes = width;
15486bc1247d28c59f29eaf0df75c06636cab4f7d37krajcevski        const int dstHeight = sampler.scaledHeight();
15586bc1247d28c59f29eaf0df75c06636cab4f7d37krajcevski        const uint8_t *srcRow = reinterpret_cast<uint8_t *>(outRGBDataPtr);
15686bc1247d28c59f29eaf0df75c06636cab4f7d37krajcevski        srcRow += sampler.srcY0() * srcRowBytes;
15786bc1247d28c59f29eaf0df75c06636cab4f7d37krajcevski        for (int y = 0; y < dstHeight; ++y) {
15886bc1247d28c59f29eaf0df75c06636cab4f7d37krajcevski            sampler.next(srcRow);
15986bc1247d28c59f29eaf0df75c06636cab4f7d37krajcevski            srcRow += sampler.srcDY() * srcRowBytes;
16086bc1247d28c59f29eaf0df75c06636cab4f7d37krajcevski        }
16186bc1247d28c59f29eaf0df75c06636cab4f7d37krajcevski
16286bc1247d28c59f29eaf0df75c06636cab4f7d37krajcevski        return true;
16386bc1247d28c59f29eaf0df75c06636cab4f7d37krajcevski
16486bc1247d28c59f29eaf0df75c06636cab4f7d37krajcevski    } else if (ktxFile.isCompressedFormat(SkTextureCompressor::kETC1_Format)) {
16599ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski        if (!sampler.begin(bm, SkScaledBitmapSampler::kRGB, *this)) {
16699ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski            return false;
16799ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski        }
16899ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski
16999ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski        // ETC1 Data is encoded as RGB pixels, so we should extract it as such
17099ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski        int nPixels = width * height;
17199ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski        SkAutoMalloc outRGBData(nPixels * 3);
17240a1e11ebebe81586f3fec96408fdfd4b51123d2krajcevski        uint8_t *outRGBDataPtr = reinterpret_cast<uint8_t *>(outRGBData.get());
17399ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski
17499ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski        // Decode ETC1
17540a1e11ebebe81586f3fec96408fdfd4b51123d2krajcevski        const uint8_t *buf = reinterpret_cast<const uint8_t *>(ktxFile.pixelData());
17640a1e11ebebe81586f3fec96408fdfd4b51123d2krajcevski        if (!SkTextureCompressor::DecompressBufferFromFormat(
17740a1e11ebebe81586f3fec96408fdfd4b51123d2krajcevski                outRGBDataPtr, width*3, buf, width, height, SkTextureCompressor::kETC1_Format)) {
17899ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski            return false;
17999ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski        }
18099ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski
18199ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski        // Set each of the pixels...
18299ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski        const int srcRowBytes = width * 3;
18399ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski        const int dstHeight = sampler.scaledHeight();
18499ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski        const uint8_t *srcRow = reinterpret_cast<uint8_t *>(outRGBDataPtr);
18599ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski        srcRow += sampler.srcY0() * srcRowBytes;
18699ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski        for (int y = 0; y < dstHeight; ++y) {
18799ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski            sampler.next(srcRow);
18899ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski            srcRow += sampler.srcDY() * srcRowBytes;
18999ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski        }
19099ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski
19199ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski        return true;
19299ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski
19399ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski    } else if (ktxFile.isRGB8()) {
19499ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski
19599ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski        // Uncompressed RGB data (without alpha)
19699ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski        if (!sampler.begin(bm, SkScaledBitmapSampler::kRGB, *this)) {
19799ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski            return false;
19899ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski        }
19999ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski
20099ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski        // Just need to read RGB pixels
20199ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski        const int srcRowBytes = width * 3;
20299ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski        const int dstHeight = sampler.scaledHeight();
20399ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski        const uint8_t *srcRow = reinterpret_cast<const uint8_t *>(ktxFile.pixelData());
20499ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski        srcRow += sampler.srcY0() * srcRowBytes;
20599ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski        for (int y = 0; y < dstHeight; ++y) {
20699ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski            sampler.next(srcRow);
20799ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski            srcRow += sampler.srcDY() * srcRowBytes;
20899ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski        }
20999ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski
21099ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski        return true;
21199ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski
21299ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski    } else if (ktxFile.isRGBA8()) {
21399ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski
2143b570c6b023c5556613f435400798d5df37a78e3krajcevski        // Uncompressed RGBA data
2153b570c6b023c5556613f435400798d5df37a78e3krajcevski
216c250d2e4abdbe8193357696518592af8a0b4555akrajcevski        // If we know that the image contains premultiplied alpha, then
2173b570c6b023c5556613f435400798d5df37a78e3krajcevski        // we need to turn off the premultiplier
2183b570c6b023c5556613f435400798d5df37a78e3krajcevski        SkScaledBitmapSampler::Options opts (*this);
2193b570c6b023c5556613f435400798d5df37a78e3krajcevski        if (bSrcIsPremul) {
2203b570c6b023c5556613f435400798d5df37a78e3krajcevski            SkASSERT(bm->alphaType() == kPremul_SkAlphaType);
2213b570c6b023c5556613f435400798d5df37a78e3krajcevski            SkASSERT(!this->getRequireUnpremultipliedColors());
222c250d2e4abdbe8193357696518592af8a0b4555akrajcevski
2233b570c6b023c5556613f435400798d5df37a78e3krajcevski            opts.fPremultiplyAlpha = false;
2243b570c6b023c5556613f435400798d5df37a78e3krajcevski        }
2253b570c6b023c5556613f435400798d5df37a78e3krajcevski
2263b570c6b023c5556613f435400798d5df37a78e3krajcevski        if (!sampler.begin(bm, SkScaledBitmapSampler::kRGBA, opts)) {
22799ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski            return false;
22899ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski        }
22999ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski
23099ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski        // Just need to read RGBA pixels
23199ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski        const int srcRowBytes = width * 4;
23299ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski        const int dstHeight = sampler.scaledHeight();
23399ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski        const uint8_t *srcRow = reinterpret_cast<const uint8_t *>(ktxFile.pixelData());
23499ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski        srcRow += sampler.srcY0() * srcRowBytes;
23599ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski        for (int y = 0; y < dstHeight; ++y) {
23699ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski            sampler.next(srcRow);
23799ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski            srcRow += sampler.srcDY() * srcRowBytes;
23899ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski        }
23999ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski
24099ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski        return true;
24199ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski    }
24299ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski
24399ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski    return false;
24499ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski}
24599ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski
246c250d2e4abdbe8193357696518592af8a0b4555akrajcevski///////////////////////////////////////////////////////////////////////////////
247c250d2e4abdbe8193357696518592af8a0b4555akrajcevski
248c250d2e4abdbe8193357696518592af8a0b4555akrajcevski// KTX Image Encoder
249c250d2e4abdbe8193357696518592af8a0b4555akrajcevski//
250c250d2e4abdbe8193357696518592af8a0b4555akrajcevski// This encoder takes a best guess at how to encode the bitmap passed to it. If
251c250d2e4abdbe8193357696518592af8a0b4555akrajcevski// there is an installed discardable pixel ref with existing PKM data, then we
252c250d2e4abdbe8193357696518592af8a0b4555akrajcevski// will repurpose the existing ETC1 data into a KTX file. If the data contains
253c250d2e4abdbe8193357696518592af8a0b4555akrajcevski// KTX data, then we simply return a copy of the same data. For all other files,
254c250d2e4abdbe8193357696518592af8a0b4555akrajcevski// the underlying KTX library tries to do its best to encode the appropriate
255c250d2e4abdbe8193357696518592af8a0b4555akrajcevski// data specified by the bitmap based on the config. (i.e. kAlpha8_Config will
256c250d2e4abdbe8193357696518592af8a0b4555akrajcevski// be represented as a full resolution 8-bit image dump with the appropriate
257c250d2e4abdbe8193357696518592af8a0b4555akrajcevski// OpenGL defines in the header).
258c250d2e4abdbe8193357696518592af8a0b4555akrajcevski
259c250d2e4abdbe8193357696518592af8a0b4555akrajcevskiclass SkKTXImageEncoder : public SkImageEncoder {
260c250d2e4abdbe8193357696518592af8a0b4555akrajcevskiprotected:
261c250d2e4abdbe8193357696518592af8a0b4555akrajcevski    virtual bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality) SK_OVERRIDE;
262c250d2e4abdbe8193357696518592af8a0b4555akrajcevski
263c250d2e4abdbe8193357696518592af8a0b4555akrajcevskiprivate:
264c250d2e4abdbe8193357696518592af8a0b4555akrajcevski    virtual bool encodePKM(SkWStream* stream, const SkData *data);
265c250d2e4abdbe8193357696518592af8a0b4555akrajcevski    typedef SkImageEncoder INHERITED;
266c250d2e4abdbe8193357696518592af8a0b4555akrajcevski};
267c250d2e4abdbe8193357696518592af8a0b4555akrajcevski
268c250d2e4abdbe8193357696518592af8a0b4555akrajcevskibool SkKTXImageEncoder::onEncode(SkWStream* stream, const SkBitmap& bitmap, int) {
269c2dcf4a4a56027fd9129c1f170b79fb1af63011fscroggo    if (!bitmap.pixelRef()) {
270c2dcf4a4a56027fd9129c1f170b79fb1af63011fscroggo        return false;
271c2dcf4a4a56027fd9129c1f170b79fb1af63011fscroggo    }
272c250d2e4abdbe8193357696518592af8a0b4555akrajcevski    SkAutoDataUnref data(bitmap.pixelRef()->refEncodedData());
273c250d2e4abdbe8193357696518592af8a0b4555akrajcevski
274c250d2e4abdbe8193357696518592af8a0b4555akrajcevski    // Is this even encoded data?
27549f085dddff10473b6ebf832a974288300224e60bsalomon    if (data) {
276c250d2e4abdbe8193357696518592af8a0b4555akrajcevski        const uint8_t *bytes = data->bytes();
277c250d2e4abdbe8193357696518592af8a0b4555akrajcevski        if (etc1_pkm_is_valid(bytes)) {
278c250d2e4abdbe8193357696518592af8a0b4555akrajcevski            return this->encodePKM(stream, data);
279c250d2e4abdbe8193357696518592af8a0b4555akrajcevski        }
280c250d2e4abdbe8193357696518592af8a0b4555akrajcevski
281c250d2e4abdbe8193357696518592af8a0b4555akrajcevski        // Is it a KTX file??
282c250d2e4abdbe8193357696518592af8a0b4555akrajcevski        if (SkKTXFile::is_ktx(bytes)) {
283c250d2e4abdbe8193357696518592af8a0b4555akrajcevski            return stream->write(bytes, data->size());
284c250d2e4abdbe8193357696518592af8a0b4555akrajcevski        }
285c250d2e4abdbe8193357696518592af8a0b4555akrajcevski
286c250d2e4abdbe8193357696518592af8a0b4555akrajcevski        // If it's neither a KTX nor a PKM, then we need to
287c250d2e4abdbe8193357696518592af8a0b4555akrajcevski        // get at the actual pixels, so fall through and decompress...
288c250d2e4abdbe8193357696518592af8a0b4555akrajcevski    }
289c250d2e4abdbe8193357696518592af8a0b4555akrajcevski
290c250d2e4abdbe8193357696518592af8a0b4555akrajcevski    return SkKTXFile::WriteBitmapToKTX(stream, bitmap);
291c250d2e4abdbe8193357696518592af8a0b4555akrajcevski}
292c250d2e4abdbe8193357696518592af8a0b4555akrajcevski
293c250d2e4abdbe8193357696518592af8a0b4555akrajcevskibool SkKTXImageEncoder::encodePKM(SkWStream* stream, const SkData *data) {
294c250d2e4abdbe8193357696518592af8a0b4555akrajcevski    const uint8_t* bytes = data->bytes();
295c250d2e4abdbe8193357696518592af8a0b4555akrajcevski    SkASSERT(etc1_pkm_is_valid(bytes));
296c250d2e4abdbe8193357696518592af8a0b4555akrajcevski
297c250d2e4abdbe8193357696518592af8a0b4555akrajcevski    etc1_uint32 width = etc1_pkm_get_width(bytes);
298c250d2e4abdbe8193357696518592af8a0b4555akrajcevski    etc1_uint32 height = etc1_pkm_get_height(bytes);
299c250d2e4abdbe8193357696518592af8a0b4555akrajcevski
300c250d2e4abdbe8193357696518592af8a0b4555akrajcevski    // ETC1 Data is stored as compressed 4x4 pixel blocks, so we must make sure
301c250d2e4abdbe8193357696518592af8a0b4555akrajcevski    // that our dimensions are valid.
302c250d2e4abdbe8193357696518592af8a0b4555akrajcevski    if (width == 0 || (width & 3) != 0 || height == 0 || (height & 3) != 0) {
303c250d2e4abdbe8193357696518592af8a0b4555akrajcevski        return false;
304c250d2e4abdbe8193357696518592af8a0b4555akrajcevski    }
305c250d2e4abdbe8193357696518592af8a0b4555akrajcevski
306c250d2e4abdbe8193357696518592af8a0b4555akrajcevski    // Advance pointer to etc1 data.
307c250d2e4abdbe8193357696518592af8a0b4555akrajcevski    bytes += ETC_PKM_HEADER_SIZE;
308c250d2e4abdbe8193357696518592af8a0b4555akrajcevski
309c250d2e4abdbe8193357696518592af8a0b4555akrajcevski    return SkKTXFile::WriteETC1ToKTX(stream, bytes, width, height);
310c250d2e4abdbe8193357696518592af8a0b4555akrajcevski}
311c250d2e4abdbe8193357696518592af8a0b4555akrajcevski
31299ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski/////////////////////////////////////////////////////////////////////////////////////////
31399ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevskiDEFINE_DECODER_CREATOR(KTXImageDecoder);
314c250d2e4abdbe8193357696518592af8a0b4555akrajcevskiDEFINE_ENCODER_CREATOR(KTXImageEncoder);
31599ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski/////////////////////////////////////////////////////////////////////////////////////////
31699ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski
31799ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevskistatic SkImageDecoder* sk_libktx_dfactory(SkStreamRewindable* stream) {
31899ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski    if (SkKTXFile::is_ktx(stream)) {
31999ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski        return SkNEW(SkKTXImageDecoder);
32099ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski    }
32199ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski    return NULL;
32299ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski}
32399ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski
32499ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevskistatic SkImageDecoder::Format get_format_ktx(SkStreamRewindable* stream) {
32599ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski    if (SkKTXFile::is_ktx(stream)) {
32699ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski        return SkImageDecoder::kKTX_Format;
32799ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski    }
32899ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski    return SkImageDecoder::kUnknown_Format;
32999ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski}
33099ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski
331c250d2e4abdbe8193357696518592af8a0b4555akrajcevskiSkImageEncoder* sk_libktx_efactory(SkImageEncoder::Type t) {
332c250d2e4abdbe8193357696518592af8a0b4555akrajcevski    return (SkImageEncoder::kKTX_Type == t) ? SkNEW(SkKTXImageEncoder) : NULL;
333c250d2e4abdbe8193357696518592af8a0b4555akrajcevski}
334c250d2e4abdbe8193357696518592af8a0b4555akrajcevski
335c250d2e4abdbe8193357696518592af8a0b4555akrajcevskistatic SkImageDecoder_DecodeReg gReg(sk_libktx_dfactory);
33699ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevskistatic SkImageDecoder_FormatReg gFormatReg(get_format_ktx);
337c250d2e4abdbe8193357696518592af8a0b4555akrajcevskistatic SkImageEncoder_EncodeReg gEReg(sk_libktx_efactory);
338