Remove all KTX support
It is untested and unused. Change-Id: I010ff4ad942738f362d42a99af4edbbb1cb0cd71 Reviewed-on: https://skia-review.googlesource.com/6142 Commit-Queue: Leon Scroggins <scroggo@google.com> Reviewed-by: Mike Klein <mtklein@chromium.org> Reviewed-by: Robert Phillips <robertphillips@google.com>
This commit is contained in:
parent
1b9924ffb7
commit
ada12ab055
2
BUILD.gn
2
BUILD.gn
@ -110,7 +110,6 @@ config("skia_private") {
|
||||
"src/utils/win",
|
||||
"third_party/etc1",
|
||||
"third_party/gif",
|
||||
"third_party/ktx",
|
||||
]
|
||||
|
||||
defines = [
|
||||
@ -590,7 +589,6 @@ component("skia") {
|
||||
"src/utils/mac/SkStream_mac.cpp",
|
||||
"third_party/etc1/etc1.cpp",
|
||||
"third_party/gif/SkGifImageReader.cpp",
|
||||
"third_party/ktx/ktx.cpp",
|
||||
]
|
||||
|
||||
libs = []
|
||||
|
@ -80,7 +80,6 @@
|
||||
'core.gyp:*',
|
||||
'utils.gyp:utils',
|
||||
'etc1.gyp:libetc1',
|
||||
'ktx.gyp:libSkKTX',
|
||||
'sksl.gyp:sksl',
|
||||
],
|
||||
'include_dirs': [
|
||||
|
34
gyp/ktx.gyp
34
gyp/ktx.gyp
@ -1,34 +0,0 @@
|
||||
# Copyright 2015 Google Inc.
|
||||
#
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
{
|
||||
'variables': {
|
||||
'skia_warnings_as_errors': 0,
|
||||
},
|
||||
'targets': [
|
||||
{
|
||||
'target_name': 'libSkKTX',
|
||||
'type': 'static_library',
|
||||
'include_dirs' : [
|
||||
'../third_party/ktx',
|
||||
'../include/gpu',
|
||||
'../include/private',
|
||||
'../src/core',
|
||||
'../src/gpu',
|
||||
'../src/utils',
|
||||
],
|
||||
'sources': [
|
||||
'../third_party/ktx/ktx.cpp',
|
||||
],
|
||||
'dependencies': [
|
||||
'core.gyp:*',
|
||||
'etc1.gyp:libetc1',
|
||||
],
|
||||
'direct_dependent_settings': {
|
||||
'include_dirs': [
|
||||
'../third_party/ktx',
|
||||
],
|
||||
},
|
||||
}],
|
||||
}
|
@ -86,8 +86,6 @@ BASE_SRCS_ALL = struct(
|
||||
"third_party/etc1/*.h",
|
||||
"third_party/gif/*.cpp",
|
||||
"third_party/gif/*.h",
|
||||
"third_party/ktx/*.cpp",
|
||||
"third_party/ktx/*.h",
|
||||
],
|
||||
# Note: PRIVATE_HDRS_INCLUDE_LIST is excluded from BASE_SRCS_ALL here
|
||||
# because they are required to appear in srcs for some rules but hdrs for
|
||||
@ -385,7 +383,6 @@ INCLUDES = [
|
||||
"src/utils",
|
||||
"third_party/etc1",
|
||||
"third_party/gif",
|
||||
"third_party/ktx",
|
||||
]
|
||||
|
||||
################################################################################
|
||||
|
@ -40,7 +40,6 @@
|
||||
#include "effects/GrYUVEffect.h"
|
||||
|
||||
#ifndef SK_IGNORE_ETC1_SUPPORT
|
||||
# include "ktx.h"
|
||||
# include "etc1.h"
|
||||
#endif
|
||||
|
||||
@ -88,22 +87,6 @@ GrPixelConfig GrIsCompressedTextureDataSupported(GrContext* ctx, SkData* data,
|
||||
|
||||
*outStartOfDataToUpload = bytes + ETC_PKM_HEADER_SIZE;
|
||||
return kETC1_GrPixelConfig;
|
||||
} else if (SkKTXFile::is_ktx(bytes, data->size())) {
|
||||
SkKTXFile ktx(data);
|
||||
|
||||
// Is it actually an ETC1 texture?
|
||||
if (!ktx.isCompressedFormat(SkTextureCompressor::kETC1_Format)) {
|
||||
return kUnknown_GrPixelConfig;
|
||||
}
|
||||
|
||||
// Does the data match the dimensions of the bitmap? If not,
|
||||
// then we don't know how to scale the image to match it...
|
||||
if (ktx.width() != expectedW || ktx.height() != expectedH) {
|
||||
return kUnknown_GrPixelConfig;
|
||||
}
|
||||
|
||||
*outStartOfDataToUpload = ktx.pixelData();
|
||||
return kETC1_GrPixelConfig;
|
||||
}
|
||||
#endif
|
||||
return kUnknown_GrPixelConfig;
|
||||
|
565
third_party/ktx/ktx.cpp
vendored
565
third_party/ktx/ktx.cpp
vendored
@ -1,565 +0,0 @@
|
||||
/*
|
||||
* 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 "ktx.h"
|
||||
#include "SkBitmap.h"
|
||||
#include "SkStream.h"
|
||||
#include "SkEndian.h"
|
||||
|
||||
#include "gl/GrGLDefines.h"
|
||||
#include "GrConfig.h"
|
||||
|
||||
#include "etc1.h"
|
||||
|
||||
static inline uint32_t compressed_fmt_to_gl_define(SkTextureCompressor::Format fmt) {
|
||||
static const uint32_t kGLDefineMap[SkTextureCompressor::kFormatCnt] = {
|
||||
GR_GL_COMPRESSED_LUMINANCE_LATC1, // kLATC_Format
|
||||
GR_GL_COMPRESSED_R11_EAC, // kR11_EAC_Format
|
||||
GR_GL_COMPRESSED_ETC1_RGB8, // kETC1_Format
|
||||
GR_GL_COMPRESSED_RGBA_ASTC_4x4, // kASTC_4x4_Format
|
||||
GR_GL_COMPRESSED_RGBA_ASTC_5x4, // kASTC_5x4_Format
|
||||
GR_GL_COMPRESSED_RGBA_ASTC_5x5, // kASTC_5x5_Format
|
||||
GR_GL_COMPRESSED_RGBA_ASTC_6x5, // kASTC_6x5_Format
|
||||
GR_GL_COMPRESSED_RGBA_ASTC_6x6, // kASTC_6x6_Format
|
||||
GR_GL_COMPRESSED_RGBA_ASTC_8x5, // kASTC_8x5_Format
|
||||
GR_GL_COMPRESSED_RGBA_ASTC_8x6, // kASTC_8x6_Format
|
||||
GR_GL_COMPRESSED_RGBA_ASTC_8x8, // kASTC_8x8_Format
|
||||
GR_GL_COMPRESSED_RGBA_ASTC_10x5, // kASTC_10x5_Format
|
||||
GR_GL_COMPRESSED_RGBA_ASTC_10x6, // kASTC_10x6_Format
|
||||
GR_GL_COMPRESSED_RGBA_ASTC_10x8, // kASTC_10x8_Format
|
||||
GR_GL_COMPRESSED_RGBA_ASTC_10x10, // kASTC_10x10_Format
|
||||
GR_GL_COMPRESSED_RGBA_ASTC_12x10, // kASTC_12x10_Format
|
||||
GR_GL_COMPRESSED_RGBA_ASTC_12x12, // kASTC_12x12_Format
|
||||
};
|
||||
|
||||
GR_STATIC_ASSERT(0 == SkTextureCompressor::kLATC_Format);
|
||||
GR_STATIC_ASSERT(1 == SkTextureCompressor::kR11_EAC_Format);
|
||||
GR_STATIC_ASSERT(2 == SkTextureCompressor::kETC1_Format);
|
||||
GR_STATIC_ASSERT(3 == SkTextureCompressor::kASTC_4x4_Format);
|
||||
GR_STATIC_ASSERT(4 == SkTextureCompressor::kASTC_5x4_Format);
|
||||
GR_STATIC_ASSERT(5 == SkTextureCompressor::kASTC_5x5_Format);
|
||||
GR_STATIC_ASSERT(6 == SkTextureCompressor::kASTC_6x5_Format);
|
||||
GR_STATIC_ASSERT(7 == SkTextureCompressor::kASTC_6x6_Format);
|
||||
GR_STATIC_ASSERT(8 == SkTextureCompressor::kASTC_8x5_Format);
|
||||
GR_STATIC_ASSERT(9 == SkTextureCompressor::kASTC_8x6_Format);
|
||||
GR_STATIC_ASSERT(10 == SkTextureCompressor::kASTC_8x8_Format);
|
||||
GR_STATIC_ASSERT(11 == SkTextureCompressor::kASTC_10x5_Format);
|
||||
GR_STATIC_ASSERT(12 == SkTextureCompressor::kASTC_10x6_Format);
|
||||
GR_STATIC_ASSERT(13 == SkTextureCompressor::kASTC_10x8_Format);
|
||||
GR_STATIC_ASSERT(14 == SkTextureCompressor::kASTC_10x10_Format);
|
||||
GR_STATIC_ASSERT(15 == SkTextureCompressor::kASTC_12x10_Format);
|
||||
GR_STATIC_ASSERT(16 == SkTextureCompressor::kASTC_12x12_Format);
|
||||
GR_STATIC_ASSERT(SK_ARRAY_COUNT(kGLDefineMap) == SkTextureCompressor::kFormatCnt);
|
||||
|
||||
return kGLDefineMap[fmt];
|
||||
}
|
||||
|
||||
#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
|
||||
};
|
||||
|
||||
static const uint32_t kKTX_ENDIANNESS_CODE = 0x04030201;
|
||||
|
||||
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 (*value != '\0' && bytesRead < this->fDataSz) {
|
||||
++bytesRead;
|
||||
++value;
|
||||
}
|
||||
|
||||
// Error of some sort..
|
||||
if (bytesRead >= this->fDataSz) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read the zero terminator
|
||||
++bytesRead;
|
||||
++value;
|
||||
|
||||
size_t bytesLeft = this->fDataSz - bytesRead;
|
||||
|
||||
// We ignore the null terminator when setting the string value.
|
||||
this->fKey.set(key, bytesRead - 1);
|
||||
if (bytesLeft > 0) {
|
||||
this->fValue.set(value, bytesLeft - 1);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SkKTXFile::KeyValue::writeKeyAndValueForKTX(SkWStream* strm) {
|
||||
size_t bytesWritten = 0;
|
||||
if (!strm->write(&(this->fDataSz), 4)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bytesWritten += 4;
|
||||
|
||||
// Here we know that C-strings must end with a null terminating
|
||||
// character, so when we get a c_str(), it will have as many
|
||||
// bytes of data as size() returns plus a zero, so we just
|
||||
// write size() + 1 bytes into the stream.
|
||||
|
||||
size_t keySize = this->fKey.size() + 1;
|
||||
if (!strm->write(this->fKey.c_str(), keySize)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bytesWritten += keySize;
|
||||
|
||||
size_t valueSize = this->fValue.size() + 1;
|
||||
if (!strm->write(this->fValue.c_str(), valueSize)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bytesWritten += valueSize;
|
||||
|
||||
size_t bytesWrittenPadFour = (bytesWritten + 3) & ~3;
|
||||
uint8_t nullBuf[4] = { 0, 0, 0, 0 };
|
||||
|
||||
size_t padding = bytesWrittenPadFour - bytesWritten;
|
||||
SkASSERT(padding < 4);
|
||||
|
||||
return strm->write(nullBuf, padding);
|
||||
}
|
||||
|
||||
uint32_t SkKTXFile::readInt(const uint8_t** buf, size_t* bytesLeft) const {
|
||||
SkASSERT(buf && bytesLeft);
|
||||
|
||||
uint32_t result;
|
||||
|
||||
if (*bytesLeft < 4) {
|
||||
SkASSERT(false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
memcpy(&result, *buf, 4);
|
||||
*buf += 4;
|
||||
|
||||
if (fSwapBytes) {
|
||||
SkEndianSwap32(result);
|
||||
}
|
||||
|
||||
*bytesLeft -= 4;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
SkString SkKTXFile::getValueForKey(const SkString& key) const {
|
||||
const KeyValue *begin = this->fKeyValuePairs.begin();
|
||||
const KeyValue *end = this->fKeyValuePairs.end();
|
||||
for (const KeyValue *kv = begin; kv != end; ++kv) {
|
||||
if (kv->key() == key) {
|
||||
return kv->value();
|
||||
}
|
||||
}
|
||||
return SkString();
|
||||
}
|
||||
|
||||
bool SkKTXFile::isCompressedFormat(SkTextureCompressor::Format fmt) const {
|
||||
if (!this->valid()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// This has many aliases
|
||||
bool isFmt = false;
|
||||
if (fmt == SkTextureCompressor::kLATC_Format) {
|
||||
isFmt = GR_GL_COMPRESSED_RED_RGTC1 == fHeader.fGLInternalFormat ||
|
||||
GR_GL_COMPRESSED_3DC_X == fHeader.fGLInternalFormat;
|
||||
}
|
||||
|
||||
return isFmt || compressed_fmt_to_gl_define(fmt) == fHeader.fGLInternalFormat;
|
||||
}
|
||||
|
||||
bool SkKTXFile::isRGBA8() const {
|
||||
return this->valid() && GR_GL_RGBA8 == fHeader.fGLInternalFormat;
|
||||
}
|
||||
|
||||
bool SkKTXFile::isRGB8() const {
|
||||
return this->valid() && GR_GL_RGB8 == fHeader.fGLInternalFormat;
|
||||
}
|
||||
|
||||
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 endianness = this->readInt(&buf, &bytesLeft);
|
||||
fSwapBytes = kKTX_ENDIANNESS_CODE != endianness;
|
||||
|
||||
// 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. If the internal format is
|
||||
// compressed, the the GLType field in the header must be zero.
|
||||
// In the future, we may support additional data types (such
|
||||
// as GL_UNSIGNED_SHORT_5_6_5)
|
||||
if (fHeader.fGLType != 0 && fHeader.fGLType != GR_GL_UNSIGNED_BYTE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
// We don't support width and/or height <= 0
|
||||
if (fHeader.fPixelWidth <= 0 || fHeader.fPixelHeight <= 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure that we have enough bytes left for the key/value
|
||||
// data according to what was said in the header.
|
||||
if (bytesLeft < fHeader.fBytesOfKeyValueData) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Next read the key value pairs
|
||||
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.push_back(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);
|
||||
|
||||
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);
|
||||
|
||||
// Truncated file.
|
||||
if (bytesLeft < imgSize) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// !FIXME! If support is ever added for cube maps then the padding
|
||||
// needs to be taken into account here.
|
||||
for (int arrayElement = 0; arrayElement < arrayElements; ++arrayElement) {
|
||||
for (int face = 0; face < faces; ++face) {
|
||||
for (int z = 0; z < depth; ++z) {
|
||||
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[], size_t size) {
|
||||
return size >= KTX_FILE_IDENTIFIER_SIZE &&
|
||||
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, KTX_FILE_IDENTIFIER_SIZE);
|
||||
}
|
||||
|
||||
SkKTXFile::KeyValue SkKTXFile::CreateKeyValue(const char *cstrKey, const char *cstrValue) {
|
||||
SkString key(cstrKey);
|
||||
SkString value(cstrValue);
|
||||
|
||||
// Size of buffer is length of string plus the null terminators...
|
||||
size_t size = key.size() + 1 + value.size() + 1;
|
||||
|
||||
SkAutoSMalloc<256> buf(size);
|
||||
uint8_t* kvBuf = reinterpret_cast<uint8_t*>(buf.get());
|
||||
memcpy(kvBuf, key.c_str(), key.size() + 1);
|
||||
memcpy(kvBuf + key.size() + 1, value.c_str(), value.size() + 1);
|
||||
|
||||
KeyValue kv(size);
|
||||
SkAssertResult(kv.readKeyAndValue(kvBuf));
|
||||
return kv;
|
||||
}
|
||||
|
||||
bool SkKTXFile::WriteETC1ToKTX(SkWStream* stream, const uint8_t *etc1Data,
|
||||
uint32_t width, uint32_t height) {
|
||||
// First thing's first, write out the magic identifier and endianness...
|
||||
if (!stream->write(KTX_FILE_IDENTIFIER, KTX_FILE_IDENTIFIER_SIZE)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!stream->write(&kKTX_ENDIANNESS_CODE, 4)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Header hdr;
|
||||
hdr.fGLType = 0;
|
||||
hdr.fGLTypeSize = 1;
|
||||
hdr.fGLFormat = 0;
|
||||
hdr.fGLInternalFormat = GR_GL_COMPRESSED_ETC1_RGB8;
|
||||
hdr.fGLBaseInternalFormat = GR_GL_RGB;
|
||||
hdr.fPixelWidth = width;
|
||||
hdr.fPixelHeight = height;
|
||||
hdr.fNumberOfArrayElements = 0;
|
||||
hdr.fNumberOfFaces = 1;
|
||||
hdr.fNumberOfMipmapLevels = 1;
|
||||
|
||||
// !FIXME! The spec suggests that we put KTXOrientation as a
|
||||
// key value pair in the header, but that means that we'd have to
|
||||
// pipe through the pixmap's orientation to properly do that.
|
||||
hdr.fBytesOfKeyValueData = 0;
|
||||
|
||||
// Write the header
|
||||
if (!stream->write(&hdr, sizeof(hdr))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Write the size of the image data
|
||||
etc1_uint32 dataSize = etc1_get_encoded_data_size(width, height);
|
||||
if (!stream->write(&dataSize, 4)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Write the actual image data
|
||||
if (!stream->write(etc1Data, dataSize)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SkKTXFile::WritePixmapToKTX(SkWStream* stream, const SkPixmap& pixmap) {
|
||||
const SkColorType ct = pixmap.colorType();
|
||||
|
||||
const int width = pixmap.width();
|
||||
const int height = pixmap.height();
|
||||
const uint8_t* src = reinterpret_cast<const uint8_t*>(pixmap.addr());
|
||||
if (!src) {
|
||||
return false;
|
||||
}
|
||||
const size_t rowBytes = pixmap.rowBytes();
|
||||
const int bytesPerPixel = pixmap.info().bytesPerPixel();
|
||||
|
||||
// First thing's first, write out the magic identifier and endianness...
|
||||
if (!stream->write(KTX_FILE_IDENTIFIER, KTX_FILE_IDENTIFIER_SIZE) ||
|
||||
!stream->write(&kKTX_ENDIANNESS_CODE, 4)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Collect our key/value pairs...
|
||||
SkTArray<KeyValue> kvPairs;
|
||||
|
||||
// Next, write the header based on the pixmap's config.
|
||||
Header hdr;
|
||||
switch (ct) {
|
||||
case kIndex_8_SkColorType:
|
||||
// There is a compressed format for this, but we don't support it yet.
|
||||
SkDebugf("Writing indexed pixmap to KTX unsupported.\n");
|
||||
// VVV fall through VVV
|
||||
default:
|
||||
case kUnknown_SkColorType:
|
||||
// Pixmap hasn't been configured.
|
||||
return false;
|
||||
|
||||
case kAlpha_8_SkColorType:
|
||||
hdr.fGLType = GR_GL_UNSIGNED_BYTE;
|
||||
hdr.fGLTypeSize = 1;
|
||||
hdr.fGLFormat = GR_GL_RED;
|
||||
hdr.fGLInternalFormat = GR_GL_R8;
|
||||
hdr.fGLBaseInternalFormat = GR_GL_RED;
|
||||
break;
|
||||
|
||||
case kRGB_565_SkColorType:
|
||||
hdr.fGLType = GR_GL_UNSIGNED_SHORT_5_6_5;
|
||||
hdr.fGLTypeSize = 2;
|
||||
hdr.fGLFormat = GR_GL_RGB;
|
||||
hdr.fGLInternalFormat = GR_GL_RGB;
|
||||
hdr.fGLBaseInternalFormat = GR_GL_RGB;
|
||||
break;
|
||||
|
||||
case kARGB_4444_SkColorType:
|
||||
hdr.fGLType = GR_GL_UNSIGNED_SHORT_4_4_4_4;
|
||||
hdr.fGLTypeSize = 2;
|
||||
hdr.fGLFormat = GR_GL_RGBA;
|
||||
hdr.fGLInternalFormat = GR_GL_RGBA4;
|
||||
hdr.fGLBaseInternalFormat = GR_GL_RGBA;
|
||||
kvPairs.push_back(CreateKeyValue("KTXPremultipliedAlpha", "True"));
|
||||
break;
|
||||
|
||||
case kN32_SkColorType:
|
||||
hdr.fGLType = GR_GL_UNSIGNED_BYTE;
|
||||
hdr.fGLTypeSize = 1;
|
||||
hdr.fGLFormat = GR_GL_RGBA;
|
||||
hdr.fGLInternalFormat = GR_GL_RGBA8;
|
||||
hdr.fGLBaseInternalFormat = GR_GL_RGBA;
|
||||
kvPairs.push_back(CreateKeyValue("KTXPremultipliedAlpha", "True"));
|
||||
break;
|
||||
}
|
||||
|
||||
// Everything else in the header is shared.
|
||||
hdr.fPixelWidth = width;
|
||||
hdr.fPixelHeight = height;
|
||||
hdr.fNumberOfArrayElements = 0;
|
||||
hdr.fNumberOfFaces = 1;
|
||||
hdr.fNumberOfMipmapLevels = 1;
|
||||
|
||||
// Calculate the key value data size
|
||||
hdr.fBytesOfKeyValueData = 0;
|
||||
for (KeyValue *kv = kvPairs.begin(); kv != kvPairs.end(); ++kv) {
|
||||
// Key value size is the size of the key value data,
|
||||
// four bytes for saying how big the key value size is
|
||||
// and then additional bytes for padding to four byte boundary
|
||||
size_t kvsize = kv->size();
|
||||
kvsize += 4;
|
||||
kvsize = (kvsize + 3) & ~3;
|
||||
hdr.fBytesOfKeyValueData = SkToU32(hdr.fBytesOfKeyValueData + kvsize);
|
||||
}
|
||||
|
||||
// Write the header
|
||||
if (!stream->write(&hdr, sizeof(hdr))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Write out each key value pair
|
||||
for (KeyValue *kv = kvPairs.begin(); kv != kvPairs.end(); ++kv) {
|
||||
if (!kv->writeKeyAndValueForKTX(stream)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate the size of the data
|
||||
uint32_t dataSz = bytesPerPixel * width * height;
|
||||
|
||||
if (0 >= bytesPerPixel) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Write it into the buffer
|
||||
if (!stream->write(&dataSz, 4)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Write the pixel data...
|
||||
const uint8_t* rowPtr = src;
|
||||
if (kN32_SkColorType == ct) {
|
||||
for (int j = 0; j < height; ++j) {
|
||||
const uint32_t* pixelsPtr = reinterpret_cast<const uint32_t*>(rowPtr);
|
||||
for (int i = 0; i < width; ++i) {
|
||||
uint32_t pixel = pixelsPtr[i];
|
||||
uint8_t dstPixel[4];
|
||||
dstPixel[0] = pixel >> SK_R32_SHIFT;
|
||||
dstPixel[1] = pixel >> SK_G32_SHIFT;
|
||||
dstPixel[2] = pixel >> SK_B32_SHIFT;
|
||||
dstPixel[3] = pixel >> SK_A32_SHIFT;
|
||||
if (!stream->write(dstPixel, 4)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
rowPtr += rowBytes;
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < height; ++i) {
|
||||
if (!stream->write(rowPtr, bytesPerPixel * width)) {
|
||||
return false;
|
||||
}
|
||||
rowPtr += rowBytes;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SkKTXFile::WriteBitmapToKTX(SkWStream* stream, const SkBitmap& bitmap) {
|
||||
SkAutoLockPixels autoLockPixels(bitmap);
|
||||
SkPixmap pixmap;
|
||||
return bitmap.peekPixels(&pixmap) && SkKTXFile::WritePixmapToKTX(stream, pixmap);
|
||||
}
|
145
third_party/ktx/ktx.h
vendored
145
third_party/ktx/ktx.h
vendored
@ -1,145 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef SkKTXFile_DEFINED
|
||||
#define SkKTXFile_DEFINED
|
||||
|
||||
#include "SkData.h"
|
||||
#include "SkTextureCompressor.h"
|
||||
#include "SkTypes.h"
|
||||
#include "SkTDArray.h"
|
||||
#include "SkString.h"
|
||||
#include "SkRefCnt.h"
|
||||
|
||||
class SkBitmap;
|
||||
class SkPixmap;
|
||||
class SkStreamRewindable;
|
||||
class SkWStream;
|
||||
|
||||
// KTX Image File
|
||||
// ---
|
||||
// KTX is a general texture data storage file format ratified by the Khronos Group. As an
|
||||
// overview, a KTX file contains all of the appropriate values needed to fully specify a
|
||||
// texture in an OpenGL application, including the use of compressed data.
|
||||
//
|
||||
// A full format specification can be found here:
|
||||
// http://www.khronos.org/opengles/sdk/tools/KTX/file_format_spec/
|
||||
|
||||
class SkKTXFile {
|
||||
public:
|
||||
// The ownership of the data remains with the caller. This class is intended
|
||||
// to be used as a logical wrapper around the data in order to properly
|
||||
// access the pixels.
|
||||
SkKTXFile(SkData* data) : fData(data), fSwapBytes(false) {
|
||||
data->ref();
|
||||
fValid = this->readKTXFile(fData->bytes(), fData->size());
|
||||
}
|
||||
|
||||
bool valid() const { return fValid; }
|
||||
|
||||
int width() const { return static_cast<int>(fHeader.fPixelWidth); }
|
||||
int height() const { return static_cast<int>(fHeader.fPixelHeight); }
|
||||
|
||||
const uint8_t *pixelData(int mipmap = 0) const {
|
||||
SkASSERT(!this->valid() || mipmap < fPixelData.count());
|
||||
return this->valid() ? fPixelData[mipmap].data() : NULL;
|
||||
}
|
||||
|
||||
// If the decoded KTX file has the following key, then it will
|
||||
// return the associated value. If not found, the empty string
|
||||
// is returned.
|
||||
SkString getValueForKey(const SkString& key) const;
|
||||
|
||||
int numMipmaps() const { return static_cast<int>(fHeader.fNumberOfMipmapLevels); }
|
||||
|
||||
bool isCompressedFormat(SkTextureCompressor::Format fmt) const;
|
||||
bool isRGBA8() const;
|
||||
bool isRGB8() const;
|
||||
|
||||
static bool is_ktx(const uint8_t data[], size_t size);
|
||||
static bool is_ktx(SkStreamRewindable* stream);
|
||||
|
||||
static bool WriteETC1ToKTX(SkWStream* stream, const uint8_t *etc1Data,
|
||||
uint32_t width, uint32_t height);
|
||||
static bool WritePixmapToKTX(SkWStream* stream, const SkPixmap& pixmap);
|
||||
static bool WriteBitmapToKTX(SkWStream* stream, const SkBitmap& bitmap);
|
||||
|
||||
private:
|
||||
|
||||
// The blob holding the file data.
|
||||
sk_sp<SkData> fData;
|
||||
|
||||
// This header captures all of the data that describes the format
|
||||
// of the image data in a KTX file.
|
||||
struct Header {
|
||||
uint32_t fGLType;
|
||||
uint32_t fGLTypeSize;
|
||||
uint32_t fGLFormat;
|
||||
uint32_t fGLInternalFormat;
|
||||
uint32_t fGLBaseInternalFormat;
|
||||
uint32_t fPixelWidth;
|
||||
uint32_t fPixelHeight;
|
||||
uint32_t fPixelDepth;
|
||||
uint32_t fNumberOfArrayElements;
|
||||
uint32_t fNumberOfFaces;
|
||||
uint32_t fNumberOfMipmapLevels;
|
||||
uint32_t fBytesOfKeyValueData;
|
||||
|
||||
Header() { memset(this, 0, sizeof(*this)); }
|
||||
} fHeader;
|
||||
|
||||
// A Key Value pair stored in the KTX file. There may be
|
||||
// arbitrarily many of these.
|
||||
class KeyValue {
|
||||
public:
|
||||
KeyValue(size_t size) : fDataSz(size) { }
|
||||
bool readKeyAndValue(const uint8_t *data);
|
||||
size_t size() const { return fDataSz; }
|
||||
const SkString& key() const { return fKey; }
|
||||
const SkString& value() const { return fValue; }
|
||||
bool writeKeyAndValueForKTX(SkWStream* strm);
|
||||
private:
|
||||
const size_t fDataSz;
|
||||
SkString fKey;
|
||||
SkString fValue;
|
||||
};
|
||||
|
||||
static KeyValue CreateKeyValue(const char *key, const char *value);
|
||||
|
||||
// The pixel data for a single mipmap level in an image. Based on how
|
||||
// the rest of the data is stored, this may be compressed, a cubemap, etc.
|
||||
// The header will describe the format of this data.
|
||||
class PixelData {
|
||||
public:
|
||||
PixelData(const uint8_t *ptr, size_t sz) : fDataSz(sz), fDataPtr(ptr) { }
|
||||
const uint8_t *data() const { return fDataPtr; }
|
||||
size_t dataSize() const { return fDataSz; }
|
||||
private:
|
||||
const size_t fDataSz;
|
||||
const uint8_t *fDataPtr;
|
||||
};
|
||||
|
||||
// This function is only called once from the constructor. It loads the data
|
||||
// and populates the appropriate fields of this class
|
||||
// (fKeyValuePairs, fPixelData, fSwapBytes)
|
||||
bool readKTXFile(const uint8_t *data, size_t dataLen);
|
||||
|
||||
SkTArray<KeyValue> fKeyValuePairs;
|
||||
SkTDArray<PixelData> fPixelData;
|
||||
bool fValid;
|
||||
|
||||
// If the endianness of the platform is different than the file,
|
||||
// then we need to do proper byte swapping.
|
||||
bool fSwapBytes;
|
||||
|
||||
// Read an integer from a buffer, advance the buffer, and swap
|
||||
// bytes if fSwapBytes is set
|
||||
uint32_t readInt(const uint8_t** buf, size_t* bytesLeft) const;
|
||||
};
|
||||
|
||||
#endif // SkKTXFile_DEFINED
|
@ -72,8 +72,8 @@ bool CollectImages(SkCommandLineFlags::StringArray images, SkTArray<SkString>* o
|
||||
SkASSERT(output);
|
||||
|
||||
static const char* const exts[] = {
|
||||
"bmp", "gif", "jpg", "jpeg", "png", "webp", "ktx", "astc", "wbmp", "ico",
|
||||
"BMP", "GIF", "JPG", "JPEG", "PNG", "WEBP", "KTX", "ASTC", "WBMP", "ICO",
|
||||
"bmp", "gif", "jpg", "jpeg", "png", "webp", "astc", "wbmp", "ico",
|
||||
"BMP", "GIF", "JPG", "JPEG", "PNG", "WEBP", "ASTC", "WBMP", "ICO",
|
||||
#ifdef SK_CODEC_DECODES_RAW
|
||||
"arw", "cr2", "dng", "nef", "nrw", "orf", "raf", "rw2", "pef", "srw",
|
||||
"ARW", "CR2", "DNG", "NEF", "NRW", "ORF", "RAF", "RW2", "PEF", "SRW",
|
||||
|
Loading…
Reference in New Issue
Block a user