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 35 class SkKTXImageDecoder : public SkImageDecoder { 36 public: 37 SkKTXImageDecoder() { } 38 39 virtual Format getFormat() const SK_OVERRIDE { 40 return kKTX_Format; 41 } 42 43 protected: 44 virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode) SK_OVERRIDE; 45 46 private: 47 typedef SkImageDecoder INHERITED; 48 }; 49 50 bool 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 259 class SkKTXImageEncoder : public SkImageEncoder { 260 protected: 261 virtual bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality) SK_OVERRIDE; 262 263 private: 264 virtual bool encodePKM(SkWStream* stream, const SkData *data); 265 typedef SkImageEncoder INHERITED; 266 }; 267 268 bool 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 293 bool 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 ///////////////////////////////////////////////////////////////////////////////////////// 313 DEFINE_DECODER_CREATOR(KTXImageDecoder); 314 DEFINE_ENCODER_CREATOR(KTXImageEncoder); 315 ///////////////////////////////////////////////////////////////////////////////////////// 316 317 static SkImageDecoder* sk_libktx_dfactory(SkStreamRewindable* stream) { 318 if (SkKTXFile::is_ktx(stream)) { 319 return SkNEW(SkKTXImageDecoder); 320 } 321 return NULL; 322 } 323 324 static 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 331 SkImageEncoder* sk_libktx_efactory(SkImageEncoder::Type t) { 332 return (SkImageEncoder::kKTX_Type == t) ? SkNEW(SkKTXImageEncoder) : NULL; 333 } 334 335 static SkImageDecoder_DecodeReg gReg(sk_libktx_dfactory); 336 static SkImageDecoder_FormatReg gFormatReg(get_format_ktx); 337 static SkImageEncoder_EncodeReg gEReg(sk_libktx_efactory); 338