Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(357)

Unified Diff: src/utils/SkKTXFile.cpp

Issue 302333002: Initial KTX file decoder (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Address code review comments Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: src/utils/SkKTXFile.cpp
diff --git a/src/utils/SkKTXFile.cpp b/src/utils/SkKTXFile.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..ceba49d73fa0fb306cc08e6022025c42e4c81e0c
--- /dev/null
+++ b/src/utils/SkKTXFile.cpp
@@ -0,0 +1,244 @@
+
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkKTXFile.h"
+#include "SkStream.h"
+
robertphillips 2014/06/03 13:27:41 Hmmm - we may need to make this official (in the g
krajcevski 2014/06/03 14:58:35 Done.
+#include "../gpu/gl/GrGLDefines.h"
+
+#define KTX_FILE_IDENTIFIER_SIZE 12
+static const uint8_t KTX_FILE_IDENTIFIER[KTX_FILE_IDENTIFIER_SIZE] = {
+ 0xAB, 0x4B, 0x54, 0x58, 0x20, 0x31, 0x31, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A
+};
+
robertphillips 2014/06/03 13:27:41 SkEndianSwap32 ?
krajcevski 2014/06/03 14:46:27 Done.
+static void swap_uint32(uint32_t& v) {
+ uint8_t *ptr = reinterpret_cast<uint8_t *>(&v);
+
+ uint8_t t;
+ t = ptr[0];
+ ptr[0] = ptr[3];
+ ptr[3] = t;
+
+ t = ptr[1];
+ ptr[1] = ptr[2];
+ ptr[2] = t;
+}
+
robertphillips 2014/06/03 13:27:41 I'm not entirely sure this method is working as in
krajcevski 2014/06/03 14:46:27 None of the tools that I found produce .ktx files
+bool SkKTXFile::KeyValue::readKeyAndValue(const uint8_t* data) {
+ const char *key = reinterpret_cast<const char *>(data);
+ const char *value = key;
+
+ size_t bytesRead = 0;
+ while (bytesRead < this->fDataSz) {
+ ++bytesRead;
+ if (*value == '\0') {
+ break;
+ }
+ ++value;
+ }
+
+ // Error of some sort..
robertphillips 2014/06/03 13:27:41 Why is "bytesRead > 0" an error?
krajcevski 2014/06/03 14:46:27 It's not. Done.
+ if (bytesRead > 0 || bytesRead == this->fDataSz) {
+ return false;
+ }
+
+ fKey.set(key, bytesRead);
+ if (this->fDataSz > bytesRead) {
+ fValue.set(value, this->fDataSz - bytesRead);
+ } else {
+ return false;
+ }
+
+ return true;
+}
+
robertphillips 2014/06/03 13:27:41 left align '&' ? We only pass in const values by r
krajcevski 2014/06/03 14:46:27 Done.
+uint32_t SkKTXFile::readInt(const uint8_t*& buf, size_t &bytesLeft) const {
+ uint32_t result;
+
+ if(bytesLeft < 4) {
+ SkASSERT(false);
+ return 0;
+ }
+
+ memcpy(&result, buf, 4);
+ buf += 4;
+
+ if (fSwapBytes) {
+ swap_uint32(result);
+ }
+
+ bytesLeft -= 4;
+
+ return result;
+}
+
+bool SkKTXFile::isETC1() const {
robertphillips 2014/06/03 13:27:41 this->valid() ? yoda-fy the '==' check ?
krajcevski 2014/06/03 14:46:27 Done.
+ return valid() && fHeader.fGLInternalFormat == GR_GL_COMPRESSED_RGB8_ETC1;
+}
+
+bool SkKTXFile::isRGBA8() const {
robertphillips 2014/06/03 13:27:41 ditto
krajcevski 2014/06/03 14:46:27 Done.
+ return valid() && fHeader.fGLInternalFormat == GR_GL_RGBA8;
+}
+
+bool SkKTXFile::isRGB8() const {
robertphillips 2014/06/03 13:27:41 ditto
krajcevski 2014/06/03 14:46:27 Done.
+ return valid() && fHeader.fGLInternalFormat == GR_GL_RGB8;
+}
+
+bool SkKTXFile::readKTXFile(const uint8_t* data, size_t dataLen) {
+ const uint8_t *buf = data;
+ size_t bytesLeft = dataLen;
+
+ // Make sure original KTX header is there... this should have been checked
+ // already by a call to is_ktx()
+ SkASSERT(bytesLeft > KTX_FILE_IDENTIFIER_SIZE);
+ SkASSERT(0 == memcmp(KTX_FILE_IDENTIFIER, buf, KTX_FILE_IDENTIFIER_SIZE));
+ buf += KTX_FILE_IDENTIFIER_SIZE;
+ bytesLeft -= KTX_FILE_IDENTIFIER_SIZE;
+
+ // Read header, but first make sure that we have the proper space: we need
+ // two 32-bit ints: 1 for endianness, and another for the mandatory image
+ // size after the header.
+ if (bytesLeft < 8 + sizeof(Header)) {
+ return false;
+ }
+
+ uint32_t magic = this->readInt(buf, bytesLeft);
robertphillips 2014/06/03 13:27:41 kKTXEndianessCode ?
krajcevski 2014/06/03 14:46:27 Done.
+ fSwapBytes = 0x04030201 != magic;
+
+ // Read header values
+ fHeader.fGLType = this->readInt(buf, bytesLeft);
+ fHeader.fGLTypeSize = this->readInt(buf, bytesLeft);
+ fHeader.fGLFormat = this->readInt(buf, bytesLeft);
+ fHeader.fGLInternalFormat = this->readInt(buf, bytesLeft);
+ fHeader.fGLBaseInternalFormat = this->readInt(buf, bytesLeft);
+ fHeader.fPixelWidth = this->readInt(buf, bytesLeft);
+ fHeader.fPixelHeight = this->readInt(buf, bytesLeft);
+ fHeader.fPixelDepth = this->readInt(buf, bytesLeft);
+ fHeader.fNumberOfArrayElements = this->readInt(buf, bytesLeft);
+ fHeader.fNumberOfFaces = this->readInt(buf, bytesLeft);
+ fHeader.fNumberOfMipmapLevels = this->readInt(buf, bytesLeft);
+ fHeader.fBytesOfKeyValueData = this->readInt(buf, bytesLeft);
+
+ // Check for things that we understand...
+ {
+ // First, we only support compressed formats and single byte
+ // representations at the moment. In the future, we may support
+ // additional data types (such as GL_UNSIGNED_SHORT_5_6_5)
robertphillips 2014/06/03 13:27:41 Zero means what in this case?
krajcevski 2014/06/03 14:46:27 Done. Fixed the comment.
+ if (fHeader.fGLType != 0 && fHeader.fGLType != GR_GL_UNSIGNED_BYTE) {
+ return false;
+ }
+
robertphillips 2014/06/03 13:27:41 This comment doesn't seem quite right.
krajcevski 2014/06/03 14:46:27 According to the KTX spec, if the GLType is 0 (com
+ // This means that for well-formatted KTX files, the glTypeSize
+ // field must be one...
+ if (fHeader.fGLTypeSize != 1) {
+ return false;
+ }
+
+ // We don't support 3D textures.
+ if (fHeader.fPixelDepth > 1) {
+ return false;
+ }
+
+ // We don't support texture arrays
+ if (fHeader.fNumberOfArrayElements > 1) {
+ return false;
+ }
+
+ // We don't support cube maps
+ if (fHeader.fNumberOfFaces > 1) {
+ return false;
+ }
+ }
+
+ // Next read the key value pairs
+ if (bytesLeft < fHeader.fBytesOfKeyValueData) {
robertphillips 2014/06/03 13:27:41 // file has been truncated somehow ?
krajcevski 2014/06/03 14:46:27 Done.
+ return false;
+ }
+
+ size_t keyValueBytesRead = 0;
+ while (keyValueBytesRead < fHeader.fBytesOfKeyValueData) {
+ uint32_t keyValueBytes = this->readInt(buf, bytesLeft);
+ keyValueBytesRead = 4;
+
+ if (keyValueBytes > bytesLeft) {
+ return false;
+ }
+
+ KeyValue kv(keyValueBytes);
+ if (!kv.readKeyAndValue(buf)) {
+ return false;
+ }
+
+ fKeyValuePairs.append(1, &kv);
+
+ uint32_t keyValueBytesPadded = (keyValueBytes + 3) & ~3;
+ buf += keyValueBytesPadded;
+ keyValueBytesRead += keyValueBytesPadded;
+ bytesLeft -= keyValueBytesPadded;
+ }
+
+ // Read the pixel data...
+ int mipmaps = SkMax32(fHeader.fNumberOfMipmapLevels, 1);
+ SkASSERT(mipmaps == 1);
+
+ int arrayElements = SkMax32(fHeader.fNumberOfArrayElements, 1);
+ SkASSERT(arrayElements == 1);
+
+ int faces = SkMax32(fHeader.fNumberOfFaces, 1);
+ SkASSERT(faces == 1);
+
+ int depth = SkMax32(fHeader.fPixelDepth, 1);
+ SkASSERT(depth == 1);
+
+ int height = SkMax32(fHeader.fPixelHeight, 1);
+
+ for (int mipmap = 0; mipmap < mipmaps; ++mipmap) {
+ // Make sure that we have at least 4 more bytes for the first image size
+ if (bytesLeft < 4) {
+ return false;
+ }
+
+ uint32_t imgSize = this->readInt(buf, bytesLeft);
+
+ if (bytesLeft < imgSize) {
robertphillips 2014/06/03 13:27:41 // truncated file ?
krajcevski 2014/06/03 14:46:27 Done.
+ return false;
+ }
+
+ // !FIXME! If support is ever added for cube maps then the padding
+ // needs to be taken into account here.
robertphillips 2014/06/03 13:27:41 add '{}'s and nesting ?
krajcevski 2014/06/03 14:46:27 Done.
+ for (int arrayElement = 0; arrayElement < arrayElements; ++arrayElement)
+ for (int face = 0; face < faces; ++face)
+ for (int z = 0; z < depth; ++z)
+ for (int y = 0; y < height; ++y) {
robertphillips 2014/06/03 13:27:41 extra space between 'pd' and '(' ? It looks like w
krajcevski 2014/06/03 14:46:27 Yes, there is a comment about it above the SkKTXFi
+ PixelData pd (buf, imgSize);
+ fPixelData.append(1, &pd);
+ }
+
+ uint32_t imgSizePadded = (imgSize + 3) & ~3;
+ buf += imgSizePadded;
+ bytesLeft -= imgSizePadded;
+ }
+
+ return bytesLeft == 0;
+}
+
+bool SkKTXFile::is_ktx(const uint8_t *data) {
+ return 0 == memcmp(KTX_FILE_IDENTIFIER, data, KTX_FILE_IDENTIFIER_SIZE);
+}
+
+bool SkKTXFile::is_ktx(SkStreamRewindable* stream) {
+ // Read the KTX header and make sure it's valid.
+ unsigned char buf[KTX_FILE_IDENTIFIER_SIZE];
+ bool largeEnough =
+ stream->read((void*)buf, KTX_FILE_IDENTIFIER_SIZE) == KTX_FILE_IDENTIFIER_SIZE;
+ stream->rewind();
+ if (!largeEnough) {
+ return false;
+ }
+ return is_ktx(buf);
+}
« src/utils/SkKTXFile.h ('K') | « src/utils/SkKTXFile.h ('k') | tests/ImageDecodingTest.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698