Refactor KTX defines and validation

This commit is contained in:
Brad Davis 2017-05-15 10:23:08 -07:00
parent 077e56a96f
commit 191b633081
8 changed files with 570 additions and 444 deletions

View file

@ -510,29 +510,29 @@ TexturePointer Texture::unserialize(const std::string& ktxfile, const ktx::KTXDe
bool Texture::evalKTXFormat(const Element& mipFormat, const Element& texelFormat, ktx::Header& header) {
if (texelFormat == Format::COLOR_RGBA_32 && mipFormat == Format::COLOR_BGRA_32) {
header.setUncompressed(ktx::GLType::UNSIGNED_BYTE, 1, ktx::GLFormat::BGRA, ktx::GLInternalFormat_Uncompressed::RGBA8, ktx::GLBaseInternalFormat::RGBA);
header.setUncompressed(ktx::GLType::UNSIGNED_BYTE, 1, ktx::GLFormat::BGRA, ktx::GLInternalFormat::RGBA8, ktx::GLBaseInternalFormat::RGBA);
} else if (texelFormat == Format::COLOR_RGBA_32 && mipFormat == Format::COLOR_RGBA_32) {
header.setUncompressed(ktx::GLType::UNSIGNED_BYTE, 1, ktx::GLFormat::RGBA, ktx::GLInternalFormat_Uncompressed::RGBA8, ktx::GLBaseInternalFormat::RGBA);
header.setUncompressed(ktx::GLType::UNSIGNED_BYTE, 1, ktx::GLFormat::RGBA, ktx::GLInternalFormat::RGBA8, ktx::GLBaseInternalFormat::RGBA);
} else if (texelFormat == Format::COLOR_SRGBA_32 && mipFormat == Format::COLOR_SBGRA_32) {
header.setUncompressed(ktx::GLType::UNSIGNED_BYTE, 1, ktx::GLFormat::BGRA, ktx::GLInternalFormat_Uncompressed::SRGB8_ALPHA8, ktx::GLBaseInternalFormat::RGBA);
header.setUncompressed(ktx::GLType::UNSIGNED_BYTE, 1, ktx::GLFormat::BGRA, ktx::GLInternalFormat::SRGB8_ALPHA8, ktx::GLBaseInternalFormat::RGBA);
} else if (texelFormat == Format::COLOR_SRGBA_32 && mipFormat == Format::COLOR_SRGBA_32) {
header.setUncompressed(ktx::GLType::UNSIGNED_BYTE, 1, ktx::GLFormat::RGBA, ktx::GLInternalFormat_Uncompressed::SRGB8_ALPHA8, ktx::GLBaseInternalFormat::RGBA);
header.setUncompressed(ktx::GLType::UNSIGNED_BYTE, 1, ktx::GLFormat::RGBA, ktx::GLInternalFormat::SRGB8_ALPHA8, ktx::GLBaseInternalFormat::RGBA);
} else if (texelFormat == Format::COLOR_R_8 && mipFormat == Format::COLOR_R_8) {
header.setUncompressed(ktx::GLType::UNSIGNED_BYTE, 1, ktx::GLFormat::RED, ktx::GLInternalFormat_Uncompressed::R8, ktx::GLBaseInternalFormat::RED);
header.setUncompressed(ktx::GLType::UNSIGNED_BYTE, 1, ktx::GLFormat::RED, ktx::GLInternalFormat::R8, ktx::GLBaseInternalFormat::RED);
} else if (texelFormat == Format::VEC2NU8_XY && mipFormat == Format::VEC2NU8_XY) {
header.setUncompressed(ktx::GLType::UNSIGNED_BYTE, 1, ktx::GLFormat::RG, ktx::GLInternalFormat_Uncompressed::RG8, ktx::GLBaseInternalFormat::RG);
header.setUncompressed(ktx::GLType::UNSIGNED_BYTE, 1, ktx::GLFormat::RG, ktx::GLInternalFormat::RG8, ktx::GLBaseInternalFormat::RG);
} else if (texelFormat == Format::COLOR_COMPRESSED_SRGB && mipFormat == Format::COLOR_COMPRESSED_SRGB) {
header.setCompressed(ktx::GLInternalFormat_Compressed::COMPRESSED_SRGB_S3TC_DXT1_EXT, ktx::GLBaseInternalFormat::RGB);
header.setCompressed(ktx::GLInternalFormat::COMPRESSED_SRGB_S3TC_DXT1_EXT, ktx::GLBaseInternalFormat::RGB);
} else if (texelFormat == Format::COLOR_COMPRESSED_SRGBA_MASK && mipFormat == Format::COLOR_COMPRESSED_SRGBA_MASK) {
header.setCompressed(ktx::GLInternalFormat_Compressed::COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT, ktx::GLBaseInternalFormat::RGBA);
header.setCompressed(ktx::GLInternalFormat::COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT, ktx::GLBaseInternalFormat::RGBA);
} else if (texelFormat == Format::COLOR_COMPRESSED_SRGBA && mipFormat == Format::COLOR_COMPRESSED_SRGBA) {
header.setCompressed(ktx::GLInternalFormat_Compressed::COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, ktx::GLBaseInternalFormat::RGBA);
header.setCompressed(ktx::GLInternalFormat::COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, ktx::GLBaseInternalFormat::RGBA);
} else if (texelFormat == Format::COLOR_COMPRESSED_RED && mipFormat == Format::COLOR_COMPRESSED_RED) {
header.setCompressed(ktx::GLInternalFormat_Compressed::COMPRESSED_RED_RGTC1, ktx::GLBaseInternalFormat::RED);
header.setCompressed(ktx::GLInternalFormat::COMPRESSED_RED_RGTC1, ktx::GLBaseInternalFormat::RED);
} else if (texelFormat == Format::COLOR_COMPRESSED_XY && mipFormat == Format::COLOR_COMPRESSED_XY) {
header.setCompressed(ktx::GLInternalFormat_Compressed::COMPRESSED_RG_RGTC2, ktx::GLBaseInternalFormat::RG);
header.setCompressed(ktx::GLInternalFormat::COMPRESSED_RG_RGTC2, ktx::GLBaseInternalFormat::RG);
} else if (texelFormat == Format::COLOR_COMPRESSED_SRGBA_HIGH && mipFormat == Format::COLOR_COMPRESSED_SRGBA_HIGH) {
header.setCompressed(ktx::GLInternalFormat_Compressed::COMPRESSED_SRGB_ALPHA_BPTC_UNORM, ktx::GLBaseInternalFormat::RGBA);
header.setCompressed(ktx::GLInternalFormat::COMPRESSED_SRGB_ALPHA_BPTC_UNORM, ktx::GLBaseInternalFormat::RGBA);
} else {
return false;
}
@ -542,20 +542,20 @@ bool Texture::evalKTXFormat(const Element& mipFormat, const Element& texelFormat
bool Texture::evalTextureFormat(const ktx::Header& header, Element& mipFormat, Element& texelFormat) {
if (header.getGLFormat() == ktx::GLFormat::BGRA && header.getGLType() == ktx::GLType::UNSIGNED_BYTE && header.getTypeSize() == 1) {
if (header.getGLInternaFormat_Uncompressed() == ktx::GLInternalFormat_Uncompressed::RGBA8) {
if (header.getGLInternaFormat() == ktx::GLInternalFormat::RGBA8) {
mipFormat = Format::COLOR_BGRA_32;
texelFormat = Format::COLOR_RGBA_32;
} else if (header.getGLInternaFormat_Uncompressed() == ktx::GLInternalFormat_Uncompressed::SRGB8_ALPHA8) {
} else if (header.getGLInternaFormat() == ktx::GLInternalFormat::SRGB8_ALPHA8) {
mipFormat = Format::COLOR_SBGRA_32;
texelFormat = Format::COLOR_SRGBA_32;
} else {
return false;
}
} else if (header.getGLFormat() == ktx::GLFormat::RGBA && header.getGLType() == ktx::GLType::UNSIGNED_BYTE && header.getTypeSize() == 1) {
if (header.getGLInternaFormat_Uncompressed() == ktx::GLInternalFormat_Uncompressed::RGBA8) {
if (header.getGLInternaFormat() == ktx::GLInternalFormat::RGBA8) {
mipFormat = Format::COLOR_RGBA_32;
texelFormat = Format::COLOR_RGBA_32;
} else if (header.getGLInternaFormat_Uncompressed() == ktx::GLInternalFormat_Uncompressed::SRGB8_ALPHA8) {
} else if (header.getGLInternaFormat() == ktx::GLInternalFormat::SRGB8_ALPHA8) {
mipFormat = Format::COLOR_SRGBA_32;
texelFormat = Format::COLOR_SRGBA_32;
} else {
@ -563,35 +563,35 @@ bool Texture::evalTextureFormat(const ktx::Header& header, Element& mipFormat, E
}
} else if (header.getGLFormat() == ktx::GLFormat::RED && header.getGLType() == ktx::GLType::UNSIGNED_BYTE && header.getTypeSize() == 1) {
mipFormat = Format::COLOR_R_8;
if (header.getGLInternaFormat_Uncompressed() == ktx::GLInternalFormat_Uncompressed::R8) {
if (header.getGLInternaFormat() == ktx::GLInternalFormat::R8) {
texelFormat = Format::COLOR_R_8;
} else {
return false;
}
} else if (header.getGLFormat() == ktx::GLFormat::RG && header.getGLType() == ktx::GLType::UNSIGNED_BYTE && header.getTypeSize() == 1) {
mipFormat = Format::VEC2NU8_XY;
if (header.getGLInternaFormat_Uncompressed() == ktx::GLInternalFormat_Uncompressed::RG8) {
if (header.getGLInternaFormat() == ktx::GLInternalFormat::RG8) {
texelFormat = Format::VEC2NU8_XY;
} else {
return false;
}
} else if (header.getGLFormat() == ktx::GLFormat::COMPRESSED_FORMAT && header.getGLType() == ktx::GLType::COMPRESSED_TYPE) {
if (header.getGLInternaFormat_Compressed() == ktx::GLInternalFormat_Compressed::COMPRESSED_SRGB_S3TC_DXT1_EXT) {
} else if (header.isCompressed()) {
if (header.getGLInternaFormat() == ktx::GLInternalFormat::COMPRESSED_SRGB_S3TC_DXT1_EXT) {
mipFormat = Format::COLOR_COMPRESSED_SRGB;
texelFormat = Format::COLOR_COMPRESSED_SRGB;
} else if (header.getGLInternaFormat_Compressed() == ktx::GLInternalFormat_Compressed::COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT) {
} else if (header.getGLInternaFormat() == ktx::GLInternalFormat::COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT) {
mipFormat = Format::COLOR_COMPRESSED_SRGBA_MASK;
texelFormat = Format::COLOR_COMPRESSED_SRGBA_MASK;
} else if (header.getGLInternaFormat_Compressed() == ktx::GLInternalFormat_Compressed::COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT) {
} else if (header.getGLInternaFormat() == ktx::GLInternalFormat::COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT) {
mipFormat = Format::COLOR_COMPRESSED_SRGBA;
texelFormat = Format::COLOR_COMPRESSED_SRGBA;
} else if (header.getGLInternaFormat_Compressed() == ktx::GLInternalFormat_Compressed::COMPRESSED_RED_RGTC1) {
} else if (header.getGLInternaFormat() == ktx::GLInternalFormat::COMPRESSED_RED_RGTC1) {
mipFormat = Format::COLOR_COMPRESSED_RED;
texelFormat = Format::COLOR_COMPRESSED_RED;
} else if (header.getGLInternaFormat_Compressed() == ktx::GLInternalFormat_Compressed::COMPRESSED_RG_RGTC2) {
} else if (header.getGLInternaFormat() == ktx::GLInternalFormat::COMPRESSED_RG_RGTC2) {
mipFormat = Format::COLOR_COMPRESSED_XY;
texelFormat = Format::COLOR_COMPRESSED_XY;
} else if (header.getGLInternaFormat_Compressed() == ktx::GLInternalFormat_Compressed::COMPRESSED_SRGB_ALPHA_BPTC_UNORM) {
} else if (header.getGLInternaFormat() == ktx::GLInternalFormat::COMPRESSED_SRGB_ALPHA_BPTC_UNORM) {
mipFormat = Format::COLOR_COMPRESSED_SRGBA_HIGH;
texelFormat = Format::COLOR_COMPRESSED_SRGBA_HIGH;
} else {

View file

@ -0,0 +1,238 @@
//
// Created by Bradley Austin Davis on 2017/05/13
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#pragma once
#ifndef khronos_khr_hpp
#define khronos_khr_hpp
namespace khronos {
namespace gl {
enum class Type : uint32_t {
// GL 4.4 Table 8.2
UNSIGNED_BYTE = 0x1401,
BYTE = 0x1400,
UNSIGNED_SHORT = 0x1403,
SHORT = 0x1402,
UNSIGNED_INT = 0x1405,
INT = 0x1404,
HALF_FLOAT = 0x140B,
FLOAT = 0x1406,
UNSIGNED_BYTE_3_3_2 = 0x8032,
UNSIGNED_BYTE_2_3_3_REV = 0x8362,
UNSIGNED_SHORT_5_6_5 = 0x8363,
UNSIGNED_SHORT_5_6_5_REV = 0x8364,
UNSIGNED_SHORT_4_4_4_4 = 0x8033,
UNSIGNED_SHORT_4_4_4_4_REV = 0x8365,
UNSIGNED_SHORT_5_5_5_1 = 0x8034,
UNSIGNED_SHORT_1_5_5_5_REV = 0x8366,
UNSIGNED_INT_8_8_8_8 = 0x8035,
UNSIGNED_INT_8_8_8_8_REV = 0x8367,
UNSIGNED_INT_10_10_10_2 = 0x8036,
UNSIGNED_INT_2_10_10_10_REV = 0x8368,
UNSIGNED_INT_24_8 = 0x84FA,
UNSIGNED_INT_10F_11F_11F_REV = 0x8C3B,
UNSIGNED_INT_5_9_9_9_REV = 0x8C3E,
FLOAT_32_UNSIGNED_INT_24_8_REV = 0x8DAD,
};
namespace texture {
enum class Format : uint32_t {
COMPRESSED_FORMAT = 0,
// GL 4.4 Table 8.3
STENCIL_INDEX = 0x1901,
DEPTH_COMPONENT = 0x1902,
DEPTH_STENCIL = 0x84F9,
RED = 0x1903,
GREEN = 0x1904,
BLUE = 0x1905,
RG = 0x8227,
RGB = 0x1907,
RGBA = 0x1908,
BGR = 0x80E0,
BGRA = 0x80E1,
RG_INTEGER = 0x8228,
RED_INTEGER = 0x8D94,
GREEN_INTEGER = 0x8D95,
BLUE_INTEGER = 0x8D96,
RGB_INTEGER = 0x8D98,
RGBA_INTEGER = 0x8D99,
BGR_INTEGER = 0x8D9A,
BGRA_INTEGER = 0x8D9B,
};
enum class InternalFormat : uint32_t {
// GL 4.4 Table 8.12
R8 = 0x8229,
R8_SNORM = 0x8F94,
R16 = 0x822A,
R16_SNORM = 0x8F98,
RG8 = 0x822B,
RG8_SNORM = 0x8F95,
RG16 = 0x822C,
RG16_SNORM = 0x8F99,
R3_G3_B2 = 0x2A10,
RGB4 = 0x804F,
RGB5 = 0x8050,
RGB565 = 0x8D62,
RGB8 = 0x8051,
RGB8_SNORM = 0x8F96,
RGB10 = 0x8052,
RGB12 = 0x8053,
RGB16 = 0x8054,
RGB16_SNORM = 0x8F9A,
RGBA2 = 0x8055,
RGBA4 = 0x8056,
RGB5_A1 = 0x8057,
RGBA8 = 0x8058,
RGBA8_SNORM = 0x8F97,
RGB10_A2 = 0x8059,
RGB10_A2UI = 0x906F,
RGBA12 = 0x805A,
RGBA16 = 0x805B,
RGBA16_SNORM = 0x8F9B,
SRGB8 = 0x8C41,
SRGB8_ALPHA8 = 0x8C43,
R16F = 0x822D,
RG16F = 0x822F,
RGB16F = 0x881B,
RGBA16F = 0x881A,
R32F = 0x822E,
RG32F = 0x8230,
RGB32F = 0x8815,
RGBA32F = 0x8814,
R11F_G11F_B10F = 0x8C3A,
RGB9_E5 = 0x8C3D,
R8I = 0x8231,
R8UI = 0x8232,
R16I = 0x8233,
R16UI = 0x8234,
R32I = 0x8235,
R32UI = 0x8236,
RG8I = 0x8237,
RG8UI = 0x8238,
RG16I = 0x8239,
RG16UI = 0x823A,
RG32I = 0x823B,
RG32UI = 0x823C,
RGB8I = 0x8D8F,
RGB8UI = 0x8D7D,
RGB16I = 0x8D89,
RGB16UI = 0x8D77,
RGB32I = 0x8D83,
RGB32UI = 0x8D71,
RGBA8I = 0x8D8E,
RGBA8UI = 0x8D7C,
RGBA16I = 0x8D88,
RGBA16UI = 0x8D76,
RGBA32I = 0x8D82,
RGBA32UI = 0x8D70,
// GL 4.4 Table 8.13
DEPTH_COMPONENT16 = 0x81A5,
DEPTH_COMPONENT24 = 0x81A6,
DEPTH_COMPONENT32 = 0x81A7,
DEPTH_COMPONENT32F = 0x8CAC,
DEPTH24_STENCIL8 = 0x88F0,
DEPTH32F_STENCIL8 = 0x8CAD,
STENCIL_INDEX1 = 0x8D46,
STENCIL_INDEX4 = 0x8D47,
STENCIL_INDEX8 = 0x8D48,
STENCIL_INDEX16 = 0x8D49,
// GL 4.4 Table 8.14
COMPRESSED_RED = 0x8225,
COMPRESSED_RG = 0x8226,
COMPRESSED_RGB = 0x84ED,
COMPRESSED_RGBA = 0x84EE,
COMPRESSED_SRGB = 0x8C48,
COMPRESSED_SRGB_ALPHA = 0x8C49,
COMPRESSED_ETC1_RGB8_OES = 0x8D64,
COMPRESSED_SRGB_S3TC_DXT1_EXT = 0x8C4C,
COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT = 0x8C4D,
COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT = 0x8C4E,
COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT = 0x8C4F,
COMPRESSED_RED_RGTC1 = 0x8DBB,
COMPRESSED_SIGNED_RED_RGTC1 = 0x8DBC,
COMPRESSED_RG_RGTC2 = 0x8DBD,
COMPRESSED_SIGNED_RG_RGTC2 = 0x8DBE,
COMPRESSED_RGBA_BPTC_UNORM = 0x8E8C,
COMPRESSED_SRGB_ALPHA_BPTC_UNORM = 0x8E8D,
COMPRESSED_RGB_BPTC_SIGNED_FLOAT = 0x8E8E,
COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT = 0x8E8F,
COMPRESSED_RGB8_ETC2 = 0x9274,
COMPRESSED_SRGB8_ETC2 = 0x9275,
COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 = 0x9276,
COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 = 0x9277,
COMPRESSED_RGBA8_ETC2_EAC = 0x9278,
COMPRESSED_SRGB8_ALPHA8_ETC2_EAC = 0x9279,
COMPRESSED_R11_EAC = 0x9270,
COMPRESSED_SIGNED_R11_EAC = 0x9271,
COMPRESSED_RG11_EAC = 0x9272,
COMPRESSED_SIGNED_RG11_EAC = 0x9273,
};
enum class BaseInternalFormat : uint32_t {
// GL 4.4 Table 8.11
DEPTH_COMPONENT = 0x1902,
DEPTH_STENCIL = 0x84F9,
RED = 0x1903,
RG = 0x8227,
RGB = 0x1907,
RGBA = 0x1908,
STENCIL_INDEX = 0x1901,
};
enum CubeMapFace {
POS_X = 0,
NEG_X = 1,
POS_Y = 2,
NEG_Y = 3,
POS_Z = 4,
NEG_Z = 5,
NUM_CUBEMAPFACES = 6,
};
}
}
}
#endif // khronos_khr_hpp

View file

@ -16,16 +16,6 @@
using namespace ktx;
uint32_t Header::evalPadding(size_t byteSize) {
//auto padding = byteSize % PACKING_SIZE;
// return (uint32_t) (padding ? PACKING_SIZE - padding : 0);
return (uint32_t) (3 - (byteSize + 3) % PACKING_SIZE);// padding ? PACKING_SIZE - padding : 0);
}
bool Header::checkAlignment(size_t byteSize) {
return ((byteSize & 0x3) == 0);
}
const Header::Identifier ktx::Header::IDENTIFIER {{
0xAB, 0x4B, 0x54, 0x58, 0x20, 0x31, 0x31, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A
}};
@ -40,24 +30,24 @@ uint32_t Header::evalMaxDimension() const {
uint32_t Header::evalPixelOrBlockWidth(uint32_t level) const {
auto pixelWidth = std::max(getPixelWidth() >> level, 1U);
if (getGLType() == GLType::COMPRESSED_TYPE) {
return (pixelWidth + 3) / 4;
if (isCompressed()) {
return evalAlignedCount(pixelWidth);
} else {
return pixelWidth;
}
}
uint32_t Header::evalPixelOrBlockHeight(uint32_t level) const {
auto pixelWidth = std::max(getPixelHeight() >> level, 1U);
if (getGLType() == GLType::COMPRESSED_TYPE) {
auto format = getGLInternaFormat_Compressed();
if (glType == COMPRESSED_TYPE) {
auto format = getGLInternaFormat();
switch (format) {
case GLInternalFormat_Compressed::COMPRESSED_SRGB_S3TC_DXT1_EXT: // BC1
case GLInternalFormat_Compressed::COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT: // BC1A
case GLInternalFormat_Compressed::COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: // BC3
case GLInternalFormat_Compressed::COMPRESSED_RED_RGTC1: // BC4
case GLInternalFormat_Compressed::COMPRESSED_RG_RGTC2: // BC5
case GLInternalFormat_Compressed::COMPRESSED_SRGB_ALPHA_BPTC_UNORM: // BC7
return (pixelWidth + 3) / 4;
case GLInternalFormat::COMPRESSED_SRGB_S3TC_DXT1_EXT: // BC1
case GLInternalFormat::COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT: // BC1A
case GLInternalFormat::COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: // BC3
case GLInternalFormat::COMPRESSED_RED_RGTC1: // BC4
case GLInternalFormat::COMPRESSED_RG_RGTC2: // BC5
case GLInternalFormat::COMPRESSED_SRGB_ALPHA_BPTC_UNORM: // BC7
return evalAlignedCount(pixelWidth);
default:
throw std::runtime_error("Unknown format");
}
@ -70,31 +60,33 @@ uint32_t Header::evalPixelOrBlockDepth(uint32_t level) const {
}
size_t Header::evalPixelOrBlockSize() const {
if (getGLType() == GLType::COMPRESSED_TYPE) {
auto format = getGLInternaFormat_Compressed();
if (format == GLInternalFormat_Compressed::COMPRESSED_SRGB_S3TC_DXT1_EXT) {
return 8;
} else if (format == GLInternalFormat_Compressed::COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT) {
return 8;
} else if (format == GLInternalFormat_Compressed::COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT) {
return 16;
} else if (format == GLInternalFormat_Compressed::COMPRESSED_RED_RGTC1) {
return 8;
} else if (format == GLInternalFormat_Compressed::COMPRESSED_RG_RGTC2) {
return 16;
} else if (format == GLInternalFormat_Compressed::COMPRESSED_SRGB_ALPHA_BPTC_UNORM) {
return 16;
if (isCompressed()) {
auto format = getGLInternaFormat();
switch (format) {
case GLInternalFormat::COMPRESSED_SRGB_S3TC_DXT1_EXT:
case GLInternalFormat::COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT:
case GLInternalFormat::COMPRESSED_RED_RGTC1:
return 8;
case GLInternalFormat::COMPRESSED_SRGB_ALPHA_BPTC_UNORM:
case GLInternalFormat::COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT:
case GLInternalFormat::COMPRESSED_RG_RGTC2:
return 16;
default:
break;
}
} else {
auto baseFormat = getGLBaseInternalFormat();
if (baseFormat == GLBaseInternalFormat::RED) {
return 1;
} else if (baseFormat == GLBaseInternalFormat::RG) {
return 2;
} else if (baseFormat == GLBaseInternalFormat::RGB) {
return 3;
} else if (baseFormat == GLBaseInternalFormat::RGBA) {
return 4;
switch (baseFormat) {
case GLBaseInternalFormat::RED:
return 1;
case GLBaseInternalFormat::RG:
return 2;
case GLBaseInternalFormat::RGB:
return 3;
case GLBaseInternalFormat::RGBA:
return 4;
default:
break;
}
}
@ -108,16 +100,16 @@ size_t Header::evalRowSize(uint32_t level) const {
if (pixSize == 0) {
return 0;
}
auto netSize = pixWidth * pixSize;
auto padding = evalPadding(netSize);
return netSize + padding;
return evalPadded(pixWidth * pixSize);
}
size_t Header::evalFaceSize(uint32_t level) const {
auto pixHeight = evalPixelOrBlockHeight(level);
auto pixDepth = evalPixelOrBlockDepth(level);
auto rowSize = evalRowSize(level);
return pixDepth * pixHeight * rowSize;
}
size_t Header::evalImageSize(uint32_t level) const {
auto faceSize = evalFaceSize(level);
if (!checkAlignment(faceSize)) {
@ -192,7 +184,7 @@ KeyValue::KeyValue(const std::string& key, const std::string& value) :
}
uint32_t KeyValue::serializedByteSize() const {
return (uint32_t) (sizeof(uint32_t) + _byteSize + Header::evalPadding(_byteSize));
return (uint32_t)sizeof(uint32_t) + evalPadded(_byteSize);
}
uint32_t KeyValue::serializedKeyValuesByteSize(const KeyValues& keyValues) {
@ -200,14 +192,8 @@ uint32_t KeyValue::serializedKeyValuesByteSize(const KeyValues& keyValues) {
for (auto& keyval : keyValues) {
keyValuesSize += keyval.serializedByteSize();
}
return (keyValuesSize + Header::evalPadding(keyValuesSize));
}
KTX::KTX() {
}
KTX::~KTX() {
Q_ASSERT(keyValuesSize % 4 == 0);
return keyValuesSize;
}
void KTX::resetStorage(const StoragePointer& storage) {
@ -230,7 +216,7 @@ size_t KTX::getTexelsDataSize() const {
if (!_storage) {
return 0;
}
return (_storage->data() + _storage->size()) - getTexelsData();
return _storage->size() - sizeof(Header) - getKeyValueDataSize();
}
const Byte* KTX::getKeyValueData() const {

View file

@ -22,7 +22,14 @@
#include <shared/Storage.h>
/* KTX Spec:
#include "../khronos/KHR.h"
/*
KTX Specification: https://www.khronos.org/opengles/sdk/tools/KTX/file_format_spec/
**** A KTX header is 64 bytes layed out as follows
Byte[12] identifier
UInt32 endianness
@ -38,6 +45,8 @@ UInt32 numberOfArrayElements
UInt32 numberOfFaces
UInt32 numberOfMipmapLevels
UInt32 bytesOfKeyValueData
**** Each KTX key value pair block is 4 byte aligned
for each keyValuePair that fits in bytesOfKeyValueData
UInt32 keyAndValueByteSize
@ -45,6 +54,8 @@ for each keyValuePair that fits in bytesOfKeyValueData
Byte valuePadding[3 - ((keyAndValueByteSize + 3) % 4)]
end
**** Each mip and cube face is 4 byte aligned
for each mipmap_level in numberOfMipmapLevels*
UInt32 imageSize;
for each array_element in numberOfArrayElements*
@ -67,231 +78,23 @@ end
** Uncompressed texture data matches a GL_UNPACK_ALIGNMENT of 4.
*/
namespace ktx {
const uint32_t PACKING_SIZE { sizeof(uint32_t) };
const std::string HIFI_MIN_POPULATED_MIP_KEY{ "hifi.minMip" };
// Alignment constants
static const uint32_t ALIGNMENT { sizeof(uint32_t) };
static const uint32_t ALIGNMENT_REMAINDER { ALIGNMENT - 1 };
static const uint32_t NUM_CUBEMAPFACES = khronos::gl::texture::CubeMapFace::NUM_CUBEMAPFACES;
// FIXME move out of this header, not specific to ktx
const std::string HIFI_MIN_POPULATED_MIP_KEY { "hifi.minMip" };
using Byte = uint8_t;
enum class GLType : uint32_t {
COMPRESSED_TYPE = 0,
// GL 4.4 Table 8.2
UNSIGNED_BYTE = 0x1401,
BYTE = 0x1400,
UNSIGNED_SHORT = 0x1403,
SHORT = 0x1402,
UNSIGNED_INT = 0x1405,
INT = 0x1404,
HALF_FLOAT = 0x140B,
FLOAT = 0x1406,
UNSIGNED_BYTE_3_3_2 = 0x8032,
UNSIGNED_BYTE_2_3_3_REV = 0x8362,
UNSIGNED_SHORT_5_6_5 = 0x8363,
UNSIGNED_SHORT_5_6_5_REV = 0x8364,
UNSIGNED_SHORT_4_4_4_4 = 0x8033,
UNSIGNED_SHORT_4_4_4_4_REV = 0x8365,
UNSIGNED_SHORT_5_5_5_1 = 0x8034,
UNSIGNED_SHORT_1_5_5_5_REV = 0x8366,
UNSIGNED_INT_8_8_8_8 = 0x8035,
UNSIGNED_INT_8_8_8_8_REV = 0x8367,
UNSIGNED_INT_10_10_10_2 = 0x8036,
UNSIGNED_INT_2_10_10_10_REV = 0x8368,
UNSIGNED_INT_24_8 = 0x84FA,
UNSIGNED_INT_10F_11F_11F_REV = 0x8C3B,
UNSIGNED_INT_5_9_9_9_REV = 0x8C3E,
FLOAT_32_UNSIGNED_INT_24_8_REV = 0x8DAD,
};
enum class GLFormat : uint32_t {
COMPRESSED_FORMAT = 0,
// GL 4.4 Table 8.3
STENCIL_INDEX = 0x1901,
DEPTH_COMPONENT = 0x1902,
DEPTH_STENCIL = 0x84F9,
RED = 0x1903,
GREEN = 0x1904,
BLUE = 0x1905,
RG = 0x8227,
RGB = 0x1907,
RGBA = 0x1908,
BGR = 0x80E0,
BGRA = 0x80E1,
RG_INTEGER = 0x8228,
RED_INTEGER = 0x8D94,
GREEN_INTEGER = 0x8D95,
BLUE_INTEGER = 0x8D96,
RGB_INTEGER = 0x8D98,
RGBA_INTEGER = 0x8D99,
BGR_INTEGER = 0x8D9A,
BGRA_INTEGER = 0x8D9B,
};
enum class GLInternalFormat_Uncompressed : uint32_t {
// GL 4.4 Table 8.12
R8 = 0x8229,
R8_SNORM = 0x8F94,
R16 = 0x822A,
R16_SNORM = 0x8F98,
RG8 = 0x822B,
RG8_SNORM = 0x8F95,
RG16 = 0x822C,
RG16_SNORM = 0x8F99,
R3_G3_B2 = 0x2A10,
RGB4 = 0x804F,
RGB5 = 0x8050,
RGB565 = 0x8D62,
RGB8 = 0x8051,
RGB8_SNORM = 0x8F96,
RGB10 = 0x8052,
RGB12 = 0x8053,
RGB16 = 0x8054,
RGB16_SNORM = 0x8F9A,
RGBA2 = 0x8055,
RGBA4 = 0x8056,
RGB5_A1 = 0x8057,
RGBA8 = 0x8058,
RGBA8_SNORM = 0x8F97,
RGB10_A2 = 0x8059,
RGB10_A2UI = 0x906F,
RGBA12 = 0x805A,
RGBA16 = 0x805B,
RGBA16_SNORM = 0x8F9B,
SRGB8 = 0x8C41,
SRGB8_ALPHA8 = 0x8C43,
R16F = 0x822D,
RG16F = 0x822F,
RGB16F = 0x881B,
RGBA16F = 0x881A,
R32F = 0x822E,
RG32F = 0x8230,
RGB32F = 0x8815,
RGBA32F = 0x8814,
R11F_G11F_B10F = 0x8C3A,
RGB9_E5 = 0x8C3D,
R8I = 0x8231,
R8UI = 0x8232,
R16I = 0x8233,
R16UI = 0x8234,
R32I = 0x8235,
R32UI = 0x8236,
RG8I = 0x8237,
RG8UI = 0x8238,
RG16I = 0x8239,
RG16UI = 0x823A,
RG32I = 0x823B,
RG32UI = 0x823C,
RGB8I = 0x8D8F,
RGB8UI = 0x8D7D,
RGB16I = 0x8D89,
RGB16UI = 0x8D77,
RGB32I = 0x8D83,
RGB32UI = 0x8D71,
RGBA8I = 0x8D8E,
RGBA8UI = 0x8D7C,
RGBA16I = 0x8D88,
RGBA16UI = 0x8D76,
RGBA32I = 0x8D82,
RGBA32UI = 0x8D70,
// GL 4.4 Table 8.13
DEPTH_COMPONENT16 = 0x81A5,
DEPTH_COMPONENT24 = 0x81A6,
DEPTH_COMPONENT32 = 0x81A7,
DEPTH_COMPONENT32F = 0x8CAC,
DEPTH24_STENCIL8 = 0x88F0,
DEPTH32F_STENCIL8 = 0x8CAD,
STENCIL_INDEX1 = 0x8D46,
STENCIL_INDEX4 = 0x8D47,
STENCIL_INDEX8 = 0x8D48,
STENCIL_INDEX16 = 0x8D49,
};
enum class GLInternalFormat_Compressed : uint32_t {
// GL 4.4 Table 8.14
COMPRESSED_RED = 0x8225,
COMPRESSED_RG = 0x8226,
COMPRESSED_RGB = 0x84ED,
COMPRESSED_RGBA = 0x84EE,
COMPRESSED_SRGB = 0x8C48,
COMPRESSED_SRGB_ALPHA = 0x8C49,
COMPRESSED_ETC1_RGB8_OES = 0x8D64,
COMPRESSED_SRGB_S3TC_DXT1_EXT = 0x8C4C,
COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT = 0x8C4D,
COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT = 0x8C4E,
COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT = 0x8C4F,
COMPRESSED_RED_RGTC1 = 0x8DBB,
COMPRESSED_SIGNED_RED_RGTC1 = 0x8DBC,
COMPRESSED_RG_RGTC2 = 0x8DBD,
COMPRESSED_SIGNED_RG_RGTC2 = 0x8DBE,
COMPRESSED_RGBA_BPTC_UNORM = 0x8E8C,
COMPRESSED_SRGB_ALPHA_BPTC_UNORM = 0x8E8D,
COMPRESSED_RGB_BPTC_SIGNED_FLOAT = 0x8E8E,
COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT = 0x8E8F,
COMPRESSED_RGB8_ETC2 = 0x9274,
COMPRESSED_SRGB8_ETC2 = 0x9275,
COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 = 0x9276,
COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 = 0x9277,
COMPRESSED_RGBA8_ETC2_EAC = 0x9278,
COMPRESSED_SRGB8_ALPHA8_ETC2_EAC = 0x9279,
COMPRESSED_R11_EAC = 0x9270,
COMPRESSED_SIGNED_R11_EAC = 0x9271,
COMPRESSED_RG11_EAC = 0x9272,
COMPRESSED_SIGNED_RG11_EAC = 0x9273,
};
enum class GLBaseInternalFormat : uint32_t {
// GL 4.4 Table 8.11
DEPTH_COMPONENT = 0x1902,
DEPTH_STENCIL = 0x84F9,
RED = 0x1903,
RG = 0x8227,
RGB = 0x1907,
RGBA = 0x1908,
STENCIL_INDEX = 0x1901,
};
enum CubeMapFace {
POS_X = 0,
NEG_X = 1,
POS_Y = 2,
NEG_Y = 3,
POS_Z = 4,
NEG_Z = 5,
NUM_CUBEMAPFACES = 6,
};
using GLType = khronos::gl::Type;
using GLFormat = khronos::gl::texture::Format;
using GLInternalFormat = khronos::gl::texture::InternalFormat;
using GLBaseInternalFormat = khronos::gl::texture::BaseInternalFormat;
using CubeMapFace = khronos::gl::texture::CubeMapFace;
using Storage = storage::Storage;
using StoragePointer = std::shared_ptr<Storage>;
@ -301,18 +104,41 @@ namespace ktx {
bool checkIdentifier(const Byte* identifier);
// Returns the number of bytes required be added to the passed value to make it 4 byte aligned
template <typename T>
inline uint8_t evalPadding(T value) {
return ALIGNMENT_REMAINDER - ((value + ALIGNMENT_REMAINDER) % ALIGNMENT);
}
// Returns the passed value rounded up to the next 4 byte aligned value, if it's not already 4 byte aligned
template <typename T>
inline T evalPadded(T value) {
return (value + ALIGNMENT_REMAINDER) & ~(T)ALIGNMENT_REMAINDER;
}
template <typename T>
inline T evalAlignedCount(T value) {
return (value + ALIGNMENT_REMAINDER) / ALIGNMENT;
}
template <typename T>
inline bool checkAlignment(T value) {
return ((value & 0x3) == 0);
}
// Header
struct Header {
static const size_t IDENTIFIER_LENGTH = 12;
static const uint32_t COMPRESSED_FORMAT { 0 };
static const uint32_t COMPRESSED_TYPE { 0 };
static const uint32_t COMPRESSED_TYPE_SIZE { 1 };
static const size_t IDENTIFIER_LENGTH { 12 };
using Identifier = std::array<uint8_t, IDENTIFIER_LENGTH>;
static const Identifier IDENTIFIER;
static const uint32_t ENDIAN_TEST = 0x04030201;
static const uint32_t REVERSE_ENDIAN_TEST = 0x01020304;
static uint32_t evalPadding(size_t byteSize);
static bool checkAlignment(size_t byteSize);
Header();
Byte identifier[IDENTIFIER_LENGTH];
@ -321,7 +147,7 @@ namespace ktx {
uint32_t glType { static_cast<uint32_t>(GLType::UNSIGNED_BYTE) };
uint32_t glTypeSize { 0 };
uint32_t glFormat { static_cast<uint32_t>(GLFormat::RGBA) };
uint32_t glInternalFormat { static_cast<uint32_t>(GLInternalFormat_Uncompressed::RGBA8) };
uint32_t glInternalFormat { static_cast<uint32_t>(GLInternalFormat::RGBA8) };
uint32_t glBaseInternalFormat { static_cast<uint32_t>(GLBaseInternalFormat::RGBA) };
uint32_t pixelWidth { 1 };
@ -338,6 +164,7 @@ namespace ktx {
uint32_t getPixelDepth() const { return (pixelDepth ? pixelDepth : 1); }
uint32_t getNumberOfSlices() const { return (numberOfArrayElements ? numberOfArrayElements : 1); }
uint32_t getNumberOfLevels() const { return (numberOfMipmapLevels ? numberOfMipmapLevels : 1); }
bool isCompressed() const { return glFormat == COMPRESSED_FORMAT; }
uint32_t evalMaxDimension() const;
uint32_t evalPixelOrBlockWidth(uint32_t level) const;
@ -349,17 +176,21 @@ namespace ktx {
size_t evalFaceSize(uint32_t level) const;
size_t evalImageSize(uint32_t level) const;
void setUncompressed(GLType type, uint32_t typeSize, GLFormat format, GLInternalFormat_Uncompressed internalFormat, GLBaseInternalFormat baseInternalFormat) {
// FIXME base internal format should automatically be determined by internal format
// FIXME type size should automatically be determined by type
void setUncompressed(GLType type, uint32_t typeSize, GLFormat format, GLInternalFormat internalFormat, GLBaseInternalFormat baseInternalFormat) {
glType = (uint32_t) type;
glTypeSize = typeSize;
glFormat = (uint32_t) format;
glInternalFormat = (uint32_t) internalFormat;
glBaseInternalFormat = (uint32_t) baseInternalFormat;
}
void setCompressed(GLInternalFormat_Compressed internalFormat, GLBaseInternalFormat baseInternalFormat) {
glType = (uint32_t) GLType::COMPRESSED_TYPE;
glTypeSize = 1;
glFormat = (uint32_t) GLFormat::COMPRESSED_FORMAT;
// FIXME base internal format should automatically be determined by internal format
void setCompressed(GLInternalFormat internalFormat, GLBaseInternalFormat baseInternalFormat) {
glType = COMPRESSED_TYPE;
glFormat = COMPRESSED_FORMAT;
glTypeSize = COMPRESSED_TYPE_SIZE;
glInternalFormat = (uint32_t) internalFormat;
glBaseInternalFormat = (uint32_t) baseInternalFormat;
}
@ -367,18 +198,9 @@ namespace ktx {
GLType getGLType() const { return (GLType)glType; }
uint32_t getTypeSize() const { return glTypeSize; }
GLFormat getGLFormat() const { return (GLFormat)glFormat; }
GLInternalFormat_Uncompressed getGLInternaFormat_Uncompressed() const { return (GLInternalFormat_Uncompressed)glInternalFormat; }
GLInternalFormat_Compressed getGLInternaFormat_Compressed() const { return (GLInternalFormat_Compressed)glInternalFormat; }
GLInternalFormat getGLInternaFormat() const { return (GLInternalFormat)glInternalFormat; }
GLBaseInternalFormat getGLBaseInternalFormat() const { return (GLBaseInternalFormat)glBaseInternalFormat; }
void setDimensions(uint32_t width, uint32_t height = 0, uint32_t depth = 0, uint32_t numSlices = 0, uint32_t numFaces = 1) {
pixelWidth = (width > 0 ? width : 1);
pixelHeight = height;
pixelDepth = depth;
numberOfArrayElements = numSlices;
numberOfFaces = ((numFaces == 1) || (numFaces == NUM_CUBEMAPFACES) ? numFaces : 1);
}
void set1D(uint32_t width) { setDimensions(width); }
void set1DArray(uint32_t width, uint32_t numSlices) { setDimensions(width, 0, 0, (numSlices > 0 ? numSlices : 1)); }
void set2D(uint32_t width, uint32_t height) { setDimensions(width, height); }
@ -392,12 +214,22 @@ namespace ktx {
// Generate a set of image descriptors based on the assumption that the full mip pyramid is populated
ImageDescriptors generateImageDescriptors() const;
private:
void setDimensions(uint32_t width, uint32_t height = 0, uint32_t depth = 0, uint32_t numSlices = 0, uint32_t numFaces = 1) {
pixelWidth = (width > 0 ? width : 1);
pixelHeight = height;
pixelDepth = depth;
numberOfArrayElements = numSlices;
numberOfFaces = numFaces;
}
};
static const size_t KTX_HEADER_SIZE = 64;
// Size as specified by the KTX specification
static const size_t KTX_HEADER_SIZE { 64 };
static_assert(sizeof(Header) == KTX_HEADER_SIZE, "KTX Header size is static and should not change from the spec");
static const size_t KV_SIZE_WIDTH = 4; // Number of bytes for keyAndValueByteSize
static const size_t IMAGE_SIZE_WIDTH = 4; // Number of bytes for imageSize
static const size_t KV_SIZE_WIDTH { ALIGNMENT }; // Number of bytes for keyAndValueByteSize
static const size_t IMAGE_SIZE_WIDTH { ALIGNMENT }; // Number of bytes for imageSize
// Key Values
struct KeyValue {
@ -488,11 +320,9 @@ namespace ktx {
class KTX {
void resetStorage(const StoragePointer& src);
KTX();
KTX() {}
KTX(const StoragePointer& storage, const Header& header, const KeyValues& keyValues, const Images& images);
public:
~KTX();
static bool validate(const StoragePointer& src);
// Define a KTX object manually to write it somewhere (in a file on disk?)
@ -539,6 +369,7 @@ namespace ktx {
KTXDescriptor toDescriptor() const;
size_t getKeyValueDataSize() const;
size_t getTexelsDataSize() const;
bool isValid() const;
Header _header;
StoragePointer _storage;

View file

@ -151,7 +151,7 @@ namespace ktx {
auto expectedImageSize = header.evalImageSize((uint32_t) images.size());
if (imageSize != expectedImageSize) {
break;
} else if (!Header::checkAlignment(imageSize)) {
} else if (!checkAlignment(imageSize)) {
break;
}
@ -163,7 +163,7 @@ namespace ktx {
// If enough data ahead then capture the pointer
if ((currentPtr - srcBytes) + imageSize <= (srcSize)) {
auto padding = Header::evalPadding(imageSize);
auto padding = evalPadding(imageSize);
if (numFaces == NUM_CUBEMAPFACES) {
Image::FaceBytes faces(NUM_CUBEMAPFACES);

View file

@ -63,111 +63,111 @@ static const std::unordered_set<uint32_t> VALID_GL_FORMATS {
};
static const std::unordered_set<uint32_t> VALID_GL_INTERNAL_FORMATS {
(uint32_t)GLInternalFormat_Uncompressed::R8,
(uint32_t)GLInternalFormat_Uncompressed::R8_SNORM,
(uint32_t)GLInternalFormat_Uncompressed::R16,
(uint32_t)GLInternalFormat_Uncompressed::R16_SNORM,
(uint32_t)GLInternalFormat_Uncompressed::RG8,
(uint32_t)GLInternalFormat_Uncompressed::RG8_SNORM,
(uint32_t)GLInternalFormat_Uncompressed::RG16,
(uint32_t)GLInternalFormat_Uncompressed::RG16_SNORM,
(uint32_t)GLInternalFormat_Uncompressed::R3_G3_B2,
(uint32_t)GLInternalFormat_Uncompressed::RGB4,
(uint32_t)GLInternalFormat_Uncompressed::RGB5,
(uint32_t)GLInternalFormat_Uncompressed::RGB565,
(uint32_t)GLInternalFormat_Uncompressed::RGB8,
(uint32_t)GLInternalFormat_Uncompressed::RGB8_SNORM,
(uint32_t)GLInternalFormat_Uncompressed::RGB10,
(uint32_t)GLInternalFormat_Uncompressed::RGB12,
(uint32_t)GLInternalFormat_Uncompressed::RGB16,
(uint32_t)GLInternalFormat_Uncompressed::RGB16_SNORM,
(uint32_t)GLInternalFormat_Uncompressed::RGBA2,
(uint32_t)GLInternalFormat_Uncompressed::RGBA4,
(uint32_t)GLInternalFormat_Uncompressed::RGB5_A1,
(uint32_t)GLInternalFormat_Uncompressed::RGBA8,
(uint32_t)GLInternalFormat_Uncompressed::RGBA8_SNORM,
(uint32_t)GLInternalFormat_Uncompressed::RGB10_A2,
(uint32_t)GLInternalFormat_Uncompressed::RGB10_A2UI,
(uint32_t)GLInternalFormat_Uncompressed::RGBA12,
(uint32_t)GLInternalFormat_Uncompressed::RGBA16,
(uint32_t)GLInternalFormat_Uncompressed::RGBA16_SNORM,
(uint32_t)GLInternalFormat_Uncompressed::SRGB8,
(uint32_t)GLInternalFormat_Uncompressed::SRGB8_ALPHA8,
(uint32_t)GLInternalFormat_Uncompressed::R16F,
(uint32_t)GLInternalFormat_Uncompressed::RG16F,
(uint32_t)GLInternalFormat_Uncompressed::RGB16F,
(uint32_t)GLInternalFormat_Uncompressed::RGBA16F,
(uint32_t)GLInternalFormat_Uncompressed::R32F,
(uint32_t)GLInternalFormat_Uncompressed::RG32F,
(uint32_t)GLInternalFormat_Uncompressed::RGBA32F,
(uint32_t)GLInternalFormat_Uncompressed::R11F_G11F_B10F,
(uint32_t)GLInternalFormat_Uncompressed::RGB9_E5,
(uint32_t)GLInternalFormat_Uncompressed::R8I,
(uint32_t)GLInternalFormat_Uncompressed::R8UI,
(uint32_t)GLInternalFormat_Uncompressed::R16I,
(uint32_t)GLInternalFormat_Uncompressed::R16UI,
(uint32_t)GLInternalFormat_Uncompressed::R32I,
(uint32_t)GLInternalFormat_Uncompressed::R32UI,
(uint32_t)GLInternalFormat_Uncompressed::RG8I,
(uint32_t)GLInternalFormat_Uncompressed::RG8UI,
(uint32_t)GLInternalFormat_Uncompressed::RG16I,
(uint32_t)GLInternalFormat_Uncompressed::RG16UI,
(uint32_t)GLInternalFormat_Uncompressed::RG32I,
(uint32_t)GLInternalFormat_Uncompressed::RG32UI,
(uint32_t)GLInternalFormat_Uncompressed::RGB8I,
(uint32_t)GLInternalFormat_Uncompressed::RGB8UI,
(uint32_t)GLInternalFormat_Uncompressed::RGB16I,
(uint32_t)GLInternalFormat_Uncompressed::RGB16UI,
(uint32_t)GLInternalFormat_Uncompressed::RGB32I,
(uint32_t)GLInternalFormat_Uncompressed::RGB32UI,
(uint32_t)GLInternalFormat_Uncompressed::RGBA8I,
(uint32_t)GLInternalFormat_Uncompressed::RGBA8UI,
(uint32_t)GLInternalFormat_Uncompressed::RGBA16I,
(uint32_t)GLInternalFormat_Uncompressed::RGBA16UI,
(uint32_t)GLInternalFormat_Uncompressed::RGBA32I,
(uint32_t)GLInternalFormat_Uncompressed::RGBA32UI,
(uint32_t)GLInternalFormat_Uncompressed::DEPTH_COMPONENT16,
(uint32_t)GLInternalFormat_Uncompressed::DEPTH_COMPONENT24,
(uint32_t)GLInternalFormat_Uncompressed::DEPTH_COMPONENT32,
(uint32_t)GLInternalFormat_Uncompressed::DEPTH_COMPONENT32F,
(uint32_t)GLInternalFormat_Uncompressed::DEPTH24_STENCIL8,
(uint32_t)GLInternalFormat_Uncompressed::DEPTH32F_STENCIL8,
(uint32_t)GLInternalFormat_Uncompressed::STENCIL_INDEX1,
(uint32_t)GLInternalFormat_Uncompressed::STENCIL_INDEX4,
(uint32_t)GLInternalFormat_Uncompressed::STENCIL_INDEX8,
(uint32_t)GLInternalFormat_Uncompressed::STENCIL_INDEX16,
(uint32_t)GLInternalFormat::R8,
(uint32_t)GLInternalFormat::R8_SNORM,
(uint32_t)GLInternalFormat::R16,
(uint32_t)GLInternalFormat::R16_SNORM,
(uint32_t)GLInternalFormat::RG8,
(uint32_t)GLInternalFormat::RG8_SNORM,
(uint32_t)GLInternalFormat::RG16,
(uint32_t)GLInternalFormat::RG16_SNORM,
(uint32_t)GLInternalFormat::R3_G3_B2,
(uint32_t)GLInternalFormat::RGB4,
(uint32_t)GLInternalFormat::RGB5,
(uint32_t)GLInternalFormat::RGB565,
(uint32_t)GLInternalFormat::RGB8,
(uint32_t)GLInternalFormat::RGB8_SNORM,
(uint32_t)GLInternalFormat::RGB10,
(uint32_t)GLInternalFormat::RGB12,
(uint32_t)GLInternalFormat::RGB16,
(uint32_t)GLInternalFormat::RGB16_SNORM,
(uint32_t)GLInternalFormat::RGBA2,
(uint32_t)GLInternalFormat::RGBA4,
(uint32_t)GLInternalFormat::RGB5_A1,
(uint32_t)GLInternalFormat::RGBA8,
(uint32_t)GLInternalFormat::RGBA8_SNORM,
(uint32_t)GLInternalFormat::RGB10_A2,
(uint32_t)GLInternalFormat::RGB10_A2UI,
(uint32_t)GLInternalFormat::RGBA12,
(uint32_t)GLInternalFormat::RGBA16,
(uint32_t)GLInternalFormat::RGBA16_SNORM,
(uint32_t)GLInternalFormat::SRGB8,
(uint32_t)GLInternalFormat::SRGB8_ALPHA8,
(uint32_t)GLInternalFormat::R16F,
(uint32_t)GLInternalFormat::RG16F,
(uint32_t)GLInternalFormat::RGB16F,
(uint32_t)GLInternalFormat::RGBA16F,
(uint32_t)GLInternalFormat::R32F,
(uint32_t)GLInternalFormat::RG32F,
(uint32_t)GLInternalFormat::RGBA32F,
(uint32_t)GLInternalFormat::R11F_G11F_B10F,
(uint32_t)GLInternalFormat::RGB9_E5,
(uint32_t)GLInternalFormat::R8I,
(uint32_t)GLInternalFormat::R8UI,
(uint32_t)GLInternalFormat::R16I,
(uint32_t)GLInternalFormat::R16UI,
(uint32_t)GLInternalFormat::R32I,
(uint32_t)GLInternalFormat::R32UI,
(uint32_t)GLInternalFormat::RG8I,
(uint32_t)GLInternalFormat::RG8UI,
(uint32_t)GLInternalFormat::RG16I,
(uint32_t)GLInternalFormat::RG16UI,
(uint32_t)GLInternalFormat::RG32I,
(uint32_t)GLInternalFormat::RG32UI,
(uint32_t)GLInternalFormat::RGB8I,
(uint32_t)GLInternalFormat::RGB8UI,
(uint32_t)GLInternalFormat::RGB16I,
(uint32_t)GLInternalFormat::RGB16UI,
(uint32_t)GLInternalFormat::RGB32I,
(uint32_t)GLInternalFormat::RGB32UI,
(uint32_t)GLInternalFormat::RGBA8I,
(uint32_t)GLInternalFormat::RGBA8UI,
(uint32_t)GLInternalFormat::RGBA16I,
(uint32_t)GLInternalFormat::RGBA16UI,
(uint32_t)GLInternalFormat::RGBA32I,
(uint32_t)GLInternalFormat::RGBA32UI,
(uint32_t)GLInternalFormat::DEPTH_COMPONENT16,
(uint32_t)GLInternalFormat::DEPTH_COMPONENT24,
(uint32_t)GLInternalFormat::DEPTH_COMPONENT32,
(uint32_t)GLInternalFormat::DEPTH_COMPONENT32F,
(uint32_t)GLInternalFormat::DEPTH24_STENCIL8,
(uint32_t)GLInternalFormat::DEPTH32F_STENCIL8,
(uint32_t)GLInternalFormat::STENCIL_INDEX1,
(uint32_t)GLInternalFormat::STENCIL_INDEX4,
(uint32_t)GLInternalFormat::STENCIL_INDEX8,
(uint32_t)GLInternalFormat::STENCIL_INDEX16,
};
static const std::unordered_set<uint32_t> VALID_GL_INTERNAL_COMPRESSED_FORMATS {
(uint32_t)GLInternalFormat_Compressed::COMPRESSED_RED,
(uint32_t)GLInternalFormat_Compressed::COMPRESSED_RG,
(uint32_t)GLInternalFormat_Compressed::COMPRESSED_RGB,
(uint32_t)GLInternalFormat_Compressed::COMPRESSED_RGBA,
(uint32_t)GLInternalFormat_Compressed::COMPRESSED_SRGB,
(uint32_t)GLInternalFormat_Compressed::COMPRESSED_SRGB_ALPHA,
(uint32_t)GLInternalFormat_Compressed::COMPRESSED_ETC1_RGB8_OES,
(uint32_t)GLInternalFormat_Compressed::COMPRESSED_SRGB_S3TC_DXT1_EXT,
(uint32_t)GLInternalFormat_Compressed::COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT,
(uint32_t)GLInternalFormat_Compressed::COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT,
(uint32_t)GLInternalFormat_Compressed::COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT,
(uint32_t)GLInternalFormat_Compressed::COMPRESSED_RED_RGTC1,
(uint32_t)GLInternalFormat_Compressed::COMPRESSED_SIGNED_RED_RGTC1,
(uint32_t)GLInternalFormat_Compressed::COMPRESSED_RG_RGTC2,
(uint32_t)GLInternalFormat_Compressed::COMPRESSED_SIGNED_RG_RGTC2,
(uint32_t)GLInternalFormat_Compressed::COMPRESSED_RGBA_BPTC_UNORM,
(uint32_t)GLInternalFormat_Compressed::COMPRESSED_SRGB_ALPHA_BPTC_UNORM,
(uint32_t)GLInternalFormat_Compressed::COMPRESSED_RGB_BPTC_SIGNED_FLOAT,
(uint32_t)GLInternalFormat_Compressed::COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT,
(uint32_t)GLInternalFormat_Compressed::COMPRESSED_RGB8_ETC2,
(uint32_t)GLInternalFormat_Compressed::COMPRESSED_SRGB8_ETC2,
(uint32_t)GLInternalFormat_Compressed::COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2,
(uint32_t)GLInternalFormat_Compressed::COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2,
(uint32_t)GLInternalFormat_Compressed::COMPRESSED_RGBA8_ETC2_EAC,
(uint32_t)GLInternalFormat_Compressed::COMPRESSED_SRGB8_ALPHA8_ETC2_EAC,
(uint32_t)GLInternalFormat_Compressed::COMPRESSED_R11_EAC,
(uint32_t)GLInternalFormat_Compressed::COMPRESSED_SIGNED_R11_EAC,
(uint32_t)GLInternalFormat_Compressed::COMPRESSED_RG11_EAC,
(uint32_t)GLInternalFormat_Compressed::COMPRESSED_SIGNED_RG11_EAC,
(uint32_t)GLInternalFormat::COMPRESSED_RED,
(uint32_t)GLInternalFormat::COMPRESSED_RG,
(uint32_t)GLInternalFormat::COMPRESSED_RGB,
(uint32_t)GLInternalFormat::COMPRESSED_RGBA,
(uint32_t)GLInternalFormat::COMPRESSED_SRGB,
(uint32_t)GLInternalFormat::COMPRESSED_SRGB_ALPHA,
(uint32_t)GLInternalFormat::COMPRESSED_ETC1_RGB8_OES,
(uint32_t)GLInternalFormat::COMPRESSED_SRGB_S3TC_DXT1_EXT,
(uint32_t)GLInternalFormat::COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT,
(uint32_t)GLInternalFormat::COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT,
(uint32_t)GLInternalFormat::COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT,
(uint32_t)GLInternalFormat::COMPRESSED_RED_RGTC1,
(uint32_t)GLInternalFormat::COMPRESSED_SIGNED_RED_RGTC1,
(uint32_t)GLInternalFormat::COMPRESSED_RG_RGTC2,
(uint32_t)GLInternalFormat::COMPRESSED_SIGNED_RG_RGTC2,
(uint32_t)GLInternalFormat::COMPRESSED_RGBA_BPTC_UNORM,
(uint32_t)GLInternalFormat::COMPRESSED_SRGB_ALPHA_BPTC_UNORM,
(uint32_t)GLInternalFormat::COMPRESSED_RGB_BPTC_SIGNED_FLOAT,
(uint32_t)GLInternalFormat::COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT,
(uint32_t)GLInternalFormat::COMPRESSED_RGB8_ETC2,
(uint32_t)GLInternalFormat::COMPRESSED_SRGB8_ETC2,
(uint32_t)GLInternalFormat::COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2,
(uint32_t)GLInternalFormat::COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2,
(uint32_t)GLInternalFormat::COMPRESSED_RGBA8_ETC2_EAC,
(uint32_t)GLInternalFormat::COMPRESSED_SRGB8_ALPHA8_ETC2_EAC,
(uint32_t)GLInternalFormat::COMPRESSED_R11_EAC,
(uint32_t)GLInternalFormat::COMPRESSED_SIGNED_R11_EAC,
(uint32_t)GLInternalFormat::COMPRESSED_RG11_EAC,
(uint32_t)GLInternalFormat::COMPRESSED_SIGNED_RG11_EAC,
};
static const std::unordered_set<uint32_t> VALID_GL_BASE_INTERNAL_FORMATS {
@ -199,7 +199,17 @@ bool Header::isValid() const {
return false;
}
if (glFormat == (uint32_t)GLFormat::COMPRESSED_FORMAT && glType == (uint32_t)GLType::COMPRESSED_TYPE) {
if (isCompressed()) {
if (glType != COMPRESSED_TYPE) {
qDebug("Invalid type for compressed texture 0x%x", glType);
return false;
}
if (glTypeSize != COMPRESSED_TYPE_SIZE) {
qDebug("Invalid type size for compressed texture %d", glTypeSize);
return false;
}
if (VALID_GL_INTERNAL_COMPRESSED_FORMATS.count(glInternalFormat) != 1) {
qDebug("Invalid compressed internal format 0x%x", glInternalFormat);
return false;
@ -241,7 +251,7 @@ bool Header::isValid() const {
// FIXME validate numberOfMipmapLevels based on the dimensions?
if ((bytesOfKeyValueData % 4) != 0) {
qDebug() << "Invalid keyvalue data size " << numberOfFaces;
qDebug() << "Invalid keyvalue data size " << bytesOfKeyValueData;
return false;
}
@ -374,3 +384,50 @@ bool KTX::validate(const StoragePointer& src) {
return true;
}
bool KTX::isValid() const {
if (!_header.isValid()) {
return false;
}
if (_images.size() != _header.numberOfMipmapLevels) {
return false;
}
const auto start = _storage->data();
const auto end = start + _storage->size();
// FIXME, do key value checks?
for (const auto& image : _images) {
if (image._numFaces != _header.numberOfFaces) {
return false;
}
for (const auto& facePointer : image._faceBytes) {
if (facePointer + image._faceSize > end) {
return false;
}
}
}
for (uint8_t mip = 0; mip < _header.numberOfMipmapLevels; ++mip) {
for (uint8_t face = 0; face < _header.numberOfFaces; ++face) {
auto faceStorage = getMipFaceTexelsData(mip, face);
// The face start offset must be 4 byte aligned
if (!checkAlignment(faceStorage->data() - start)) {
return false;
}
// The face size must be 4 byte aligned
if (!checkAlignment(faceStorage->size())) {
return false;
}
}
}
return true;
}

View file

@ -70,8 +70,7 @@ namespace ktx {
for (uint32_t l = 0; l < numMips; l++) {
if (images.size() > l) {
storageSize += sizeof(uint32_t);
storageSize += images[l]._imageSize;
storageSize += Header::evalPadding(images[l]._imageSize);
storageSize += evalPadded(images[l]._imageSize);
}
}
return storageSize;
@ -89,8 +88,7 @@ namespace ktx {
for (uint32_t l = 0; l < numMips; l++) {
if (imageDescriptors.size() > l) {
storageSize += sizeof(uint32_t);
storageSize += imageDescriptors[l]._imageSize;
storageSize += Header::evalPadding(imageDescriptors[l]._imageSize);
storageSize += evalPadded(imageDescriptors[l]._imageSize);
}
}
return storageSize;
@ -221,7 +219,7 @@ namespace ktx {
// If enough data ahead then capture the copy source pointer
if (currentDataSize + imageSize <= (allocatedImagesDataSize)) {
auto padding = Header::evalPadding(imageSize);
auto padding = evalPadding(imageSize);
// Single face vs cubes
if (srcImages[l]._numFaces == 1) {

View file

@ -21,6 +21,7 @@
#include <QtCore/QTimer>
#include <QtCore/QThread>
#include <QtCore/QThreadPool>
#include <QtCore/QSaveFile>
#include <QtGui/QGuiApplication>
#include <QtGui/QResizeEvent>
@ -88,6 +89,20 @@ int main(int argc, char** argv) {
QCoreApplication::setOrganizationDomain("highfidelity.com");
logger.reset(new FileLogger());
Q_ASSERT(ktx::evalPadding(0) == 0);
Q_ASSERT(ktx::evalPadding(1) == 3);
Q_ASSERT(ktx::evalPadding(2) == 2);
Q_ASSERT(ktx::evalPadding(3) == 1);
Q_ASSERT(ktx::evalPadding(4) == 0);
Q_ASSERT(ktx::evalPadding(1024) == 0);
Q_ASSERT(ktx::evalPadding(1025) == 3);
Q_ASSERT(ktx::evalPadded(0) == 0);
Q_ASSERT(ktx::evalPadded(1) == 4);
Q_ASSERT(ktx::evalPadded(2) == 4);
Q_ASSERT(ktx::evalPadded(3) == 4);
Q_ASSERT(ktx::evalPadded(4) == 4);
Q_ASSERT(ktx::evalPadded(1024) == 1024);
Q_ASSERT(ktx::evalPadded(1025) == 1028);
Q_ASSERT(sizeof(ktx::Header) == 12 + (sizeof(uint32_t) * 13));
DependencyManager::set<tracing::Tracer>();
@ -100,8 +115,10 @@ int main(int argc, char** argv) {
auto ktxMemory = gpu::Texture::serialize(*testTexture);
{
const auto& ktxStorage = ktxMemory->getStorage();
QFile outFile(TEST_IMAGE_KTX);
if (!outFile.open(QFile::Truncate | QFile::ReadWrite)) {
Q_ASSERT_X(ktx::KTX::validate(ktxStorage), __FUNCTION__, "KTX storage validation failed");
Q_ASSERT_X(ktxMemory->isValid(), __FUNCTION__, "KTX self-validation failed");
QSaveFile outFile(TEST_IMAGE_KTX);
if (!outFile.open(QFile::WriteOnly)) {
throw std::runtime_error("Unable to open file");
}
auto ktxSize = ktxStorage->size();
@ -109,7 +126,7 @@ int main(int argc, char** argv) {
auto dest = outFile.map(0, ktxSize);
memcpy(dest, ktxStorage->data(), ktxSize);
outFile.unmap(dest);
outFile.close();
outFile.commit();
}
{
@ -169,7 +186,6 @@ int mainTemp(int, char**) {
auto ktxFile = ktx::KTX::create(storage);
ktx::KTXDescriptor ktxDescriptor = ktxFile->toDescriptor();
assert(ktxFile->_keyValues == ktxDescriptor.keyValues);
qDebug() << "Contains " << ktxDescriptor.keyValues.size() << " key value pairs";
for (const auto& kv : ktxDescriptor.keyValues) {