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