Home | History | Annotate | Download | only in ktx
      1 
      2 /*
      3  * Copyright 2014 Google Inc.
      4  *
      5  * Use of this source code is governed by a BSD-style license that can be
      6  * found in the LICENSE file.
      7  */
      8 
      9 #include "ktx.h"
     10 #include "SkBitmap.h"
     11 #include "SkStream.h"
     12 #include "SkEndian.h"
     13 
     14 #include "gl/GrGLDefines.h"
     15 
     16 #include "etc1.h"
     17 
     18 #define KTX_FILE_IDENTIFIER_SIZE 12
     19 static const uint8_t KTX_FILE_IDENTIFIER[KTX_FILE_IDENTIFIER_SIZE] = {
     20     0xAB, 0x4B, 0x54, 0x58, 0x20, 0x31, 0x31, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A
     21 };
     22 
     23 static const uint32_t kKTX_ENDIANNESS_CODE = 0x04030201;
     24 
     25 bool SkKTXFile::KeyValue::readKeyAndValue(const uint8_t* data) {
     26     const char *key = reinterpret_cast<const char *>(data);
     27     const char *value = key;
     28 
     29     size_t bytesRead = 0;
     30     while (*value != '\0' && bytesRead < this->fDataSz) {
     31         ++bytesRead;
     32         ++value;
     33     }
     34 
     35     // Error of some sort..
     36     if (bytesRead >= this->fDataSz) {
     37         return false;
     38     }
     39 
     40     // Read the zero terminator
     41     ++bytesRead;
     42     ++value;
     43 
     44     size_t bytesLeft = this->fDataSz - bytesRead;
     45 
     46     // We ignore the null terminator when setting the string value.
     47     this->fKey.set(key, bytesRead - 1);
     48     if (bytesLeft > 0) {
     49         this->fValue.set(value, bytesLeft - 1);
     50     } else {
     51         return false;
     52     }
     53 
     54     return true;
     55 }
     56 
     57 bool SkKTXFile::KeyValue::writeKeyAndValueForKTX(SkWStream* strm) {
     58     size_t bytesWritten = 0;
     59     if (!strm->write(&(this->fDataSz), 4)) {
     60         return false;
     61     }
     62 
     63     bytesWritten += 4;
     64 
     65     // Here we know that C-strings must end with a null terminating
     66     // character, so when we get a c_str(), it will have as many
     67     // bytes of data as size() returns plus a zero, so we just
     68     // write size() + 1 bytes into the stream.
     69 
     70     size_t keySize = this->fKey.size() + 1;
     71     if (!strm->write(this->fKey.c_str(), keySize)) {
     72         return false;
     73     }
     74 
     75     bytesWritten += keySize;
     76 
     77     size_t valueSize = this->fValue.size() + 1;
     78     if (!strm->write(this->fValue.c_str(), valueSize)) {
     79         return false;
     80     }
     81 
     82     bytesWritten += valueSize;
     83 
     84     size_t bytesWrittenPadFour = (bytesWritten + 3) & ~3;
     85     uint8_t nullBuf[4] = { 0, 0, 0, 0 };
     86 
     87     size_t padding = bytesWrittenPadFour - bytesWritten;
     88     SkASSERT(padding < 4);
     89 
     90     return strm->write(nullBuf, padding);
     91 }
     92 
     93 uint32_t SkKTXFile::readInt(const uint8_t** buf, size_t* bytesLeft) const {
     94     SkASSERT(NULL != buf && NULL != bytesLeft);
     95 
     96     uint32_t result;
     97 
     98     if (*bytesLeft < 4) {
     99         SkASSERT(false);
    100         return 0;
    101     }
    102 
    103     memcpy(&result, *buf, 4);
    104     *buf += 4;
    105 
    106     if (fSwapBytes) {
    107         SkEndianSwap32(result);
    108     }
    109 
    110     *bytesLeft -= 4;
    111 
    112     return result;
    113 }
    114 
    115 SkString SkKTXFile::getValueForKey(const SkString& key) const {
    116     const KeyValue *begin = this->fKeyValuePairs.begin();
    117     const KeyValue *end = this->fKeyValuePairs.end();
    118     for (const KeyValue *kv = begin; kv != end; ++kv) {
    119         if (kv->key() == key) {
    120             return kv->value();
    121         }
    122     }
    123     return SkString();
    124 }
    125 
    126 bool SkKTXFile::isETC1() const {
    127     return this->valid() && GR_GL_COMPRESSED_RGB8_ETC1 == fHeader.fGLInternalFormat;
    128 }
    129 
    130 bool SkKTXFile::isRGBA8() const {
    131     return this->valid() && GR_GL_RGBA8 == fHeader.fGLInternalFormat;
    132 }
    133 
    134 bool SkKTXFile::isRGB8() const {
    135     return this->valid() && GR_GL_RGB8 == fHeader.fGLInternalFormat;
    136 }
    137 
    138 bool SkKTXFile::readKTXFile(const uint8_t* data, size_t dataLen) {
    139     const uint8_t *buf = data;
    140     size_t bytesLeft = dataLen;
    141 
    142     // Make sure original KTX header is there... this should have been checked
    143     // already by a call to is_ktx()
    144     SkASSERT(bytesLeft > KTX_FILE_IDENTIFIER_SIZE);
    145     SkASSERT(0 == memcmp(KTX_FILE_IDENTIFIER, buf, KTX_FILE_IDENTIFIER_SIZE));
    146     buf += KTX_FILE_IDENTIFIER_SIZE;
    147     bytesLeft -= KTX_FILE_IDENTIFIER_SIZE;
    148 
    149     // Read header, but first make sure that we have the proper space: we need
    150     // two 32-bit ints: 1 for endianness, and another for the mandatory image
    151     // size after the header.
    152     if (bytesLeft < 8 + sizeof(Header)) {
    153         return false;
    154     }
    155 
    156     uint32_t endianness = this->readInt(&buf, &bytesLeft);
    157     fSwapBytes = kKTX_ENDIANNESS_CODE != endianness;
    158 
    159     // Read header values
    160     fHeader.fGLType                = this->readInt(&buf, &bytesLeft);
    161     fHeader.fGLTypeSize            = this->readInt(&buf, &bytesLeft);
    162     fHeader.fGLFormat              = this->readInt(&buf, &bytesLeft);
    163     fHeader.fGLInternalFormat      = this->readInt(&buf, &bytesLeft);
    164     fHeader.fGLBaseInternalFormat  = this->readInt(&buf, &bytesLeft);
    165     fHeader.fPixelWidth            = this->readInt(&buf, &bytesLeft);
    166     fHeader.fPixelHeight           = this->readInt(&buf, &bytesLeft);
    167     fHeader.fPixelDepth            = this->readInt(&buf, &bytesLeft);
    168     fHeader.fNumberOfArrayElements = this->readInt(&buf, &bytesLeft);
    169     fHeader.fNumberOfFaces         = this->readInt(&buf, &bytesLeft);
    170     fHeader.fNumberOfMipmapLevels  = this->readInt(&buf, &bytesLeft);
    171     fHeader.fBytesOfKeyValueData   = this->readInt(&buf, &bytesLeft);
    172 
    173     // Check for things that we understand...
    174     {
    175         // First, we only support compressed formats and single byte
    176         // representations at the moment. If the internal format is
    177         // compressed, the the GLType field in the header must be zero.
    178         // In the future, we may support additional data types (such
    179         // as GL_UNSIGNED_SHORT_5_6_5)
    180         if (fHeader.fGLType != 0 && fHeader.fGLType != GR_GL_UNSIGNED_BYTE) {
    181             return false;
    182         }
    183 
    184         // This means that for well-formatted KTX files, the glTypeSize
    185         // field must be one...
    186         if (fHeader.fGLTypeSize != 1) {
    187             return false;
    188         }
    189 
    190         // We don't support 3D textures.
    191         if (fHeader.fPixelDepth > 1) {
    192             return false;
    193         }
    194 
    195         // We don't support texture arrays
    196         if (fHeader.fNumberOfArrayElements > 1) {
    197             return false;
    198         }
    199 
    200         // We don't support cube maps
    201         if (fHeader.fNumberOfFaces > 1) {
    202             return false;
    203         }
    204     }
    205 
    206     // Make sure that we have enough bytes left for the key/value
    207     // data according to what was said in the header.
    208     if (bytesLeft < fHeader.fBytesOfKeyValueData) {
    209         return false;
    210     }
    211 
    212     // Next read the key value pairs
    213     size_t keyValueBytesRead = 0;
    214     while (keyValueBytesRead < fHeader.fBytesOfKeyValueData) {
    215         uint32_t keyValueBytes = this->readInt(&buf, &bytesLeft);
    216         keyValueBytesRead += 4;
    217 
    218         if (keyValueBytes > bytesLeft) {
    219             return false;
    220         }
    221 
    222         KeyValue kv(keyValueBytes);
    223         if (!kv.readKeyAndValue(buf)) {
    224             return false;
    225         }
    226 
    227         fKeyValuePairs.push_back(kv);
    228 
    229         uint32_t keyValueBytesPadded = (keyValueBytes + 3) & ~3;
    230         buf += keyValueBytesPadded;
    231         keyValueBytesRead += keyValueBytesPadded;
    232         bytesLeft -= keyValueBytesPadded;
    233     }
    234 
    235     // Read the pixel data...
    236     int mipmaps = SkMax32(fHeader.fNumberOfMipmapLevels, 1);
    237     SkASSERT(mipmaps == 1);
    238 
    239     int arrayElements = SkMax32(fHeader.fNumberOfArrayElements, 1);
    240     SkASSERT(arrayElements == 1);
    241 
    242     int faces = SkMax32(fHeader.fNumberOfFaces, 1);
    243     SkASSERT(faces == 1);
    244 
    245     int depth = SkMax32(fHeader.fPixelDepth, 1);
    246     SkASSERT(depth == 1);
    247 
    248     for (int mipmap = 0; mipmap < mipmaps; ++mipmap) {
    249         // Make sure that we have at least 4 more bytes for the first image size
    250         if (bytesLeft < 4) {
    251             return false;
    252         }
    253 
    254         uint32_t imgSize = this->readInt(&buf, &bytesLeft);
    255 
    256         // Truncated file.
    257         if (bytesLeft < imgSize) {
    258             return false;
    259         }
    260 
    261         // !FIXME! If support is ever added for cube maps then the padding
    262         // needs to be taken into account here.
    263         for (int arrayElement = 0; arrayElement < arrayElements; ++arrayElement) {
    264             for (int face = 0; face < faces; ++face) {
    265                 for (int z = 0; z < depth; ++z) {
    266                     PixelData pd(buf, imgSize);
    267                     fPixelData.append(1, &pd);
    268                 }
    269             }
    270         }
    271 
    272         uint32_t imgSizePadded = (imgSize + 3) & ~3;
    273         buf += imgSizePadded;
    274         bytesLeft -= imgSizePadded;
    275     }
    276 
    277     return bytesLeft == 0;
    278 }
    279 
    280 bool SkKTXFile::is_ktx(const uint8_t *data) {
    281     return 0 == memcmp(KTX_FILE_IDENTIFIER, data, KTX_FILE_IDENTIFIER_SIZE);
    282 }
    283 
    284 bool SkKTXFile::is_ktx(SkStreamRewindable* stream) {
    285     // Read the KTX header and make sure it's valid.
    286     unsigned char buf[KTX_FILE_IDENTIFIER_SIZE];
    287     bool largeEnough =
    288         stream->read((void*)buf, KTX_FILE_IDENTIFIER_SIZE) == KTX_FILE_IDENTIFIER_SIZE;
    289     stream->rewind();
    290     if (!largeEnough) {
    291         return false;
    292     }
    293     return is_ktx(buf);
    294 }
    295 
    296 SkKTXFile::KeyValue SkKTXFile::CreateKeyValue(const char *cstrKey, const char *cstrValue) {
    297     SkString key(cstrKey);
    298     SkString value(cstrValue);
    299 
    300     // Size of buffer is length of string plus the null terminators...
    301     size_t size = key.size() + 1 + value.size() + 1;
    302 
    303     SkAutoSMalloc<256> buf(size);
    304     uint8_t* kvBuf = reinterpret_cast<uint8_t*>(buf.get());
    305     memcpy(kvBuf, key.c_str(), key.size() + 1);
    306     memcpy(kvBuf + key.size() + 1, value.c_str(), value.size() + 1);
    307 
    308     KeyValue kv(size);
    309     SkAssertResult(kv.readKeyAndValue(kvBuf));
    310     return kv;
    311 }
    312 
    313 bool SkKTXFile::WriteETC1ToKTX(SkWStream* stream, const uint8_t *etc1Data,
    314                                uint32_t width, uint32_t height) {
    315     // First thing's first, write out the magic identifier and endianness...
    316     if (!stream->write(KTX_FILE_IDENTIFIER, KTX_FILE_IDENTIFIER_SIZE)) {
    317         return false;
    318     }
    319 
    320     if (!stream->write(&kKTX_ENDIANNESS_CODE, 4)) {
    321         return false;
    322     }
    323 
    324     Header hdr;
    325     hdr.fGLType = 0;
    326     hdr.fGLTypeSize = 1;
    327     hdr.fGLFormat = 0;
    328     hdr.fGLInternalFormat = GR_GL_COMPRESSED_RGB8_ETC1;
    329     hdr.fGLBaseInternalFormat = GR_GL_RGB;
    330     hdr.fPixelWidth = width;
    331     hdr.fPixelHeight = height;
    332     hdr.fNumberOfArrayElements = 0;
    333     hdr.fNumberOfFaces = 1;
    334     hdr.fNumberOfMipmapLevels = 1;
    335 
    336     // !FIXME! The spec suggests that we put KTXOrientation as a
    337     // key value pair in the header, but that means that we'd have to
    338     // pipe through the bitmap's orientation to properly do that.
    339     hdr.fBytesOfKeyValueData = 0;
    340 
    341     // Write the header
    342     if (!stream->write(&hdr, sizeof(hdr))) {
    343         return false;
    344     }
    345 
    346     // Write the size of the image data
    347     etc1_uint32 dataSize = etc1_get_encoded_data_size(width, height);
    348     if (!stream->write(&dataSize, 4)) {
    349         return false;
    350     }
    351 
    352     // Write the actual image data
    353     if (!stream->write(etc1Data, dataSize)) {
    354         return false;
    355     }
    356 
    357     return true;
    358 }
    359 
    360 bool SkKTXFile::WriteBitmapToKTX(SkWStream* stream, const SkBitmap& bitmap) {
    361     const SkColorType ct = bitmap.colorType();
    362     SkAutoLockPixels alp(bitmap);
    363 
    364     const int width = bitmap.width();
    365     const int height = bitmap.width();
    366     const uint8_t* src = reinterpret_cast<uint8_t*>(bitmap.getPixels());
    367     if (NULL == bitmap.getPixels()) {
    368         return false;
    369     }
    370 
    371     // First thing's first, write out the magic identifier and endianness...
    372     if (!stream->write(KTX_FILE_IDENTIFIER, KTX_FILE_IDENTIFIER_SIZE) ||
    373         !stream->write(&kKTX_ENDIANNESS_CODE, 4)) {
    374         return false;
    375     }
    376 
    377     // Collect our key/value pairs...
    378     SkTArray<KeyValue> kvPairs;
    379 
    380     // Next, write the header based on the bitmap's config.
    381     Header hdr;
    382     switch (ct) {
    383         case kIndex_8_SkColorType:
    384             // There is a compressed format for this, but we don't support it yet.
    385             SkDebugf("Writing indexed bitmap to KTX unsupported.\n");
    386             // VVV fall through VVV
    387         default:
    388         case kUnknown_SkColorType:
    389             // Bitmap hasn't been configured.
    390             return false;
    391 
    392         case kAlpha_8_SkColorType:
    393             hdr.fGLType = GR_GL_UNSIGNED_BYTE;
    394             hdr.fGLTypeSize = 1;
    395             hdr.fGLFormat = GR_GL_RED;
    396             hdr.fGLInternalFormat = GR_GL_R8;
    397             hdr.fGLBaseInternalFormat = GR_GL_RED;
    398             break;
    399 
    400         case kRGB_565_SkColorType:
    401             hdr.fGLType = GR_GL_UNSIGNED_SHORT_5_6_5;
    402             hdr.fGLTypeSize = 2;
    403             hdr.fGLFormat = GR_GL_RGB;
    404             hdr.fGLInternalFormat = GR_GL_RGB;
    405             hdr.fGLBaseInternalFormat = GR_GL_RGB;
    406             break;
    407 
    408         case kARGB_4444_SkColorType:
    409             hdr.fGLType = GR_GL_UNSIGNED_SHORT_4_4_4_4;
    410             hdr.fGLTypeSize = 2;
    411             hdr.fGLFormat = GR_GL_RGBA;
    412             hdr.fGLInternalFormat = GR_GL_RGBA4;
    413             hdr.fGLBaseInternalFormat = GR_GL_RGBA;
    414             kvPairs.push_back(CreateKeyValue("KTXPremultipliedAlpha", "True"));
    415             break;
    416 
    417         case kN32_SkColorType:
    418             hdr.fGLType = GR_GL_UNSIGNED_BYTE;
    419             hdr.fGLTypeSize = 1;
    420             hdr.fGLFormat = GR_GL_RGBA;
    421             hdr.fGLInternalFormat = GR_GL_RGBA8;
    422             hdr.fGLBaseInternalFormat = GR_GL_RGBA;
    423             kvPairs.push_back(CreateKeyValue("KTXPremultipliedAlpha", "True"));
    424             break;
    425     }
    426 
    427     // Everything else in the header is shared.
    428     hdr.fPixelWidth = width;
    429     hdr.fPixelHeight = height;
    430     hdr.fNumberOfArrayElements = 0;
    431     hdr.fNumberOfFaces = 1;
    432     hdr.fNumberOfMipmapLevels = 1;
    433 
    434     // Calculate the key value data size
    435     hdr.fBytesOfKeyValueData = 0;
    436     for (KeyValue *kv = kvPairs.begin(); kv != kvPairs.end(); ++kv) {
    437         // Key value size is the size of the key value data,
    438         // four bytes for saying how big the key value size is
    439         // and then additional bytes for padding to four byte boundary
    440         size_t kvsize = kv->size();
    441         kvsize += 4;
    442         kvsize = (kvsize + 3) & ~3;
    443         hdr.fBytesOfKeyValueData += kvsize;
    444     }
    445 
    446     // Write the header
    447     if (!stream->write(&hdr, sizeof(hdr))) {
    448         return false;
    449     }
    450 
    451     // Write out each key value pair
    452     for (KeyValue *kv = kvPairs.begin(); kv != kvPairs.end(); ++kv) {
    453         if (!kv->writeKeyAndValueForKTX(stream)) {
    454             return false;
    455         }
    456     }
    457 
    458     // Calculate the size of the data
    459     int bpp = bitmap.bytesPerPixel();
    460     uint32_t dataSz = bpp * width * height;
    461 
    462     if (0 >= bpp) {
    463         return false;
    464     }
    465 
    466     // Write it into the buffer
    467     if (!stream->write(&dataSz, 4)) {
    468         return false;
    469     }
    470 
    471     // Write the pixel data...
    472     const uint8_t* rowPtr = src;
    473     if (kN32_SkColorType == ct) {
    474         for (int j = 0; j < height; ++j) {
    475             const uint32_t* pixelsPtr = reinterpret_cast<const uint32_t*>(rowPtr);
    476             for (int i = 0; i < width; ++i) {
    477                 uint32_t pixel = pixelsPtr[i];
    478                 uint8_t dstPixel[4];
    479                 dstPixel[0] = pixel >> SK_R32_SHIFT;
    480                 dstPixel[1] = pixel >> SK_G32_SHIFT;
    481                 dstPixel[2] = pixel >> SK_B32_SHIFT;
    482                 dstPixel[3] = pixel >> SK_A32_SHIFT;
    483                 if (!stream->write(dstPixel, 4)) {
    484                     return false;
    485                 }
    486             }
    487             rowPtr += bitmap.rowBytes();
    488         }
    489     } else {
    490         for (int i = 0; i < height; ++i) {
    491             if (!stream->write(rowPtr, bpp*width)) {
    492                 return false;
    493             }
    494             rowPtr += bitmap.rowBytes();
    495         }
    496     }
    497 
    498     return true;
    499 }
    500