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 "SkData.h" 9 #include "SkEndian.h" 10 #include "SkColorPriv.h" 11 #include "SkImageDecoder.h" 12 #include "SkScaledBitmapSampler.h" 13 #include "SkStream.h" 14 #include "SkStreamPriv.h" 15 #include "SkTypes.h" 16 17 #include "SkTextureCompressor.h" 18 19 class SkASTCImageDecoder : public SkImageDecoder { 20 public: 21 SkASTCImageDecoder() { } 22 23 Format getFormat() const override { 24 return kASTC_Format; 25 } 26 27 protected: 28 Result onDecode(SkStream* stream, SkBitmap* bm, Mode) override; 29 30 private: 31 typedef SkImageDecoder INHERITED; 32 }; 33 34 ///////////////////////////////////////////////////////////////////////////////////////// 35 36 static const uint32_t kASTCMagicNumber = 0x5CA1AB13; 37 38 static inline int read_24bit(const uint8_t* buf) { 39 // Assume everything is little endian... 40 return 41 static_cast<int>(buf[0]) | 42 (static_cast<int>(buf[1]) << 8) | 43 (static_cast<int>(buf[2]) << 16); 44 } 45 46 SkImageDecoder::Result SkASTCImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) { 47 SkAutoTUnref<SkData> data(SkCopyStreamToData(stream)); 48 if (!data || !data->size()) { 49 return kFailure; 50 } 51 52 unsigned char* buf = (unsigned char*) data->data(); 53 54 // Make sure that the magic header is there... 55 SkASSERT(SkEndian_SwapLE32(*(reinterpret_cast<uint32_t*>(buf))) == kASTCMagicNumber); 56 57 // Advance past the magic header 58 buf += 4; 59 60 const int blockDimX = buf[0]; 61 const int blockDimY = buf[1]; 62 const int blockDimZ = buf[2]; 63 64 if (1 != blockDimZ) { 65 // We don't support decoding 3D 66 return kFailure; 67 } 68 69 // Choose the proper ASTC format 70 SkTextureCompressor::Format astcFormat; 71 if (4 == blockDimX && 4 == blockDimY) { 72 astcFormat = SkTextureCompressor::kASTC_4x4_Format; 73 } else if (5 == blockDimX && 4 == blockDimY) { 74 astcFormat = SkTextureCompressor::kASTC_5x4_Format; 75 } else if (5 == blockDimX && 5 == blockDimY) { 76 astcFormat = SkTextureCompressor::kASTC_5x5_Format; 77 } else if (6 == blockDimX && 5 == blockDimY) { 78 astcFormat = SkTextureCompressor::kASTC_6x5_Format; 79 } else if (6 == blockDimX && 6 == blockDimY) { 80 astcFormat = SkTextureCompressor::kASTC_6x6_Format; 81 } else if (8 == blockDimX && 5 == blockDimY) { 82 astcFormat = SkTextureCompressor::kASTC_8x5_Format; 83 } else if (8 == blockDimX && 6 == blockDimY) { 84 astcFormat = SkTextureCompressor::kASTC_8x6_Format; 85 } else if (8 == blockDimX && 8 == blockDimY) { 86 astcFormat = SkTextureCompressor::kASTC_8x8_Format; 87 } else if (10 == blockDimX && 5 == blockDimY) { 88 astcFormat = SkTextureCompressor::kASTC_10x5_Format; 89 } else if (10 == blockDimX && 6 == blockDimY) { 90 astcFormat = SkTextureCompressor::kASTC_10x6_Format; 91 } else if (10 == blockDimX && 8 == blockDimY) { 92 astcFormat = SkTextureCompressor::kASTC_10x8_Format; 93 } else if (10 == blockDimX && 10 == blockDimY) { 94 astcFormat = SkTextureCompressor::kASTC_10x10_Format; 95 } else if (12 == blockDimX && 10 == blockDimY) { 96 astcFormat = SkTextureCompressor::kASTC_12x10_Format; 97 } else if (12 == blockDimX && 12 == blockDimY) { 98 astcFormat = SkTextureCompressor::kASTC_12x12_Format; 99 } else { 100 // We don't support any other block dimensions.. 101 return kFailure; 102 } 103 104 // Advance buf past the block dimensions 105 buf += 3; 106 107 // Read the width/height/depth from the buffer... 108 const int width = read_24bit(buf); 109 const int height = read_24bit(buf + 3); 110 const int depth = read_24bit(buf + 6); 111 112 if (1 != depth) { 113 // We don't support decoding 3D. 114 return kFailure; 115 } 116 117 // Advance the buffer past the image dimensions 118 buf += 9; 119 120 // Setup the sampler... 121 SkScaledBitmapSampler sampler(width, height, this->getSampleSize()); 122 123 // Determine the alpha of the bitmap... 124 SkAlphaType alphaType = kOpaque_SkAlphaType; 125 if (this->getRequireUnpremultipliedColors()) { 126 alphaType = kUnpremul_SkAlphaType; 127 } else { 128 alphaType = kPremul_SkAlphaType; 129 } 130 131 // Set the config... 132 bm->setInfo(SkImageInfo::MakeN32(sampler.scaledWidth(), sampler.scaledHeight(), alphaType)); 133 134 if (SkImageDecoder::kDecodeBounds_Mode == mode) { 135 return kSuccess; 136 } 137 138 if (!this->allocPixelRef(bm, nullptr)) { 139 return kFailure; 140 } 141 142 // Lock the pixels, since we're about to write to them... 143 SkAutoLockPixels alp(*bm); 144 145 if (!sampler.begin(bm, SkScaledBitmapSampler::kRGBA, *this)) { 146 return kFailure; 147 } 148 149 // ASTC Data is encoded as RGBA pixels, so we should extract it as such 150 int nPixels = width * height; 151 SkAutoMalloc outRGBAData(nPixels * 4); 152 uint8_t *outRGBADataPtr = reinterpret_cast<uint8_t *>(outRGBAData.get()); 153 154 // Decode ASTC 155 if (!SkTextureCompressor::DecompressBufferFromFormat( 156 outRGBADataPtr, width*4, buf, width, height, astcFormat)) { 157 return kFailure; 158 } 159 160 // Set each of the pixels... 161 const int srcRowBytes = width * 4; 162 const int dstHeight = sampler.scaledHeight(); 163 const uint8_t *srcRow = reinterpret_cast<uint8_t *>(outRGBADataPtr); 164 srcRow += sampler.srcY0() * srcRowBytes; 165 for (int y = 0; y < dstHeight; ++y) { 166 sampler.next(srcRow); 167 srcRow += sampler.srcDY() * srcRowBytes; 168 } 169 170 return kSuccess; 171 } 172 173 ///////////////////////////////////////////////////////////////////////////////////////// 174 DEFINE_DECODER_CREATOR(ASTCImageDecoder); 175 ///////////////////////////////////////////////////////////////////////////////////////// 176 177 static bool is_astc(SkStreamRewindable* stream) { 178 // Read the ASTC header and make sure it's valid. 179 uint32_t magic; 180 if (stream->read((void*)&magic, 4) != 4) { 181 return false; 182 } 183 184 return kASTCMagicNumber == SkEndian_SwapLE32(magic); 185 } 186 187 static SkImageDecoder* sk_libastc_dfactory(SkStreamRewindable* stream) { 188 if (is_astc(stream)) { 189 return new SkASTCImageDecoder; 190 } 191 return nullptr; 192 } 193 194 static SkImageDecoder_DecodeReg gReg(sk_libastc_dfactory); 195 196 static SkImageDecoder::Format get_format_astc(SkStreamRewindable* stream) { 197 if (is_astc(stream)) { 198 return SkImageDecoder::kASTC_Format; 199 } 200 return SkImageDecoder::kUnknown_Format; 201 } 202 203 static SkImageDecoder_FormatReg gFormatReg(get_format_astc); 204