199ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 299ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski/* 399ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski * Copyright 2014 Google Inc. 499ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski * 599ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski * Use of this source code is governed by a BSD-style license that can be 699ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski * found in the LICENSE file. 799ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski */ 899ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 999ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski#include "ktx.h" 10c250d2e4abdbe8193357696518592af8a0b4555akrajcevski#include "SkBitmap.h" 1199ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski#include "SkStream.h" 1299ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski#include "SkEndian.h" 1399ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 1499ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski#include "gl/GrGLDefines.h" 1540a1e11ebebe81586f3fec96408fdfd4b51123d2krajcevski#include "GrConfig.h" 1699ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 17c250d2e4abdbe8193357696518592af8a0b4555akrajcevski#include "etc1.h" 18c250d2e4abdbe8193357696518592af8a0b4555akrajcevski 1940a1e11ebebe81586f3fec96408fdfd4b51123d2krajcevskistatic inline uint32_t compressed_fmt_to_gl_define(SkTextureCompressor::Format fmt) { 2040a1e11ebebe81586f3fec96408fdfd4b51123d2krajcevski static const uint32_t kGLDefineMap[SkTextureCompressor::kFormatCnt] = { 2140a1e11ebebe81586f3fec96408fdfd4b51123d2krajcevski GR_GL_COMPRESSED_LUMINANCE_LATC1, // kLATC_Format 2295b1b3d82d227141647777d83324aa570b530096krajcevski GR_GL_COMPRESSED_R11, // kR11_EAC_Format 2395b1b3d82d227141647777d83324aa570b530096krajcevski GR_GL_COMPRESSED_RGB8_ETC1, // kETC1_Format 2495b1b3d82d227141647777d83324aa570b530096krajcevski GR_GL_COMPRESSED_RGBA_ASTC_4x4, // kASTC_4x4_Format 2595b1b3d82d227141647777d83324aa570b530096krajcevski GR_GL_COMPRESSED_RGBA_ASTC_5x4, // kASTC_5x4_Format 2695b1b3d82d227141647777d83324aa570b530096krajcevski GR_GL_COMPRESSED_RGBA_ASTC_5x5, // kASTC_5x5_Format 2795b1b3d82d227141647777d83324aa570b530096krajcevski GR_GL_COMPRESSED_RGBA_ASTC_6x5, // kASTC_6x5_Format 2895b1b3d82d227141647777d83324aa570b530096krajcevski GR_GL_COMPRESSED_RGBA_ASTC_6x6, // kASTC_6x6_Format 2995b1b3d82d227141647777d83324aa570b530096krajcevski GR_GL_COMPRESSED_RGBA_ASTC_8x5, // kASTC_8x5_Format 3095b1b3d82d227141647777d83324aa570b530096krajcevski GR_GL_COMPRESSED_RGBA_ASTC_8x6, // kASTC_8x6_Format 3195b1b3d82d227141647777d83324aa570b530096krajcevski GR_GL_COMPRESSED_RGBA_ASTC_8x8, // kASTC_8x8_Format 3295b1b3d82d227141647777d83324aa570b530096krajcevski GR_GL_COMPRESSED_RGBA_ASTC_10x5, // kASTC_10x5_Format 3395b1b3d82d227141647777d83324aa570b530096krajcevski GR_GL_COMPRESSED_RGBA_ASTC_10x6, // kASTC_10x6_Format 3495b1b3d82d227141647777d83324aa570b530096krajcevski GR_GL_COMPRESSED_RGBA_ASTC_10x8, // kASTC_10x8_Format 3595b1b3d82d227141647777d83324aa570b530096krajcevski GR_GL_COMPRESSED_RGBA_ASTC_10x10, // kASTC_10x10_Format 3695b1b3d82d227141647777d83324aa570b530096krajcevski GR_GL_COMPRESSED_RGBA_ASTC_12x10, // kASTC_12x10_Format 3740a1e11ebebe81586f3fec96408fdfd4b51123d2krajcevski GR_GL_COMPRESSED_RGBA_ASTC_12x12, // kASTC_12x12_Format 3840a1e11ebebe81586f3fec96408fdfd4b51123d2krajcevski }; 3940a1e11ebebe81586f3fec96408fdfd4b51123d2krajcevski 4040a1e11ebebe81586f3fec96408fdfd4b51123d2krajcevski GR_STATIC_ASSERT(0 == SkTextureCompressor::kLATC_Format); 4140a1e11ebebe81586f3fec96408fdfd4b51123d2krajcevski GR_STATIC_ASSERT(1 == SkTextureCompressor::kR11_EAC_Format); 4240a1e11ebebe81586f3fec96408fdfd4b51123d2krajcevski GR_STATIC_ASSERT(2 == SkTextureCompressor::kETC1_Format); 4395b1b3d82d227141647777d83324aa570b530096krajcevski GR_STATIC_ASSERT(3 == SkTextureCompressor::kASTC_4x4_Format); 4495b1b3d82d227141647777d83324aa570b530096krajcevski GR_STATIC_ASSERT(4 == SkTextureCompressor::kASTC_5x4_Format); 4595b1b3d82d227141647777d83324aa570b530096krajcevski GR_STATIC_ASSERT(5 == SkTextureCompressor::kASTC_5x5_Format); 4695b1b3d82d227141647777d83324aa570b530096krajcevski GR_STATIC_ASSERT(6 == SkTextureCompressor::kASTC_6x5_Format); 4795b1b3d82d227141647777d83324aa570b530096krajcevski GR_STATIC_ASSERT(7 == SkTextureCompressor::kASTC_6x6_Format); 4895b1b3d82d227141647777d83324aa570b530096krajcevski GR_STATIC_ASSERT(8 == SkTextureCompressor::kASTC_8x5_Format); 4995b1b3d82d227141647777d83324aa570b530096krajcevski GR_STATIC_ASSERT(9 == SkTextureCompressor::kASTC_8x6_Format); 5095b1b3d82d227141647777d83324aa570b530096krajcevski GR_STATIC_ASSERT(10 == SkTextureCompressor::kASTC_8x8_Format); 5195b1b3d82d227141647777d83324aa570b530096krajcevski GR_STATIC_ASSERT(11 == SkTextureCompressor::kASTC_10x5_Format); 5295b1b3d82d227141647777d83324aa570b530096krajcevski GR_STATIC_ASSERT(12 == SkTextureCompressor::kASTC_10x6_Format); 5395b1b3d82d227141647777d83324aa570b530096krajcevski GR_STATIC_ASSERT(13 == SkTextureCompressor::kASTC_10x8_Format); 5495b1b3d82d227141647777d83324aa570b530096krajcevski GR_STATIC_ASSERT(14 == SkTextureCompressor::kASTC_10x10_Format); 5595b1b3d82d227141647777d83324aa570b530096krajcevski GR_STATIC_ASSERT(15 == SkTextureCompressor::kASTC_12x10_Format); 5695b1b3d82d227141647777d83324aa570b530096krajcevski GR_STATIC_ASSERT(16 == SkTextureCompressor::kASTC_12x12_Format); 5740a1e11ebebe81586f3fec96408fdfd4b51123d2krajcevski GR_STATIC_ASSERT(SK_ARRAY_COUNT(kGLDefineMap) == SkTextureCompressor::kFormatCnt); 5840a1e11ebebe81586f3fec96408fdfd4b51123d2krajcevski 5940a1e11ebebe81586f3fec96408fdfd4b51123d2krajcevski return kGLDefineMap[fmt]; 6040a1e11ebebe81586f3fec96408fdfd4b51123d2krajcevski} 6140a1e11ebebe81586f3fec96408fdfd4b51123d2krajcevski 6299ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski#define KTX_FILE_IDENTIFIER_SIZE 12 6399ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevskistatic const uint8_t KTX_FILE_IDENTIFIER[KTX_FILE_IDENTIFIER_SIZE] = { 6499ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 0xAB, 0x4B, 0x54, 0x58, 0x20, 0x31, 0x31, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A 6599ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski}; 6699ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 6799ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevskistatic const uint32_t kKTX_ENDIANNESS_CODE = 0x04030201; 6899ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 6999ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevskibool SkKTXFile::KeyValue::readKeyAndValue(const uint8_t* data) { 7099ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski const char *key = reinterpret_cast<const char *>(data); 7199ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski const char *value = key; 7299ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 7399ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski size_t bytesRead = 0; 7499ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski while (*value != '\0' && bytesRead < this->fDataSz) { 7599ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski ++bytesRead; 7699ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski ++value; 7799ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski } 7899ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 7999ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski // Error of some sort.. 8099ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski if (bytesRead >= this->fDataSz) { 8199ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski return false; 8299ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski } 8399ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 8499ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski // Read the zero terminator 8599ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski ++bytesRead; 8699ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski ++value; 8799ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 8899ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski size_t bytesLeft = this->fDataSz - bytesRead; 89c250d2e4abdbe8193357696518592af8a0b4555akrajcevski 90c250d2e4abdbe8193357696518592af8a0b4555akrajcevski // We ignore the null terminator when setting the string value. 91c250d2e4abdbe8193357696518592af8a0b4555akrajcevski this->fKey.set(key, bytesRead - 1); 9299ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski if (bytesLeft > 0) { 93c250d2e4abdbe8193357696518592af8a0b4555akrajcevski this->fValue.set(value, bytesLeft - 1); 9499ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski } else { 9599ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski return false; 9699ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski } 9799ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 9899ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski return true; 9999ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski} 10099ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 101c250d2e4abdbe8193357696518592af8a0b4555akrajcevskibool SkKTXFile::KeyValue::writeKeyAndValueForKTX(SkWStream* strm) { 102c250d2e4abdbe8193357696518592af8a0b4555akrajcevski size_t bytesWritten = 0; 103c250d2e4abdbe8193357696518592af8a0b4555akrajcevski if (!strm->write(&(this->fDataSz), 4)) { 104c250d2e4abdbe8193357696518592af8a0b4555akrajcevski return false; 105c250d2e4abdbe8193357696518592af8a0b4555akrajcevski } 106c250d2e4abdbe8193357696518592af8a0b4555akrajcevski 107c250d2e4abdbe8193357696518592af8a0b4555akrajcevski bytesWritten += 4; 108c250d2e4abdbe8193357696518592af8a0b4555akrajcevski 109c250d2e4abdbe8193357696518592af8a0b4555akrajcevski // Here we know that C-strings must end with a null terminating 110c250d2e4abdbe8193357696518592af8a0b4555akrajcevski // character, so when we get a c_str(), it will have as many 111c250d2e4abdbe8193357696518592af8a0b4555akrajcevski // bytes of data as size() returns plus a zero, so we just 112c250d2e4abdbe8193357696518592af8a0b4555akrajcevski // write size() + 1 bytes into the stream. 113c250d2e4abdbe8193357696518592af8a0b4555akrajcevski 114c250d2e4abdbe8193357696518592af8a0b4555akrajcevski size_t keySize = this->fKey.size() + 1; 115c250d2e4abdbe8193357696518592af8a0b4555akrajcevski if (!strm->write(this->fKey.c_str(), keySize)) { 116c250d2e4abdbe8193357696518592af8a0b4555akrajcevski return false; 117c250d2e4abdbe8193357696518592af8a0b4555akrajcevski } 118c250d2e4abdbe8193357696518592af8a0b4555akrajcevski 119c250d2e4abdbe8193357696518592af8a0b4555akrajcevski bytesWritten += keySize; 120c250d2e4abdbe8193357696518592af8a0b4555akrajcevski 121c250d2e4abdbe8193357696518592af8a0b4555akrajcevski size_t valueSize = this->fValue.size() + 1; 122c250d2e4abdbe8193357696518592af8a0b4555akrajcevski if (!strm->write(this->fValue.c_str(), valueSize)) { 123c250d2e4abdbe8193357696518592af8a0b4555akrajcevski return false; 124c250d2e4abdbe8193357696518592af8a0b4555akrajcevski } 125c250d2e4abdbe8193357696518592af8a0b4555akrajcevski 126c250d2e4abdbe8193357696518592af8a0b4555akrajcevski bytesWritten += valueSize; 127c250d2e4abdbe8193357696518592af8a0b4555akrajcevski 128c250d2e4abdbe8193357696518592af8a0b4555akrajcevski size_t bytesWrittenPadFour = (bytesWritten + 3) & ~3; 129c250d2e4abdbe8193357696518592af8a0b4555akrajcevski uint8_t nullBuf[4] = { 0, 0, 0, 0 }; 130c250d2e4abdbe8193357696518592af8a0b4555akrajcevski 131c250d2e4abdbe8193357696518592af8a0b4555akrajcevski size_t padding = bytesWrittenPadFour - bytesWritten; 132c250d2e4abdbe8193357696518592af8a0b4555akrajcevski SkASSERT(padding < 4); 133c250d2e4abdbe8193357696518592af8a0b4555akrajcevski 134c250d2e4abdbe8193357696518592af8a0b4555akrajcevski return strm->write(nullBuf, padding); 135c250d2e4abdbe8193357696518592af8a0b4555akrajcevski} 136c250d2e4abdbe8193357696518592af8a0b4555akrajcevski 13799ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevskiuint32_t SkKTXFile::readInt(const uint8_t** buf, size_t* bytesLeft) const { 13849f085dddff10473b6ebf832a974288300224e60bsalomon SkASSERT(buf && bytesLeft); 13999ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 14099ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski uint32_t result; 14199ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 14299ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski if (*bytesLeft < 4) { 14399ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski SkASSERT(false); 14499ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski return 0; 14599ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski } 14699ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 14799ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski memcpy(&result, *buf, 4); 14899ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski *buf += 4; 14999ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 15099ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski if (fSwapBytes) { 15199ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski SkEndianSwap32(result); 15299ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski } 15399ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 15499ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski *bytesLeft -= 4; 15599ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 15699ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski return result; 15799ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski} 15899ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 159c250d2e4abdbe8193357696518592af8a0b4555akrajcevskiSkString SkKTXFile::getValueForKey(const SkString& key) const { 160c250d2e4abdbe8193357696518592af8a0b4555akrajcevski const KeyValue *begin = this->fKeyValuePairs.begin(); 161c250d2e4abdbe8193357696518592af8a0b4555akrajcevski const KeyValue *end = this->fKeyValuePairs.end(); 162c250d2e4abdbe8193357696518592af8a0b4555akrajcevski for (const KeyValue *kv = begin; kv != end; ++kv) { 163c250d2e4abdbe8193357696518592af8a0b4555akrajcevski if (kv->key() == key) { 164c250d2e4abdbe8193357696518592af8a0b4555akrajcevski return kv->value(); 165c250d2e4abdbe8193357696518592af8a0b4555akrajcevski } 166c250d2e4abdbe8193357696518592af8a0b4555akrajcevski } 167c250d2e4abdbe8193357696518592af8a0b4555akrajcevski return SkString(); 168c250d2e4abdbe8193357696518592af8a0b4555akrajcevski} 169c250d2e4abdbe8193357696518592af8a0b4555akrajcevski 17040a1e11ebebe81586f3fec96408fdfd4b51123d2krajcevskibool SkKTXFile::isCompressedFormat(SkTextureCompressor::Format fmt) const { 17140a1e11ebebe81586f3fec96408fdfd4b51123d2krajcevski if (!this->valid()) { 17240a1e11ebebe81586f3fec96408fdfd4b51123d2krajcevski return false; 17340a1e11ebebe81586f3fec96408fdfd4b51123d2krajcevski } 17440a1e11ebebe81586f3fec96408fdfd4b51123d2krajcevski 17540a1e11ebebe81586f3fec96408fdfd4b51123d2krajcevski // This has many aliases 17640a1e11ebebe81586f3fec96408fdfd4b51123d2krajcevski bool isFmt = false; 17740a1e11ebebe81586f3fec96408fdfd4b51123d2krajcevski if (fmt == SkTextureCompressor::kLATC_Format) { 17840a1e11ebebe81586f3fec96408fdfd4b51123d2krajcevski isFmt = GR_GL_COMPRESSED_RED_RGTC1 == fHeader.fGLInternalFormat || 17940a1e11ebebe81586f3fec96408fdfd4b51123d2krajcevski GR_GL_COMPRESSED_3DC_X == fHeader.fGLInternalFormat; 18040a1e11ebebe81586f3fec96408fdfd4b51123d2krajcevski } 18140a1e11ebebe81586f3fec96408fdfd4b51123d2krajcevski 18240a1e11ebebe81586f3fec96408fdfd4b51123d2krajcevski return isFmt || compressed_fmt_to_gl_define(fmt) == fHeader.fGLInternalFormat; 18399ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski} 18499ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 18599ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevskibool SkKTXFile::isRGBA8() const { 18699ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski return this->valid() && GR_GL_RGBA8 == fHeader.fGLInternalFormat; 18799ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski} 18899ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 18999ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevskibool SkKTXFile::isRGB8() const { 19099ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski return this->valid() && GR_GL_RGB8 == fHeader.fGLInternalFormat; 19199ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski} 19299ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 19399ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevskibool SkKTXFile::readKTXFile(const uint8_t* data, size_t dataLen) { 19499ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski const uint8_t *buf = data; 19599ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski size_t bytesLeft = dataLen; 19699ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 19799ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski // Make sure original KTX header is there... this should have been checked 19899ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski // already by a call to is_ktx() 19999ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski SkASSERT(bytesLeft > KTX_FILE_IDENTIFIER_SIZE); 20099ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski SkASSERT(0 == memcmp(KTX_FILE_IDENTIFIER, buf, KTX_FILE_IDENTIFIER_SIZE)); 20199ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski buf += KTX_FILE_IDENTIFIER_SIZE; 20299ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski bytesLeft -= KTX_FILE_IDENTIFIER_SIZE; 20399ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 20499ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski // Read header, but first make sure that we have the proper space: we need 20599ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski // two 32-bit ints: 1 for endianness, and another for the mandatory image 20699ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski // size after the header. 20799ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski if (bytesLeft < 8 + sizeof(Header)) { 20899ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski return false; 20999ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski } 21099ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 21199ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski uint32_t endianness = this->readInt(&buf, &bytesLeft); 21299ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski fSwapBytes = kKTX_ENDIANNESS_CODE != endianness; 21399ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 21499ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski // Read header values 21599ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski fHeader.fGLType = this->readInt(&buf, &bytesLeft); 21699ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski fHeader.fGLTypeSize = this->readInt(&buf, &bytesLeft); 21799ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski fHeader.fGLFormat = this->readInt(&buf, &bytesLeft); 21899ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski fHeader.fGLInternalFormat = this->readInt(&buf, &bytesLeft); 21999ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski fHeader.fGLBaseInternalFormat = this->readInt(&buf, &bytesLeft); 22099ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski fHeader.fPixelWidth = this->readInt(&buf, &bytesLeft); 22199ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski fHeader.fPixelHeight = this->readInt(&buf, &bytesLeft); 22299ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski fHeader.fPixelDepth = this->readInt(&buf, &bytesLeft); 22399ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski fHeader.fNumberOfArrayElements = this->readInt(&buf, &bytesLeft); 22499ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski fHeader.fNumberOfFaces = this->readInt(&buf, &bytesLeft); 22599ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski fHeader.fNumberOfMipmapLevels = this->readInt(&buf, &bytesLeft); 22699ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski fHeader.fBytesOfKeyValueData = this->readInt(&buf, &bytesLeft); 22799ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 22899ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski // Check for things that we understand... 22999ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski { 23099ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski // First, we only support compressed formats and single byte 23199ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski // representations at the moment. If the internal format is 23299ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski // compressed, the the GLType field in the header must be zero. 23399ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski // In the future, we may support additional data types (such 23499ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski // as GL_UNSIGNED_SHORT_5_6_5) 23599ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski if (fHeader.fGLType != 0 && fHeader.fGLType != GR_GL_UNSIGNED_BYTE) { 23699ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski return false; 23799ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski } 23899ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 23999ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski // This means that for well-formatted KTX files, the glTypeSize 24099ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski // field must be one... 24199ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski if (fHeader.fGLTypeSize != 1) { 24299ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski return false; 24399ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski } 24499ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 24599ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski // We don't support 3D textures. 24699ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski if (fHeader.fPixelDepth > 1) { 24799ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski return false; 24899ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski } 24999ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 25099ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski // We don't support texture arrays 25199ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski if (fHeader.fNumberOfArrayElements > 1) { 25299ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski return false; 25399ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski } 25499ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 25599ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski // We don't support cube maps 25699ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski if (fHeader.fNumberOfFaces > 1) { 25799ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski return false; 25899ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski } 2596b0d6b43cf662735dc804d8142383452c7f246f9djsollen 2606b0d6b43cf662735dc804d8142383452c7f246f9djsollen // We don't support width and/or height <= 0 2616b0d6b43cf662735dc804d8142383452c7f246f9djsollen if (fHeader.fPixelWidth <= 0 || fHeader.fPixelHeight <= 0) { 2626b0d6b43cf662735dc804d8142383452c7f246f9djsollen return false; 2636b0d6b43cf662735dc804d8142383452c7f246f9djsollen } 26499ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski } 26599ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 26699ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski // Make sure that we have enough bytes left for the key/value 26799ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski // data according to what was said in the header. 26899ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski if (bytesLeft < fHeader.fBytesOfKeyValueData) { 26999ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski return false; 27099ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski } 27199ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 27299ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski // Next read the key value pairs 27399ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski size_t keyValueBytesRead = 0; 27499ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski while (keyValueBytesRead < fHeader.fBytesOfKeyValueData) { 27599ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski uint32_t keyValueBytes = this->readInt(&buf, &bytesLeft); 27699ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski keyValueBytesRead += 4; 27799ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 27899ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski if (keyValueBytes > bytesLeft) { 27999ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski return false; 28099ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski } 28199ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 28299ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski KeyValue kv(keyValueBytes); 28399ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski if (!kv.readKeyAndValue(buf)) { 28499ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski return false; 28599ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski } 28699ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 28799ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski fKeyValuePairs.push_back(kv); 28899ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 28999ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski uint32_t keyValueBytesPadded = (keyValueBytes + 3) & ~3; 29099ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski buf += keyValueBytesPadded; 29199ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski keyValueBytesRead += keyValueBytesPadded; 29299ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski bytesLeft -= keyValueBytesPadded; 29399ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski } 29499ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 29599ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski // Read the pixel data... 29699ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski int mipmaps = SkMax32(fHeader.fNumberOfMipmapLevels, 1); 29799ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski SkASSERT(mipmaps == 1); 29899ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 29999ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski int arrayElements = SkMax32(fHeader.fNumberOfArrayElements, 1); 30099ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski SkASSERT(arrayElements == 1); 30199ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 30299ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski int faces = SkMax32(fHeader.fNumberOfFaces, 1); 30399ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski SkASSERT(faces == 1); 30499ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 30599ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski int depth = SkMax32(fHeader.fPixelDepth, 1); 30699ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski SkASSERT(depth == 1); 30799ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 30899ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski for (int mipmap = 0; mipmap < mipmaps; ++mipmap) { 30999ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski // Make sure that we have at least 4 more bytes for the first image size 31099ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski if (bytesLeft < 4) { 31199ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski return false; 31299ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski } 31399ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 31499ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski uint32_t imgSize = this->readInt(&buf, &bytesLeft); 31599ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 31699ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski // Truncated file. 31799ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski if (bytesLeft < imgSize) { 31899ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski return false; 31999ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski } 32099ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 32199ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski // !FIXME! If support is ever added for cube maps then the padding 32299ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski // needs to be taken into account here. 32399ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski for (int arrayElement = 0; arrayElement < arrayElements; ++arrayElement) { 32499ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski for (int face = 0; face < faces; ++face) { 32599ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski for (int z = 0; z < depth; ++z) { 32699ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski PixelData pd(buf, imgSize); 32799ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski fPixelData.append(1, &pd); 32899ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski } 32999ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski } 33099ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski } 33199ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 33299ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski uint32_t imgSizePadded = (imgSize + 3) & ~3; 33399ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski buf += imgSizePadded; 33499ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski bytesLeft -= imgSizePadded; 33599ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski } 33699ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 33799ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski return bytesLeft == 0; 33899ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski} 33999ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 34099ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevskibool SkKTXFile::is_ktx(const uint8_t *data) { 34199ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski return 0 == memcmp(KTX_FILE_IDENTIFIER, data, KTX_FILE_IDENTIFIER_SIZE); 34299ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski} 34399ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 34499ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevskibool SkKTXFile::is_ktx(SkStreamRewindable* stream) { 34599ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski // Read the KTX header and make sure it's valid. 34699ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski unsigned char buf[KTX_FILE_IDENTIFIER_SIZE]; 34799ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski bool largeEnough = 34899ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski stream->read((void*)buf, KTX_FILE_IDENTIFIER_SIZE) == KTX_FILE_IDENTIFIER_SIZE; 34999ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski stream->rewind(); 35099ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski if (!largeEnough) { 35199ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski return false; 35299ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski } 35399ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski return is_ktx(buf); 35499ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski} 355c250d2e4abdbe8193357696518592af8a0b4555akrajcevski 356c250d2e4abdbe8193357696518592af8a0b4555akrajcevskiSkKTXFile::KeyValue SkKTXFile::CreateKeyValue(const char *cstrKey, const char *cstrValue) { 357c250d2e4abdbe8193357696518592af8a0b4555akrajcevski SkString key(cstrKey); 358c250d2e4abdbe8193357696518592af8a0b4555akrajcevski SkString value(cstrValue); 359c250d2e4abdbe8193357696518592af8a0b4555akrajcevski 360c250d2e4abdbe8193357696518592af8a0b4555akrajcevski // Size of buffer is length of string plus the null terminators... 361c250d2e4abdbe8193357696518592af8a0b4555akrajcevski size_t size = key.size() + 1 + value.size() + 1; 362c250d2e4abdbe8193357696518592af8a0b4555akrajcevski 363c250d2e4abdbe8193357696518592af8a0b4555akrajcevski SkAutoSMalloc<256> buf(size); 364c250d2e4abdbe8193357696518592af8a0b4555akrajcevski uint8_t* kvBuf = reinterpret_cast<uint8_t*>(buf.get()); 365c250d2e4abdbe8193357696518592af8a0b4555akrajcevski memcpy(kvBuf, key.c_str(), key.size() + 1); 366c250d2e4abdbe8193357696518592af8a0b4555akrajcevski memcpy(kvBuf + key.size() + 1, value.c_str(), value.size() + 1); 367c250d2e4abdbe8193357696518592af8a0b4555akrajcevski 368c250d2e4abdbe8193357696518592af8a0b4555akrajcevski KeyValue kv(size); 369c250d2e4abdbe8193357696518592af8a0b4555akrajcevski SkAssertResult(kv.readKeyAndValue(kvBuf)); 370c250d2e4abdbe8193357696518592af8a0b4555akrajcevski return kv; 371c250d2e4abdbe8193357696518592af8a0b4555akrajcevski} 372c250d2e4abdbe8193357696518592af8a0b4555akrajcevski 373c250d2e4abdbe8193357696518592af8a0b4555akrajcevskibool SkKTXFile::WriteETC1ToKTX(SkWStream* stream, const uint8_t *etc1Data, 374c250d2e4abdbe8193357696518592af8a0b4555akrajcevski uint32_t width, uint32_t height) { 375c250d2e4abdbe8193357696518592af8a0b4555akrajcevski // First thing's first, write out the magic identifier and endianness... 376c250d2e4abdbe8193357696518592af8a0b4555akrajcevski if (!stream->write(KTX_FILE_IDENTIFIER, KTX_FILE_IDENTIFIER_SIZE)) { 377c250d2e4abdbe8193357696518592af8a0b4555akrajcevski return false; 378c250d2e4abdbe8193357696518592af8a0b4555akrajcevski } 379c250d2e4abdbe8193357696518592af8a0b4555akrajcevski 380c250d2e4abdbe8193357696518592af8a0b4555akrajcevski if (!stream->write(&kKTX_ENDIANNESS_CODE, 4)) { 381c250d2e4abdbe8193357696518592af8a0b4555akrajcevski return false; 382c250d2e4abdbe8193357696518592af8a0b4555akrajcevski } 383c250d2e4abdbe8193357696518592af8a0b4555akrajcevski 384c250d2e4abdbe8193357696518592af8a0b4555akrajcevski Header hdr; 385c250d2e4abdbe8193357696518592af8a0b4555akrajcevski hdr.fGLType = 0; 386c250d2e4abdbe8193357696518592af8a0b4555akrajcevski hdr.fGLTypeSize = 1; 387c250d2e4abdbe8193357696518592af8a0b4555akrajcevski hdr.fGLFormat = 0; 388c250d2e4abdbe8193357696518592af8a0b4555akrajcevski hdr.fGLInternalFormat = GR_GL_COMPRESSED_RGB8_ETC1; 389c250d2e4abdbe8193357696518592af8a0b4555akrajcevski hdr.fGLBaseInternalFormat = GR_GL_RGB; 390c250d2e4abdbe8193357696518592af8a0b4555akrajcevski hdr.fPixelWidth = width; 391c250d2e4abdbe8193357696518592af8a0b4555akrajcevski hdr.fPixelHeight = height; 392c250d2e4abdbe8193357696518592af8a0b4555akrajcevski hdr.fNumberOfArrayElements = 0; 393c250d2e4abdbe8193357696518592af8a0b4555akrajcevski hdr.fNumberOfFaces = 1; 394c250d2e4abdbe8193357696518592af8a0b4555akrajcevski hdr.fNumberOfMipmapLevels = 1; 395c250d2e4abdbe8193357696518592af8a0b4555akrajcevski 396c250d2e4abdbe8193357696518592af8a0b4555akrajcevski // !FIXME! The spec suggests that we put KTXOrientation as a 397c250d2e4abdbe8193357696518592af8a0b4555akrajcevski // key value pair in the header, but that means that we'd have to 398c250d2e4abdbe8193357696518592af8a0b4555akrajcevski // pipe through the bitmap's orientation to properly do that. 399c250d2e4abdbe8193357696518592af8a0b4555akrajcevski hdr.fBytesOfKeyValueData = 0; 400c250d2e4abdbe8193357696518592af8a0b4555akrajcevski 401c250d2e4abdbe8193357696518592af8a0b4555akrajcevski // Write the header 402c250d2e4abdbe8193357696518592af8a0b4555akrajcevski if (!stream->write(&hdr, sizeof(hdr))) { 403c250d2e4abdbe8193357696518592af8a0b4555akrajcevski return false; 404c250d2e4abdbe8193357696518592af8a0b4555akrajcevski } 405c250d2e4abdbe8193357696518592af8a0b4555akrajcevski 406c250d2e4abdbe8193357696518592af8a0b4555akrajcevski // Write the size of the image data 407c250d2e4abdbe8193357696518592af8a0b4555akrajcevski etc1_uint32 dataSize = etc1_get_encoded_data_size(width, height); 408c250d2e4abdbe8193357696518592af8a0b4555akrajcevski if (!stream->write(&dataSize, 4)) { 409c250d2e4abdbe8193357696518592af8a0b4555akrajcevski return false; 410c250d2e4abdbe8193357696518592af8a0b4555akrajcevski } 411c250d2e4abdbe8193357696518592af8a0b4555akrajcevski 412c250d2e4abdbe8193357696518592af8a0b4555akrajcevski // Write the actual image data 413c250d2e4abdbe8193357696518592af8a0b4555akrajcevski if (!stream->write(etc1Data, dataSize)) { 414c250d2e4abdbe8193357696518592af8a0b4555akrajcevski return false; 415c250d2e4abdbe8193357696518592af8a0b4555akrajcevski } 416c250d2e4abdbe8193357696518592af8a0b4555akrajcevski 417c250d2e4abdbe8193357696518592af8a0b4555akrajcevski return true; 418c250d2e4abdbe8193357696518592af8a0b4555akrajcevski} 419c250d2e4abdbe8193357696518592af8a0b4555akrajcevski 420c250d2e4abdbe8193357696518592af8a0b4555akrajcevskibool SkKTXFile::WriteBitmapToKTX(SkWStream* stream, const SkBitmap& bitmap) { 421c3b3266b7db2f1a41d41ecac010c766b7ad8eebcreed const SkColorType ct = bitmap.colorType(); 422c250d2e4abdbe8193357696518592af8a0b4555akrajcevski SkAutoLockPixels alp(bitmap); 423c250d2e4abdbe8193357696518592af8a0b4555akrajcevski 424c250d2e4abdbe8193357696518592af8a0b4555akrajcevski const int width = bitmap.width(); 425c250d2e4abdbe8193357696518592af8a0b4555akrajcevski const int height = bitmap.width(); 426c250d2e4abdbe8193357696518592af8a0b4555akrajcevski const uint8_t* src = reinterpret_cast<uint8_t*>(bitmap.getPixels()); 427c250d2e4abdbe8193357696518592af8a0b4555akrajcevski if (NULL == bitmap.getPixels()) { 428c250d2e4abdbe8193357696518592af8a0b4555akrajcevski return false; 429c250d2e4abdbe8193357696518592af8a0b4555akrajcevski } 430c250d2e4abdbe8193357696518592af8a0b4555akrajcevski 431c250d2e4abdbe8193357696518592af8a0b4555akrajcevski // First thing's first, write out the magic identifier and endianness... 432c250d2e4abdbe8193357696518592af8a0b4555akrajcevski if (!stream->write(KTX_FILE_IDENTIFIER, KTX_FILE_IDENTIFIER_SIZE) || 433c250d2e4abdbe8193357696518592af8a0b4555akrajcevski !stream->write(&kKTX_ENDIANNESS_CODE, 4)) { 434c250d2e4abdbe8193357696518592af8a0b4555akrajcevski return false; 435c250d2e4abdbe8193357696518592af8a0b4555akrajcevski } 436c250d2e4abdbe8193357696518592af8a0b4555akrajcevski 437c250d2e4abdbe8193357696518592af8a0b4555akrajcevski // Collect our key/value pairs... 438c250d2e4abdbe8193357696518592af8a0b4555akrajcevski SkTArray<KeyValue> kvPairs; 439c250d2e4abdbe8193357696518592af8a0b4555akrajcevski 440c250d2e4abdbe8193357696518592af8a0b4555akrajcevski // Next, write the header based on the bitmap's config. 441c250d2e4abdbe8193357696518592af8a0b4555akrajcevski Header hdr; 442c3b3266b7db2f1a41d41ecac010c766b7ad8eebcreed switch (ct) { 443c3b3266b7db2f1a41d41ecac010c766b7ad8eebcreed case kIndex_8_SkColorType: 444c250d2e4abdbe8193357696518592af8a0b4555akrajcevski // There is a compressed format for this, but we don't support it yet. 445c250d2e4abdbe8193357696518592af8a0b4555akrajcevski SkDebugf("Writing indexed bitmap to KTX unsupported.\n"); 446c250d2e4abdbe8193357696518592af8a0b4555akrajcevski // VVV fall through VVV 447c250d2e4abdbe8193357696518592af8a0b4555akrajcevski default: 448c3b3266b7db2f1a41d41ecac010c766b7ad8eebcreed case kUnknown_SkColorType: 449c250d2e4abdbe8193357696518592af8a0b4555akrajcevski // Bitmap hasn't been configured. 450c250d2e4abdbe8193357696518592af8a0b4555akrajcevski return false; 451c250d2e4abdbe8193357696518592af8a0b4555akrajcevski 452c3b3266b7db2f1a41d41ecac010c766b7ad8eebcreed case kAlpha_8_SkColorType: 453c250d2e4abdbe8193357696518592af8a0b4555akrajcevski hdr.fGLType = GR_GL_UNSIGNED_BYTE; 454c250d2e4abdbe8193357696518592af8a0b4555akrajcevski hdr.fGLTypeSize = 1; 455c250d2e4abdbe8193357696518592af8a0b4555akrajcevski hdr.fGLFormat = GR_GL_RED; 456c250d2e4abdbe8193357696518592af8a0b4555akrajcevski hdr.fGLInternalFormat = GR_GL_R8; 457c250d2e4abdbe8193357696518592af8a0b4555akrajcevski hdr.fGLBaseInternalFormat = GR_GL_RED; 458c250d2e4abdbe8193357696518592af8a0b4555akrajcevski break; 459c250d2e4abdbe8193357696518592af8a0b4555akrajcevski 460c3b3266b7db2f1a41d41ecac010c766b7ad8eebcreed case kRGB_565_SkColorType: 461c250d2e4abdbe8193357696518592af8a0b4555akrajcevski hdr.fGLType = GR_GL_UNSIGNED_SHORT_5_6_5; 462c250d2e4abdbe8193357696518592af8a0b4555akrajcevski hdr.fGLTypeSize = 2; 463c250d2e4abdbe8193357696518592af8a0b4555akrajcevski hdr.fGLFormat = GR_GL_RGB; 464c250d2e4abdbe8193357696518592af8a0b4555akrajcevski hdr.fGLInternalFormat = GR_GL_RGB; 465c250d2e4abdbe8193357696518592af8a0b4555akrajcevski hdr.fGLBaseInternalFormat = GR_GL_RGB; 466c250d2e4abdbe8193357696518592af8a0b4555akrajcevski break; 467c250d2e4abdbe8193357696518592af8a0b4555akrajcevski 468c3b3266b7db2f1a41d41ecac010c766b7ad8eebcreed case kARGB_4444_SkColorType: 469c250d2e4abdbe8193357696518592af8a0b4555akrajcevski hdr.fGLType = GR_GL_UNSIGNED_SHORT_4_4_4_4; 470c250d2e4abdbe8193357696518592af8a0b4555akrajcevski hdr.fGLTypeSize = 2; 471c250d2e4abdbe8193357696518592af8a0b4555akrajcevski hdr.fGLFormat = GR_GL_RGBA; 472c250d2e4abdbe8193357696518592af8a0b4555akrajcevski hdr.fGLInternalFormat = GR_GL_RGBA4; 473c250d2e4abdbe8193357696518592af8a0b4555akrajcevski hdr.fGLBaseInternalFormat = GR_GL_RGBA; 474c250d2e4abdbe8193357696518592af8a0b4555akrajcevski kvPairs.push_back(CreateKeyValue("KTXPremultipliedAlpha", "True")); 475c250d2e4abdbe8193357696518592af8a0b4555akrajcevski break; 476c250d2e4abdbe8193357696518592af8a0b4555akrajcevski 477c3b3266b7db2f1a41d41ecac010c766b7ad8eebcreed case kN32_SkColorType: 478c250d2e4abdbe8193357696518592af8a0b4555akrajcevski hdr.fGLType = GR_GL_UNSIGNED_BYTE; 479c250d2e4abdbe8193357696518592af8a0b4555akrajcevski hdr.fGLTypeSize = 1; 480c250d2e4abdbe8193357696518592af8a0b4555akrajcevski hdr.fGLFormat = GR_GL_RGBA; 481c250d2e4abdbe8193357696518592af8a0b4555akrajcevski hdr.fGLInternalFormat = GR_GL_RGBA8; 482c250d2e4abdbe8193357696518592af8a0b4555akrajcevski hdr.fGLBaseInternalFormat = GR_GL_RGBA; 483c250d2e4abdbe8193357696518592af8a0b4555akrajcevski kvPairs.push_back(CreateKeyValue("KTXPremultipliedAlpha", "True")); 484c250d2e4abdbe8193357696518592af8a0b4555akrajcevski break; 485c250d2e4abdbe8193357696518592af8a0b4555akrajcevski } 486c250d2e4abdbe8193357696518592af8a0b4555akrajcevski 487c250d2e4abdbe8193357696518592af8a0b4555akrajcevski // Everything else in the header is shared. 488c250d2e4abdbe8193357696518592af8a0b4555akrajcevski hdr.fPixelWidth = width; 489c250d2e4abdbe8193357696518592af8a0b4555akrajcevski hdr.fPixelHeight = height; 490c250d2e4abdbe8193357696518592af8a0b4555akrajcevski hdr.fNumberOfArrayElements = 0; 491c250d2e4abdbe8193357696518592af8a0b4555akrajcevski hdr.fNumberOfFaces = 1; 492c250d2e4abdbe8193357696518592af8a0b4555akrajcevski hdr.fNumberOfMipmapLevels = 1; 493c250d2e4abdbe8193357696518592af8a0b4555akrajcevski 494c250d2e4abdbe8193357696518592af8a0b4555akrajcevski // Calculate the key value data size 495c250d2e4abdbe8193357696518592af8a0b4555akrajcevski hdr.fBytesOfKeyValueData = 0; 496c250d2e4abdbe8193357696518592af8a0b4555akrajcevski for (KeyValue *kv = kvPairs.begin(); kv != kvPairs.end(); ++kv) { 497c250d2e4abdbe8193357696518592af8a0b4555akrajcevski // Key value size is the size of the key value data, 498c250d2e4abdbe8193357696518592af8a0b4555akrajcevski // four bytes for saying how big the key value size is 499c250d2e4abdbe8193357696518592af8a0b4555akrajcevski // and then additional bytes for padding to four byte boundary 500c250d2e4abdbe8193357696518592af8a0b4555akrajcevski size_t kvsize = kv->size(); 501c250d2e4abdbe8193357696518592af8a0b4555akrajcevski kvsize += 4; 502c250d2e4abdbe8193357696518592af8a0b4555akrajcevski kvsize = (kvsize + 3) & ~3; 503c250d2e4abdbe8193357696518592af8a0b4555akrajcevski hdr.fBytesOfKeyValueData += kvsize; 504c250d2e4abdbe8193357696518592af8a0b4555akrajcevski } 505c250d2e4abdbe8193357696518592af8a0b4555akrajcevski 506c250d2e4abdbe8193357696518592af8a0b4555akrajcevski // Write the header 507c250d2e4abdbe8193357696518592af8a0b4555akrajcevski if (!stream->write(&hdr, sizeof(hdr))) { 508c250d2e4abdbe8193357696518592af8a0b4555akrajcevski return false; 509c250d2e4abdbe8193357696518592af8a0b4555akrajcevski } 510c250d2e4abdbe8193357696518592af8a0b4555akrajcevski 511c250d2e4abdbe8193357696518592af8a0b4555akrajcevski // Write out each key value pair 512c250d2e4abdbe8193357696518592af8a0b4555akrajcevski for (KeyValue *kv = kvPairs.begin(); kv != kvPairs.end(); ++kv) { 513c250d2e4abdbe8193357696518592af8a0b4555akrajcevski if (!kv->writeKeyAndValueForKTX(stream)) { 514c250d2e4abdbe8193357696518592af8a0b4555akrajcevski return false; 515c250d2e4abdbe8193357696518592af8a0b4555akrajcevski } 516c250d2e4abdbe8193357696518592af8a0b4555akrajcevski } 517c250d2e4abdbe8193357696518592af8a0b4555akrajcevski 518c250d2e4abdbe8193357696518592af8a0b4555akrajcevski // Calculate the size of the data 519c250d2e4abdbe8193357696518592af8a0b4555akrajcevski int bpp = bitmap.bytesPerPixel(); 520c250d2e4abdbe8193357696518592af8a0b4555akrajcevski uint32_t dataSz = bpp * width * height; 521c250d2e4abdbe8193357696518592af8a0b4555akrajcevski 522c250d2e4abdbe8193357696518592af8a0b4555akrajcevski if (0 >= bpp) { 523c250d2e4abdbe8193357696518592af8a0b4555akrajcevski return false; 524c250d2e4abdbe8193357696518592af8a0b4555akrajcevski } 525c250d2e4abdbe8193357696518592af8a0b4555akrajcevski 526c250d2e4abdbe8193357696518592af8a0b4555akrajcevski // Write it into the buffer 527c250d2e4abdbe8193357696518592af8a0b4555akrajcevski if (!stream->write(&dataSz, 4)) { 528c250d2e4abdbe8193357696518592af8a0b4555akrajcevski return false; 529c250d2e4abdbe8193357696518592af8a0b4555akrajcevski } 530c250d2e4abdbe8193357696518592af8a0b4555akrajcevski 531c250d2e4abdbe8193357696518592af8a0b4555akrajcevski // Write the pixel data... 532c250d2e4abdbe8193357696518592af8a0b4555akrajcevski const uint8_t* rowPtr = src; 533c3b3266b7db2f1a41d41ecac010c766b7ad8eebcreed if (kN32_SkColorType == ct) { 534c250d2e4abdbe8193357696518592af8a0b4555akrajcevski for (int j = 0; j < height; ++j) { 535c250d2e4abdbe8193357696518592af8a0b4555akrajcevski const uint32_t* pixelsPtr = reinterpret_cast<const uint32_t*>(rowPtr); 536c250d2e4abdbe8193357696518592af8a0b4555akrajcevski for (int i = 0; i < width; ++i) { 537c250d2e4abdbe8193357696518592af8a0b4555akrajcevski uint32_t pixel = pixelsPtr[i]; 538c250d2e4abdbe8193357696518592af8a0b4555akrajcevski uint8_t dstPixel[4]; 539c250d2e4abdbe8193357696518592af8a0b4555akrajcevski dstPixel[0] = pixel >> SK_R32_SHIFT; 540c250d2e4abdbe8193357696518592af8a0b4555akrajcevski dstPixel[1] = pixel >> SK_G32_SHIFT; 541c250d2e4abdbe8193357696518592af8a0b4555akrajcevski dstPixel[2] = pixel >> SK_B32_SHIFT; 542c250d2e4abdbe8193357696518592af8a0b4555akrajcevski dstPixel[3] = pixel >> SK_A32_SHIFT; 543c250d2e4abdbe8193357696518592af8a0b4555akrajcevski if (!stream->write(dstPixel, 4)) { 544c250d2e4abdbe8193357696518592af8a0b4555akrajcevski return false; 545c250d2e4abdbe8193357696518592af8a0b4555akrajcevski } 546c250d2e4abdbe8193357696518592af8a0b4555akrajcevski } 547c250d2e4abdbe8193357696518592af8a0b4555akrajcevski rowPtr += bitmap.rowBytes(); 548c250d2e4abdbe8193357696518592af8a0b4555akrajcevski } 549c250d2e4abdbe8193357696518592af8a0b4555akrajcevski } else { 550c250d2e4abdbe8193357696518592af8a0b4555akrajcevski for (int i = 0; i < height; ++i) { 551c250d2e4abdbe8193357696518592af8a0b4555akrajcevski if (!stream->write(rowPtr, bpp*width)) { 552c250d2e4abdbe8193357696518592af8a0b4555akrajcevski return false; 553c250d2e4abdbe8193357696518592af8a0b4555akrajcevski } 554c250d2e4abdbe8193357696518592af8a0b4555akrajcevski rowPtr += bitmap.rowBytes(); 555c250d2e4abdbe8193357696518592af8a0b4555akrajcevski } 556c250d2e4abdbe8193357696518592af8a0b4555akrajcevski } 557c250d2e4abdbe8193357696518592af8a0b4555akrajcevski 558c250d2e4abdbe8193357696518592af8a0b4555akrajcevski return true; 559c250d2e4abdbe8193357696518592af8a0b4555akrajcevski} 560