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