mirror of
https://github.com/overte-org/overte.git
synced 2025-08-08 13:18:38 +02:00
Merge pull request #10458 from jherico/ktx_validation
Add KTX validation routines
This commit is contained in:
commit
5b0d2f32b4
8 changed files with 967 additions and 361 deletions
|
@ -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) {
|
bool Texture::evalKTXFormat(const Element& mipFormat, const Element& texelFormat, ktx::Header& header) {
|
||||||
if (texelFormat == Format::COLOR_RGBA_32 && mipFormat == Format::COLOR_BGRA_32) {
|
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) {
|
} 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) {
|
} 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) {
|
} 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) {
|
} 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) {
|
} 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) {
|
} 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) {
|
} 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) {
|
} 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) {
|
} 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) {
|
} 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) {
|
} 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 {
|
} else {
|
||||||
return false;
|
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) {
|
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.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;
|
mipFormat = Format::COLOR_BGRA_32;
|
||||||
texelFormat = 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_SBGRA_32;
|
mipFormat = Format::COLOR_SBGRA_32;
|
||||||
texelFormat = Format::COLOR_SRGBA_32;
|
texelFormat = Format::COLOR_SRGBA_32;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (header.getGLFormat() == ktx::GLFormat::RGBA && header.getGLType() == ktx::GLType::UNSIGNED_BYTE && header.getTypeSize() == 1) {
|
} 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;
|
mipFormat = Format::COLOR_RGBA_32;
|
||||||
texelFormat = 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;
|
mipFormat = Format::COLOR_SRGBA_32;
|
||||||
texelFormat = Format::COLOR_SRGBA_32;
|
texelFormat = Format::COLOR_SRGBA_32;
|
||||||
} else {
|
} 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) {
|
} else if (header.getGLFormat() == ktx::GLFormat::RED && header.getGLType() == ktx::GLType::UNSIGNED_BYTE && header.getTypeSize() == 1) {
|
||||||
mipFormat = Format::COLOR_R_8;
|
mipFormat = Format::COLOR_R_8;
|
||||||
if (header.getGLInternaFormat_Uncompressed() == ktx::GLInternalFormat_Uncompressed::R8) {
|
if (header.getGLInternaFormat() == ktx::GLInternalFormat::R8) {
|
||||||
texelFormat = Format::COLOR_R_8;
|
texelFormat = Format::COLOR_R_8;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (header.getGLFormat() == ktx::GLFormat::RG && header.getGLType() == ktx::GLType::UNSIGNED_BYTE && header.getTypeSize() == 1) {
|
} else if (header.getGLFormat() == ktx::GLFormat::RG && header.getGLType() == ktx::GLType::UNSIGNED_BYTE && header.getTypeSize() == 1) {
|
||||||
mipFormat = Format::VEC2NU8_XY;
|
mipFormat = Format::VEC2NU8_XY;
|
||||||
if (header.getGLInternaFormat_Uncompressed() == ktx::GLInternalFormat_Uncompressed::RG8) {
|
if (header.getGLInternaFormat() == ktx::GLInternalFormat::RG8) {
|
||||||
texelFormat = Format::VEC2NU8_XY;
|
texelFormat = Format::VEC2NU8_XY;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (header.getGLFormat() == ktx::GLFormat::COMPRESSED_FORMAT && header.getGLType() == ktx::GLType::COMPRESSED_TYPE) {
|
} else if (header.isCompressed()) {
|
||||||
if (header.getGLInternaFormat_Compressed() == ktx::GLInternalFormat_Compressed::COMPRESSED_SRGB_S3TC_DXT1_EXT) {
|
if (header.getGLInternaFormat() == ktx::GLInternalFormat::COMPRESSED_SRGB_S3TC_DXT1_EXT) {
|
||||||
mipFormat = Format::COLOR_COMPRESSED_SRGB;
|
mipFormat = Format::COLOR_COMPRESSED_SRGB;
|
||||||
texelFormat = 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;
|
mipFormat = Format::COLOR_COMPRESSED_SRGBA_MASK;
|
||||||
texelFormat = 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;
|
mipFormat = Format::COLOR_COMPRESSED_SRGBA;
|
||||||
texelFormat = 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;
|
mipFormat = Format::COLOR_COMPRESSED_RED;
|
||||||
texelFormat = 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;
|
mipFormat = Format::COLOR_COMPRESSED_XY;
|
||||||
texelFormat = 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;
|
mipFormat = Format::COLOR_COMPRESSED_SRGBA_HIGH;
|
||||||
texelFormat = Format::COLOR_COMPRESSED_SRGBA_HIGH;
|
texelFormat = Format::COLOR_COMPRESSED_SRGBA_HIGH;
|
||||||
} else {
|
} else {
|
||||||
|
|
303
libraries/ktx/src/khronos/KHR.h
Normal file
303
libraries/ktx/src/khronos/KHR.h
Normal file
|
@ -0,0 +1,303 @@
|
||||||
|
//
|
||||||
|
// 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,
|
||||||
|
};
|
||||||
|
|
||||||
|
template <uint32_t ALIGNMENT>
|
||||||
|
inline uint32_t evalAlignedCompressedBlockCount(uint32_t value) {
|
||||||
|
// FIXME add static assert that ALIGNMENT is a power of 2
|
||||||
|
return (value + (ALIGNMENT - 1) / ALIGNMENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint8_t evalBlockAlignemnt(InternalFormat format, uint32_t value) {
|
||||||
|
switch (format) {
|
||||||
|
case InternalFormat::COMPRESSED_SRGB_S3TC_DXT1_EXT: // BC1
|
||||||
|
case InternalFormat::COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT: // BC1A
|
||||||
|
case InternalFormat::COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: // BC3
|
||||||
|
case InternalFormat::COMPRESSED_RED_RGTC1: // BC4
|
||||||
|
case InternalFormat::COMPRESSED_RG_RGTC2: // BC5
|
||||||
|
case InternalFormat::COMPRESSED_SRGB_ALPHA_BPTC_UNORM: // BC7
|
||||||
|
return evalAlignedCompressedBlockCount<4>(value);
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw std::runtime_error("Unknown format");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint8_t evalCompressedBlockSize(InternalFormat format) {
|
||||||
|
switch (format) {
|
||||||
|
case InternalFormat::COMPRESSED_SRGB_S3TC_DXT1_EXT:
|
||||||
|
case InternalFormat::COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT:
|
||||||
|
case InternalFormat::COMPRESSED_RED_RGTC1:
|
||||||
|
return 8;
|
||||||
|
|
||||||
|
case InternalFormat::COMPRESSED_SRGB_ALPHA_BPTC_UNORM:
|
||||||
|
case InternalFormat::COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT:
|
||||||
|
case InternalFormat::COMPRESSED_RG_RGTC2:
|
||||||
|
return 16;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
|
};
|
||||||
|
|
||||||
|
inline uint8_t evalComponentCount(BaseInternalFormat format) {
|
||||||
|
switch (format) {
|
||||||
|
case BaseInternalFormat::DEPTH_COMPONENT:
|
||||||
|
case BaseInternalFormat::STENCIL_INDEX:
|
||||||
|
case BaseInternalFormat::RED:
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
case BaseInternalFormat::DEPTH_STENCIL:
|
||||||
|
case BaseInternalFormat::RG:
|
||||||
|
return 2;
|
||||||
|
|
||||||
|
case BaseInternalFormat::RGB:
|
||||||
|
return 3;
|
||||||
|
|
||||||
|
case BaseInternalFormat::RGBA:
|
||||||
|
return 4;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace cubemap {
|
||||||
|
enum Constants {
|
||||||
|
NUM_CUBEMAPFACES = 6,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class Face {
|
||||||
|
POSITIVE_X = 0x8515,
|
||||||
|
NEGATIVE_X = 0x8516,
|
||||||
|
POSITIVE_Y = 0x8517,
|
||||||
|
NEGATIVE_Y = 0x8518,
|
||||||
|
POSITIVE_Z = 0x8519,
|
||||||
|
NEGATIVE_Z = 0x851A,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // khronos_khr_hpp
|
|
@ -16,16 +16,6 @@
|
||||||
|
|
||||||
using namespace ktx;
|
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 {{
|
const Header::Identifier ktx::Header::IDENTIFIER {{
|
||||||
0xAB, 0x4B, 0x54, 0x58, 0x20, 0x31, 0x31, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A
|
0xAB, 0x4B, 0x54, 0x58, 0x20, 0x31, 0x31, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A
|
||||||
}};
|
}};
|
||||||
|
@ -38,68 +28,45 @@ uint32_t Header::evalMaxDimension() const {
|
||||||
return std::max(getPixelWidth(), std::max(getPixelHeight(), getPixelDepth()));
|
return std::max(getPixelWidth(), std::max(getPixelHeight(), getPixelDepth()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t Header::evalPixelOrBlockDimension(uint32_t pixelDimension) const {
|
||||||
|
if (isCompressed()) {
|
||||||
|
return khronos::gl::texture::evalBlockAlignemnt(getGLInternaFormat(), pixelDimension);
|
||||||
|
}
|
||||||
|
return pixelDimension;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t Header::evalMipPixelOrBlockDimension(uint32_t mipLevel, uint32_t pixelDimension) const {
|
||||||
|
uint32_t mipPixelDimension = evalMipDimension(mipLevel, pixelDimension);
|
||||||
|
return evalPixelOrBlockDimension(mipPixelDimension);
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t Header::evalPixelOrBlockWidth(uint32_t level) const {
|
uint32_t Header::evalPixelOrBlockWidth(uint32_t level) const {
|
||||||
auto pixelWidth = std::max(getPixelWidth() >> level, 1U);
|
return evalMipPixelOrBlockDimension(level, getPixelWidth());
|
||||||
if (getGLType() == GLType::COMPRESSED_TYPE) {
|
|
||||||
return (pixelWidth + 3) / 4;
|
|
||||||
} else {
|
|
||||||
return pixelWidth;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t Header::evalPixelOrBlockHeight(uint32_t level) const {
|
uint32_t Header::evalPixelOrBlockHeight(uint32_t level) const {
|
||||||
auto pixelWidth = std::max(getPixelHeight() >> level, 1U);
|
return evalMipPixelOrBlockDimension(level, getPixelHeight());
|
||||||
if (getGLType() == GLType::COMPRESSED_TYPE) {
|
|
||||||
auto format = getGLInternaFormat_Compressed();
|
|
||||||
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;
|
|
||||||
default:
|
|
||||||
throw std::runtime_error("Unknown format");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return pixelWidth;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t Header::evalPixelOrBlockDepth(uint32_t level) const {
|
uint32_t Header::evalPixelOrBlockDepth(uint32_t level) const {
|
||||||
return std::max(getPixelDepth() >> level, 1U);
|
return evalMipDimension(level, getPixelDepth());
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t Header::evalPixelOrBlockSize() const {
|
size_t Header::evalPixelOrBlockSize() const {
|
||||||
if (getGLType() == GLType::COMPRESSED_TYPE) {
|
size_t result = 0;
|
||||||
auto format = getGLInternaFormat_Compressed();
|
if (isCompressed()) {
|
||||||
if (format == GLInternalFormat_Compressed::COMPRESSED_SRGB_S3TC_DXT1_EXT) {
|
auto format = getGLInternaFormat();
|
||||||
return 8;
|
result = khronos::gl::texture::evalCompressedBlockSize(format);
|
||||||
} 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;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
|
// FIXME should really be using the internal format, not the base internal format
|
||||||
auto baseFormat = getGLBaseInternalFormat();
|
auto baseFormat = getGLBaseInternalFormat();
|
||||||
if (baseFormat == GLBaseInternalFormat::RED) {
|
result = khronos::gl::texture::evalComponentCount(baseFormat);
|
||||||
return 1;
|
|
||||||
} else if (baseFormat == GLBaseInternalFormat::RG) {
|
|
||||||
return 2;
|
|
||||||
} else if (baseFormat == GLBaseInternalFormat::RGB) {
|
|
||||||
return 3;
|
|
||||||
} else if (baseFormat == GLBaseInternalFormat::RGBA) {
|
|
||||||
return 4;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
qWarning() << "Unknown ktx format: " << glFormat << " " << glBaseInternalFormat << " " << glInternalFormat;
|
if (0 == result) {
|
||||||
return 0;
|
qWarning() << "Unknown ktx format: " << glFormat << " " << glBaseInternalFormat << " " << glInternalFormat;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t Header::evalRowSize(uint32_t level) const {
|
size_t Header::evalRowSize(uint32_t level) const {
|
||||||
|
@ -108,16 +75,16 @@ size_t Header::evalRowSize(uint32_t level) const {
|
||||||
if (pixSize == 0) {
|
if (pixSize == 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
auto netSize = pixWidth * pixSize;
|
return evalPaddedSize(pixWidth * pixSize);
|
||||||
auto padding = evalPadding(netSize);
|
|
||||||
return netSize + padding;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t Header::evalFaceSize(uint32_t level) const {
|
size_t Header::evalFaceSize(uint32_t level) const {
|
||||||
auto pixHeight = evalPixelOrBlockHeight(level);
|
auto pixHeight = evalPixelOrBlockHeight(level);
|
||||||
auto pixDepth = evalPixelOrBlockDepth(level);
|
auto pixDepth = evalPixelOrBlockDepth(level);
|
||||||
auto rowSize = evalRowSize(level);
|
auto rowSize = evalRowSize(level);
|
||||||
return pixDepth * pixHeight * rowSize;
|
return pixDepth * pixHeight * rowSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t Header::evalImageSize(uint32_t level) const {
|
size_t Header::evalImageSize(uint32_t level) const {
|
||||||
auto faceSize = evalFaceSize(level);
|
auto faceSize = evalFaceSize(level);
|
||||||
if (!checkAlignment(faceSize)) {
|
if (!checkAlignment(faceSize)) {
|
||||||
|
@ -192,7 +159,7 @@ KeyValue::KeyValue(const std::string& key, const std::string& value) :
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t KeyValue::serializedByteSize() const {
|
uint32_t KeyValue::serializedByteSize() const {
|
||||||
return (uint32_t) (sizeof(uint32_t) + _byteSize + Header::evalPadding(_byteSize));
|
return (uint32_t)sizeof(uint32_t) + evalPaddedSize(_byteSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t KeyValue::serializedKeyValuesByteSize(const KeyValues& keyValues) {
|
uint32_t KeyValue::serializedKeyValuesByteSize(const KeyValues& keyValues) {
|
||||||
|
@ -200,14 +167,8 @@ uint32_t KeyValue::serializedKeyValuesByteSize(const KeyValues& keyValues) {
|
||||||
for (auto& keyval : keyValues) {
|
for (auto& keyval : keyValues) {
|
||||||
keyValuesSize += keyval.serializedByteSize();
|
keyValuesSize += keyval.serializedByteSize();
|
||||||
}
|
}
|
||||||
return (keyValuesSize + Header::evalPadding(keyValuesSize));
|
Q_ASSERT(keyValuesSize % 4 == 0);
|
||||||
}
|
return keyValuesSize;
|
||||||
|
|
||||||
|
|
||||||
KTX::KTX() {
|
|
||||||
}
|
|
||||||
|
|
||||||
KTX::~KTX() {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void KTX::resetStorage(const StoragePointer& storage) {
|
void KTX::resetStorage(const StoragePointer& storage) {
|
||||||
|
@ -230,7 +191,7 @@ size_t KTX::getTexelsDataSize() const {
|
||||||
if (!_storage) {
|
if (!_storage) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return (_storage->data() + _storage->size()) - getTexelsData();
|
return _storage->size() - sizeof(Header) - getKeyValueDataSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
const Byte* KTX::getKeyValueData() const {
|
const Byte* KTX::getKeyValueData() const {
|
||||||
|
|
|
@ -22,7 +22,14 @@
|
||||||
|
|
||||||
#include <shared/Storage.h>
|
#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
|
Byte[12] identifier
|
||||||
UInt32 endianness
|
UInt32 endianness
|
||||||
|
@ -38,6 +45,8 @@ UInt32 numberOfArrayElements
|
||||||
UInt32 numberOfFaces
|
UInt32 numberOfFaces
|
||||||
UInt32 numberOfMipmapLevels
|
UInt32 numberOfMipmapLevels
|
||||||
UInt32 bytesOfKeyValueData
|
UInt32 bytesOfKeyValueData
|
||||||
|
|
||||||
|
**** Each KTX key value pair block is 4 byte aligned
|
||||||
|
|
||||||
for each keyValuePair that fits in bytesOfKeyValueData
|
for each keyValuePair that fits in bytesOfKeyValueData
|
||||||
UInt32 keyAndValueByteSize
|
UInt32 keyAndValueByteSize
|
||||||
|
@ -45,6 +54,8 @@ for each keyValuePair that fits in bytesOfKeyValueData
|
||||||
Byte valuePadding[3 - ((keyAndValueByteSize + 3) % 4)]
|
Byte valuePadding[3 - ((keyAndValueByteSize + 3) % 4)]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
**** Each mip and cube face is 4 byte aligned
|
||||||
|
|
||||||
for each mipmap_level in numberOfMipmapLevels*
|
for each mipmap_level in numberOfMipmapLevels*
|
||||||
UInt32 imageSize;
|
UInt32 imageSize;
|
||||||
for each array_element in numberOfArrayElements*
|
for each array_element in numberOfArrayElements*
|
||||||
|
@ -67,229 +78,22 @@ end
|
||||||
** Uncompressed texture data matches a GL_UNPACK_ALIGNMENT of 4.
|
** Uncompressed texture data matches a GL_UNPACK_ALIGNMENT of 4.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
namespace ktx {
|
namespace ktx {
|
||||||
const uint32_t PACKING_SIZE { sizeof(uint32_t) };
|
// Alignment constants
|
||||||
const std::string HIFI_MIN_POPULATED_MIP_KEY{ "hifi.minMip" };
|
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::cubemap::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;
|
using Byte = uint8_t;
|
||||||
|
|
||||||
enum class GLType : uint32_t {
|
using GLType = khronos::gl::Type;
|
||||||
COMPRESSED_TYPE = 0,
|
using GLFormat = khronos::gl::texture::Format;
|
||||||
|
using GLInternalFormat = khronos::gl::texture::InternalFormat;
|
||||||
// GL 4.4 Table 8.2
|
using GLBaseInternalFormat = khronos::gl::texture::BaseInternalFormat;
|
||||||
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_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 Storage = storage::Storage;
|
using Storage = storage::Storage;
|
||||||
using StoragePointer = std::shared_ptr<Storage>;
|
using StoragePointer = std::shared_ptr<Storage>;
|
||||||
|
@ -299,31 +103,54 @@ namespace ktx {
|
||||||
|
|
||||||
bool checkIdentifier(const Byte* identifier);
|
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 evalPaddedSize(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 & ALIGNMENT_REMAINDER) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Header
|
// Header
|
||||||
struct 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>;
|
using Identifier = std::array<uint8_t, IDENTIFIER_LENGTH>;
|
||||||
static const Identifier IDENTIFIER;
|
static const Identifier IDENTIFIER;
|
||||||
|
|
||||||
static const uint32_t ENDIAN_TEST = 0x04030201;
|
static const uint32_t ENDIAN_TEST = 0x04030201;
|
||||||
static const uint32_t REVERSE_ENDIAN_TEST = 0x01020304;
|
static const uint32_t REVERSE_ENDIAN_TEST = 0x01020304;
|
||||||
|
|
||||||
static uint32_t evalPadding(size_t byteSize);
|
|
||||||
static bool checkAlignment(size_t byteSize);
|
|
||||||
|
|
||||||
Header();
|
Header();
|
||||||
|
|
||||||
Byte identifier[IDENTIFIER_LENGTH];
|
Byte identifier[IDENTIFIER_LENGTH];
|
||||||
uint32_t endianness { ENDIAN_TEST };
|
uint32_t endianness { ENDIAN_TEST };
|
||||||
|
|
||||||
uint32_t glType;
|
uint32_t glType { static_cast<uint32_t>(GLType::UNSIGNED_BYTE) };
|
||||||
uint32_t glTypeSize { 0 };
|
uint32_t glTypeSize { 0 };
|
||||||
uint32_t glFormat;
|
uint32_t glFormat { static_cast<uint32_t>(GLFormat::RGBA) };
|
||||||
uint32_t glInternalFormat;
|
uint32_t glInternalFormat { static_cast<uint32_t>(GLInternalFormat::RGBA8) };
|
||||||
uint32_t glBaseInternalFormat;
|
uint32_t glBaseInternalFormat { static_cast<uint32_t>(GLBaseInternalFormat::RGBA) };
|
||||||
|
|
||||||
uint32_t pixelWidth { 1 };
|
uint32_t pixelWidth { 1 };
|
||||||
uint32_t pixelHeight { 0 };
|
uint32_t pixelHeight { 1 };
|
||||||
uint32_t pixelDepth { 0 };
|
uint32_t pixelDepth { 0 };
|
||||||
uint32_t numberOfArrayElements { 0 };
|
uint32_t numberOfArrayElements { 0 };
|
||||||
uint32_t numberOfFaces { 1 };
|
uint32_t numberOfFaces { 1 };
|
||||||
|
@ -336,6 +163,7 @@ namespace ktx {
|
||||||
uint32_t getPixelDepth() const { return (pixelDepth ? pixelDepth : 1); }
|
uint32_t getPixelDepth() const { return (pixelDepth ? pixelDepth : 1); }
|
||||||
uint32_t getNumberOfSlices() const { return (numberOfArrayElements ? numberOfArrayElements : 1); }
|
uint32_t getNumberOfSlices() const { return (numberOfArrayElements ? numberOfArrayElements : 1); }
|
||||||
uint32_t getNumberOfLevels() const { return (numberOfMipmapLevels ? numberOfMipmapLevels : 1); }
|
uint32_t getNumberOfLevels() const { return (numberOfMipmapLevels ? numberOfMipmapLevels : 1); }
|
||||||
|
bool isCompressed() const { return glFormat == COMPRESSED_FORMAT; }
|
||||||
|
|
||||||
uint32_t evalMaxDimension() const;
|
uint32_t evalMaxDimension() const;
|
||||||
uint32_t evalPixelOrBlockWidth(uint32_t level) const;
|
uint32_t evalPixelOrBlockWidth(uint32_t level) const;
|
||||||
|
@ -347,17 +175,21 @@ namespace ktx {
|
||||||
size_t evalFaceSize(uint32_t level) const;
|
size_t evalFaceSize(uint32_t level) const;
|
||||||
size_t evalImageSize(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;
|
glType = (uint32_t) type;
|
||||||
glTypeSize = typeSize;
|
glTypeSize = typeSize;
|
||||||
glFormat = (uint32_t) format;
|
glFormat = (uint32_t) format;
|
||||||
glInternalFormat = (uint32_t) internalFormat;
|
glInternalFormat = (uint32_t) internalFormat;
|
||||||
glBaseInternalFormat = (uint32_t) baseInternalFormat;
|
glBaseInternalFormat = (uint32_t) baseInternalFormat;
|
||||||
}
|
}
|
||||||
void setCompressed(GLInternalFormat_Compressed internalFormat, GLBaseInternalFormat baseInternalFormat) {
|
|
||||||
glType = (uint32_t) GLType::COMPRESSED_TYPE;
|
// FIXME base internal format should automatically be determined by internal format
|
||||||
glTypeSize = 1;
|
void setCompressed(GLInternalFormat internalFormat, GLBaseInternalFormat baseInternalFormat) {
|
||||||
glFormat = (uint32_t) GLFormat::COMPRESSED_FORMAT;
|
glType = COMPRESSED_TYPE;
|
||||||
|
glFormat = COMPRESSED_FORMAT;
|
||||||
|
glTypeSize = COMPRESSED_TYPE_SIZE;
|
||||||
glInternalFormat = (uint32_t) internalFormat;
|
glInternalFormat = (uint32_t) internalFormat;
|
||||||
glBaseInternalFormat = (uint32_t) baseInternalFormat;
|
glBaseInternalFormat = (uint32_t) baseInternalFormat;
|
||||||
}
|
}
|
||||||
|
@ -365,18 +197,9 @@ namespace ktx {
|
||||||
GLType getGLType() const { return (GLType)glType; }
|
GLType getGLType() const { return (GLType)glType; }
|
||||||
uint32_t getTypeSize() const { return glTypeSize; }
|
uint32_t getTypeSize() const { return glTypeSize; }
|
||||||
GLFormat getGLFormat() const { return (GLFormat)glFormat; }
|
GLFormat getGLFormat() const { return (GLFormat)glFormat; }
|
||||||
GLInternalFormat_Uncompressed getGLInternaFormat_Uncompressed() const { return (GLInternalFormat_Uncompressed)glInternalFormat; }
|
GLInternalFormat getGLInternaFormat() const { return (GLInternalFormat)glInternalFormat; }
|
||||||
GLInternalFormat_Compressed getGLInternaFormat_Compressed() const { return (GLInternalFormat_Compressed)glInternalFormat; }
|
|
||||||
GLBaseInternalFormat getGLBaseInternalFormat() const { return (GLBaseInternalFormat)glBaseInternalFormat; }
|
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 set1D(uint32_t width) { setDimensions(width); }
|
||||||
void set1DArray(uint32_t width, uint32_t numSlices) { setDimensions(width, 0, 0, (numSlices > 0 ? numSlices : 1)); }
|
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); }
|
void set2D(uint32_t width, uint32_t height) { setDimensions(width, height); }
|
||||||
|
@ -386,12 +209,33 @@ namespace ktx {
|
||||||
void setCube(uint32_t width, uint32_t height) { setDimensions(width, height, 0, 0, NUM_CUBEMAPFACES); }
|
void setCube(uint32_t width, uint32_t height) { setDimensions(width, height, 0, 0, NUM_CUBEMAPFACES); }
|
||||||
void setCubeArray(uint32_t width, uint32_t height, uint32_t numSlices) { setDimensions(width, height, 0, (numSlices > 0 ? numSlices : 1), NUM_CUBEMAPFACES); }
|
void setCubeArray(uint32_t width, uint32_t height, uint32_t numSlices) { setDimensions(width, height, 0, (numSlices > 0 ? numSlices : 1), NUM_CUBEMAPFACES); }
|
||||||
|
|
||||||
|
bool isValid() const;
|
||||||
|
|
||||||
|
// Generate a set of image descriptors based on the assumption that the full mip pyramid is populated
|
||||||
ImageDescriptors generateImageDescriptors() const;
|
ImageDescriptors generateImageDescriptors() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint32_t evalPixelOrBlockDimension(uint32_t pixelDimension) const;
|
||||||
|
uint32_t evalMipPixelOrBlockDimension(uint32_t level, uint32_t pixelDimension) const;
|
||||||
|
|
||||||
|
static inline uint32_t evalMipDimension(uint32_t mipLevel, uint32_t pixelDimension) {
|
||||||
|
return std::max(pixelDimension >> mipLevel, 1U);
|
||||||
|
}
|
||||||
|
|
||||||
|
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_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 KV_SIZE_WIDTH { ALIGNMENT }; // Number of bytes for keyAndValueByteSize
|
||||||
static const size_t IMAGE_SIZE_WIDTH = 4; // Number of bytes for imageSize
|
static const size_t IMAGE_SIZE_WIDTH { ALIGNMENT }; // Number of bytes for imageSize
|
||||||
|
|
||||||
// Key Values
|
// Key Values
|
||||||
struct KeyValue {
|
struct KeyValue {
|
||||||
|
@ -426,6 +270,7 @@ namespace ktx {
|
||||||
const uint32_t _imageSize;
|
const uint32_t _imageSize;
|
||||||
const uint32_t _faceSize;
|
const uint32_t _faceSize;
|
||||||
const uint32_t _padding;
|
const uint32_t _padding;
|
||||||
|
|
||||||
ImageHeader(bool cube, size_t imageOffset, uint32_t imageSize, uint32_t padding) :
|
ImageHeader(bool cube, size_t imageOffset, uint32_t imageSize, uint32_t padding) :
|
||||||
_numFaces(cube ? NUM_CUBEMAPFACES : 1),
|
_numFaces(cube ? NUM_CUBEMAPFACES : 1),
|
||||||
_imageOffset(imageOffset),
|
_imageOffset(imageOffset),
|
||||||
|
@ -481,11 +326,11 @@ namespace ktx {
|
||||||
class KTX {
|
class KTX {
|
||||||
void resetStorage(const StoragePointer& src);
|
void resetStorage(const StoragePointer& src);
|
||||||
|
|
||||||
KTX();
|
KTX() {}
|
||||||
KTX(const StoragePointer& storage, const Header& header, const KeyValues& keyValues, const Images& images);
|
KTX(const StoragePointer& storage, const Header& header, const KeyValues& keyValues, const Images& images);
|
||||||
public:
|
public:
|
||||||
~KTX();
|
static bool validate(const StoragePointer& src);
|
||||||
|
|
||||||
// Define a KTX object manually to write it somewhere (in a file on disk?)
|
// Define a KTX object manually to write it somewhere (in a file on disk?)
|
||||||
// This path allocate the Storage where to store header, keyvalues and copy mips
|
// This path allocate the Storage where to store header, keyvalues and copy mips
|
||||||
// Then COPY all the data
|
// Then COPY all the data
|
||||||
|
@ -530,6 +375,7 @@ namespace ktx {
|
||||||
KTXDescriptor toDescriptor() const;
|
KTXDescriptor toDescriptor() const;
|
||||||
size_t getKeyValueDataSize() const;
|
size_t getKeyValueDataSize() const;
|
||||||
size_t getTexelsDataSize() const;
|
size_t getTexelsDataSize() const;
|
||||||
|
bool isValid() const;
|
||||||
|
|
||||||
Header _header;
|
Header _header;
|
||||||
StoragePointer _storage;
|
StoragePointer _storage;
|
||||||
|
|
|
@ -151,7 +151,7 @@ namespace ktx {
|
||||||
auto expectedImageSize = header.evalImageSize((uint32_t) images.size());
|
auto expectedImageSize = header.evalImageSize((uint32_t) images.size());
|
||||||
if (imageSize != expectedImageSize) {
|
if (imageSize != expectedImageSize) {
|
||||||
break;
|
break;
|
||||||
} else if (!Header::checkAlignment(imageSize)) {
|
} else if (!checkAlignment(imageSize)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -163,7 +163,7 @@ namespace ktx {
|
||||||
|
|
||||||
// If enough data ahead then capture the pointer
|
// If enough data ahead then capture the pointer
|
||||||
if ((currentPtr - srcBytes) + imageSize <= (srcSize)) {
|
if ((currentPtr - srcBytes) + imageSize <= (srcSize)) {
|
||||||
auto padding = Header::evalPadding(imageSize);
|
auto padding = evalPadding(imageSize);
|
||||||
|
|
||||||
if (numFaces == NUM_CUBEMAPFACES) {
|
if (numFaces == NUM_CUBEMAPFACES) {
|
||||||
Image::FaceBytes faces(NUM_CUBEMAPFACES);
|
Image::FaceBytes faces(NUM_CUBEMAPFACES);
|
||||||
|
|
428
libraries/ktx/src/ktx/Validation.cpp
Normal file
428
libraries/ktx/src/ktx/Validation.cpp
Normal file
|
@ -0,0 +1,428 @@
|
||||||
|
//
|
||||||
|
// 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
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "KTX.h"
|
||||||
|
|
||||||
|
#include <unordered_set>
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
using namespace ktx;
|
||||||
|
|
||||||
|
static const std::unordered_set<uint32_t> VALID_GL_TYPES {
|
||||||
|
(uint32_t)GLType::UNSIGNED_BYTE,
|
||||||
|
(uint32_t)GLType::BYTE,
|
||||||
|
(uint32_t)GLType::UNSIGNED_SHORT,
|
||||||
|
(uint32_t)GLType::SHORT,
|
||||||
|
(uint32_t)GLType::UNSIGNED_INT,
|
||||||
|
(uint32_t)GLType::INT,
|
||||||
|
(uint32_t)GLType::HALF_FLOAT,
|
||||||
|
(uint32_t)GLType::FLOAT,
|
||||||
|
(uint32_t)GLType::UNSIGNED_BYTE_3_3_2,
|
||||||
|
(uint32_t)GLType::UNSIGNED_BYTE_2_3_3_REV,
|
||||||
|
(uint32_t)GLType::UNSIGNED_SHORT_5_6_5,
|
||||||
|
(uint32_t)GLType::UNSIGNED_SHORT_5_6_5_REV,
|
||||||
|
(uint32_t)GLType::UNSIGNED_SHORT_4_4_4_4,
|
||||||
|
(uint32_t)GLType::UNSIGNED_SHORT_4_4_4_4_REV,
|
||||||
|
(uint32_t)GLType::UNSIGNED_SHORT_5_5_5_1,
|
||||||
|
(uint32_t)GLType::UNSIGNED_SHORT_1_5_5_5_REV,
|
||||||
|
(uint32_t)GLType::UNSIGNED_INT_8_8_8_8,
|
||||||
|
(uint32_t)GLType::UNSIGNED_INT_8_8_8_8_REV,
|
||||||
|
(uint32_t)GLType::UNSIGNED_INT_10_10_10_2,
|
||||||
|
(uint32_t)GLType::UNSIGNED_INT_2_10_10_10_REV,
|
||||||
|
(uint32_t)GLType::UNSIGNED_INT_24_8,
|
||||||
|
(uint32_t)GLType::UNSIGNED_INT_10F_11F_11F_REV,
|
||||||
|
(uint32_t)GLType::UNSIGNED_INT_5_9_9_9_REV,
|
||||||
|
(uint32_t)GLType::FLOAT_32_UNSIGNED_INT_24_8_REV,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const std::unordered_set<uint32_t> VALID_GL_FORMATS {
|
||||||
|
(uint32_t)GLFormat::STENCIL_INDEX,
|
||||||
|
(uint32_t)GLFormat::DEPTH_COMPONENT,
|
||||||
|
(uint32_t)GLFormat::DEPTH_STENCIL,
|
||||||
|
(uint32_t)GLFormat::RED,
|
||||||
|
(uint32_t)GLFormat::GREEN,
|
||||||
|
(uint32_t)GLFormat::BLUE,
|
||||||
|
(uint32_t)GLFormat::RG,
|
||||||
|
(uint32_t)GLFormat::RGB,
|
||||||
|
(uint32_t)GLFormat::RGBA,
|
||||||
|
(uint32_t)GLFormat::BGR,
|
||||||
|
(uint32_t)GLFormat::BGRA,
|
||||||
|
(uint32_t)GLFormat::RG_INTEGER,
|
||||||
|
(uint32_t)GLFormat::RED_INTEGER,
|
||||||
|
(uint32_t)GLFormat::GREEN_INTEGER,
|
||||||
|
(uint32_t)GLFormat::BLUE_INTEGER,
|
||||||
|
(uint32_t)GLFormat::RGB_INTEGER,
|
||||||
|
(uint32_t)GLFormat::RGBA_INTEGER,
|
||||||
|
(uint32_t)GLFormat::BGR_INTEGER,
|
||||||
|
(uint32_t)GLFormat::BGRA_INTEGER,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const std::unordered_set<uint32_t> VALID_GL_INTERNAL_FORMATS {
|
||||||
|
(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_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 {
|
||||||
|
(uint32_t)GLBaseInternalFormat::DEPTH_COMPONENT,
|
||||||
|
(uint32_t)GLBaseInternalFormat::DEPTH_STENCIL,
|
||||||
|
(uint32_t)GLBaseInternalFormat::RED,
|
||||||
|
(uint32_t)GLBaseInternalFormat::RG,
|
||||||
|
(uint32_t)GLBaseInternalFormat::RGB,
|
||||||
|
(uint32_t)GLBaseInternalFormat::RGBA,
|
||||||
|
(uint32_t)GLBaseInternalFormat::STENCIL_INDEX,
|
||||||
|
};
|
||||||
|
|
||||||
|
bool Header::isValid() const {
|
||||||
|
if (0 != memcmp(identifier, IDENTIFIER.data(), IDENTIFIER_LENGTH)) {
|
||||||
|
qDebug() << "Invalid header identifier";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (endianness != ENDIAN_TEST && endianness != REVERSE_ENDIAN_TEST) {
|
||||||
|
qDebug("Invalid endian marker 0x%x", endianness);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// GL enum validity
|
||||||
|
//
|
||||||
|
if (VALID_GL_BASE_INTERNAL_FORMATS.count(glBaseInternalFormat) != 1) {
|
||||||
|
qDebug("Invalid base internal format 0x%x", glBaseInternalFormat);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (VALID_GL_TYPES.count(glType) != 1) {
|
||||||
|
qDebug("Invalid type 0x%x", glType);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (VALID_GL_FORMATS.count(glFormat) != 1) {
|
||||||
|
qDebug("Invalid format 0x%x", glFormat);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (VALID_GL_INTERNAL_FORMATS.count(glInternalFormat) != 1) {
|
||||||
|
qDebug("Invalid internal format 0x%x", glInternalFormat);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Dimensions validity
|
||||||
|
//
|
||||||
|
|
||||||
|
// Textures must at least have a width
|
||||||
|
// If they have a depth, they must have a height
|
||||||
|
if ((pixelWidth == 0) || (pixelDepth != 0 && pixelHeight == 0)) {
|
||||||
|
qDebug() << "Invalid dimensions " << pixelWidth << "x" << pixelHeight << "x" << pixelDepth;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (numberOfFaces != 1 && numberOfFaces != NUM_CUBEMAPFACES) {
|
||||||
|
qDebug() << "Invalid number of faces " << numberOfFaces;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME validate numberOfMipmapLevels based on the dimensions?
|
||||||
|
|
||||||
|
if ((bytesOfKeyValueData % 4) != 0) {
|
||||||
|
qDebug() << "Invalid keyvalue data size " << bytesOfKeyValueData;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct AlignedStreamBuffer {
|
||||||
|
AlignedStreamBuffer(size_t size, const uint8_t* data)
|
||||||
|
: _size(size), _data(data) { }
|
||||||
|
|
||||||
|
AlignedStreamBuffer(const StoragePointer& storage)
|
||||||
|
: AlignedStreamBuffer(storage->size(), storage->data()) { }
|
||||||
|
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
bool read(T& t) {
|
||||||
|
// Ensure we don't read more than we have
|
||||||
|
if (sizeof(T) > _size) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Grab the data
|
||||||
|
memcpy(&t, _data, sizeof(T));
|
||||||
|
|
||||||
|
// Advance the pointer
|
||||||
|
return skip(sizeof(T));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool skip(size_t skipSize) {
|
||||||
|
skipSize = ktx::evalPaddedSize(skipSize);
|
||||||
|
if (skipSize > _size) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
_data += skipSize;
|
||||||
|
_size -= skipSize;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
AlignedStreamBuffer front(size_t size) const {
|
||||||
|
return AlignedStreamBuffer { std::min(size, _size), _data };
|
||||||
|
}
|
||||||
|
|
||||||
|
bool empty() const {
|
||||||
|
return _size == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
size_t _size;
|
||||||
|
const uint8_t* _data;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool validateKeyValueData(AlignedStreamBuffer kvbuffer) {
|
||||||
|
while (!kvbuffer.empty()) {
|
||||||
|
uint32_t keyValueSize;
|
||||||
|
// Try to fetch the size of the next key value block
|
||||||
|
if (!kvbuffer.read(keyValueSize)) {
|
||||||
|
qDebug() << "Unable to read past key value size";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!kvbuffer.skip(keyValueSize)) {
|
||||||
|
qDebug() << "Unable to skip past key value data";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool KTX::validate(const StoragePointer& src) {
|
||||||
|
if (!checkAlignment(src->size())) {
|
||||||
|
// All KTX data is 4-byte aligned
|
||||||
|
qDebug() << "Invalid size, not 4 byte aligned";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Header header;
|
||||||
|
AlignedStreamBuffer buffer { src };
|
||||||
|
if (!buffer.read(header)) {
|
||||||
|
qDebug() << "Unable to read header";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Basic header validation, are the enums and size valid?
|
||||||
|
if (!header.isValid()) {
|
||||||
|
qDebug() << "Invalid header";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate the key value pairs
|
||||||
|
if (!validateKeyValueData(buffer.front(header.bytesOfKeyValueData))) {
|
||||||
|
qDebug() << "Invalid key value data";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// now skip the KV data
|
||||||
|
if (!buffer.skip(header.bytesOfKeyValueData)) {
|
||||||
|
qDebug() << "Unable to read past key value data";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Validate the images
|
||||||
|
for (uint32_t mip = 0; mip < header.numberOfMipmapLevels; ++mip) {
|
||||||
|
uint32_t imageSize;
|
||||||
|
if (!buffer.read(imageSize)) {
|
||||||
|
qDebug() << "Unable to read image size";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t arrayElements = header.numberOfArrayElements == 0 ? 1 : header.numberOfArrayElements;
|
||||||
|
for (uint32_t arrayElement = 0; arrayElement < arrayElements; ++arrayElement) {
|
||||||
|
for (uint8_t face = 0; face < header.numberOfFaces; ++face) {
|
||||||
|
if (!buffer.skip(imageSize)) {
|
||||||
|
qDebug() << "Unable to skip past image data";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The buffer should be empty afer we've skipped all of the KTX data
|
||||||
|
if (!buffer.empty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
|
@ -70,8 +70,7 @@ namespace ktx {
|
||||||
for (uint32_t l = 0; l < numMips; l++) {
|
for (uint32_t l = 0; l < numMips; l++) {
|
||||||
if (images.size() > l) {
|
if (images.size() > l) {
|
||||||
storageSize += sizeof(uint32_t);
|
storageSize += sizeof(uint32_t);
|
||||||
storageSize += images[l]._imageSize;
|
storageSize += evalPaddedSize(images[l]._imageSize);
|
||||||
storageSize += Header::evalPadding(images[l]._imageSize);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return storageSize;
|
return storageSize;
|
||||||
|
@ -89,8 +88,7 @@ namespace ktx {
|
||||||
for (uint32_t l = 0; l < numMips; l++) {
|
for (uint32_t l = 0; l < numMips; l++) {
|
||||||
if (imageDescriptors.size() > l) {
|
if (imageDescriptors.size() > l) {
|
||||||
storageSize += sizeof(uint32_t);
|
storageSize += sizeof(uint32_t);
|
||||||
storageSize += imageDescriptors[l]._imageSize;
|
storageSize += evalPaddedSize(imageDescriptors[l]._imageSize);
|
||||||
storageSize += Header::evalPadding(imageDescriptors[l]._imageSize);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return storageSize;
|
return storageSize;
|
||||||
|
@ -221,7 +219,7 @@ namespace ktx {
|
||||||
|
|
||||||
// If enough data ahead then capture the copy source pointer
|
// If enough data ahead then capture the copy source pointer
|
||||||
if (currentDataSize + imageSize <= (allocatedImagesDataSize)) {
|
if (currentDataSize + imageSize <= (allocatedImagesDataSize)) {
|
||||||
auto padding = Header::evalPadding(imageSize);
|
auto padding = evalPadding(imageSize);
|
||||||
|
|
||||||
// Single face vs cubes
|
// Single face vs cubes
|
||||||
if (srcImages[l]._numFaces == 1) {
|
if (srcImages[l]._numFaces == 1) {
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#include <QtCore/QTimer>
|
#include <QtCore/QTimer>
|
||||||
#include <QtCore/QThread>
|
#include <QtCore/QThread>
|
||||||
#include <QtCore/QThreadPool>
|
#include <QtCore/QThreadPool>
|
||||||
|
#include <QtCore/QSaveFile>
|
||||||
|
|
||||||
#include <QtGui/QGuiApplication>
|
#include <QtGui/QGuiApplication>
|
||||||
#include <QtGui/QResizeEvent>
|
#include <QtGui/QResizeEvent>
|
||||||
|
@ -38,14 +39,12 @@
|
||||||
#include <StatTracker.h>
|
#include <StatTracker.h>
|
||||||
#include <LogHandler.h>
|
#include <LogHandler.h>
|
||||||
|
|
||||||
|
|
||||||
#include <gpu/Texture.h>
|
#include <gpu/Texture.h>
|
||||||
#include <gl/Config.h>
|
#include <gl/Config.h>
|
||||||
#include <model/TextureMap.h>
|
#include <model/TextureMap.h>
|
||||||
#include <ktx/KTX.h>
|
#include <ktx/KTX.h>
|
||||||
#include <image/Image.h>
|
#include <image/Image.h>
|
||||||
|
|
||||||
|
|
||||||
QSharedPointer<FileLogger> logger;
|
QSharedPointer<FileLogger> logger;
|
||||||
|
|
||||||
gpu::Texture* cacheTexture(const std::string& name, gpu::Texture* srcTexture, bool write = true, bool read = true);
|
gpu::Texture* cacheTexture(const std::string& name, gpu::Texture* srcTexture, bool write = true, bool read = true);
|
||||||
|
@ -59,7 +58,9 @@ void messageHandler(QtMsgType type, const QMessageLogContext& context, const QSt
|
||||||
OutputDebugStringA(logMessage.toLocal8Bit().constData());
|
OutputDebugStringA(logMessage.toLocal8Bit().constData());
|
||||||
OutputDebugStringA("\n");
|
OutputDebugStringA("\n");
|
||||||
#endif
|
#endif
|
||||||
logger->addMessage(qPrintable(logMessage + "\n"));
|
if (logger) {
|
||||||
|
logger->addMessage(qPrintable(logMessage + "\n"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,6 +89,20 @@ int main(int argc, char** argv) {
|
||||||
QCoreApplication::setOrganizationDomain("highfidelity.com");
|
QCoreApplication::setOrganizationDomain("highfidelity.com");
|
||||||
logger.reset(new FileLogger());
|
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::evalPaddedSize(0) == 0);
|
||||||
|
Q_ASSERT(ktx::evalPaddedSize(1) == 4);
|
||||||
|
Q_ASSERT(ktx::evalPaddedSize(2) == 4);
|
||||||
|
Q_ASSERT(ktx::evalPaddedSize(3) == 4);
|
||||||
|
Q_ASSERT(ktx::evalPaddedSize(4) == 4);
|
||||||
|
Q_ASSERT(ktx::evalPaddedSize(1024) == 1024);
|
||||||
|
Q_ASSERT(ktx::evalPaddedSize(1025) == 1028);
|
||||||
Q_ASSERT(sizeof(ktx::Header) == 12 + (sizeof(uint32_t) * 13));
|
Q_ASSERT(sizeof(ktx::Header) == 12 + (sizeof(uint32_t) * 13));
|
||||||
|
|
||||||
DependencyManager::set<tracing::Tracer>();
|
DependencyManager::set<tracing::Tracer>();
|
||||||
|
@ -100,8 +115,10 @@ int main(int argc, char** argv) {
|
||||||
auto ktxMemory = gpu::Texture::serialize(*testTexture);
|
auto ktxMemory = gpu::Texture::serialize(*testTexture);
|
||||||
{
|
{
|
||||||
const auto& ktxStorage = ktxMemory->getStorage();
|
const auto& ktxStorage = ktxMemory->getStorage();
|
||||||
QFile outFile(TEST_IMAGE_KTX);
|
Q_ASSERT_X(ktx::KTX::validate(ktxStorage), __FUNCTION__, "KTX storage validation failed");
|
||||||
if (!outFile.open(QFile::Truncate | QFile::ReadWrite)) {
|
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");
|
throw std::runtime_error("Unable to open file");
|
||||||
}
|
}
|
||||||
auto ktxSize = ktxStorage->size();
|
auto ktxSize = ktxStorage->size();
|
||||||
|
@ -109,7 +126,7 @@ int main(int argc, char** argv) {
|
||||||
auto dest = outFile.map(0, ktxSize);
|
auto dest = outFile.map(0, ktxSize);
|
||||||
memcpy(dest, ktxStorage->data(), ktxSize);
|
memcpy(dest, ktxStorage->data(), ktxSize);
|
||||||
outFile.unmap(dest);
|
outFile.unmap(dest);
|
||||||
outFile.close();
|
outFile.commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -149,5 +166,58 @@ int main(int argc, char** argv) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
static const QString TEST_FOLDER { "H:/ktx_cacheold" };
|
||||||
|
//static const QString TEST_FOLDER { "C:/Users/bdavis/Git/KTX/testimages" };
|
||||||
|
|
||||||
|
//static const QString EXTENSIONS { "4bbdf8f786470e4ab3e672d44b8e8df2.ktx" };
|
||||||
|
static const QString EXTENSIONS { "*.ktx" };
|
||||||
|
|
||||||
|
int mainTemp(int, char**) {
|
||||||
|
qInstallMessageHandler(messageHandler);
|
||||||
|
auto fileInfoList = QDir { TEST_FOLDER }.entryInfoList(QStringList { EXTENSIONS });
|
||||||
|
for (auto fileInfo : fileInfoList) {
|
||||||
|
qDebug() << fileInfo.filePath();
|
||||||
|
std::shared_ptr<storage::Storage> storage { new storage::FileStorage { fileInfo.filePath() } };
|
||||||
|
|
||||||
|
if (!ktx::KTX::validate(storage)) {
|
||||||
|
qDebug() << "KTX invalid";
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ktxFile = ktx::KTX::create(storage);
|
||||||
|
ktx::KTXDescriptor ktxDescriptor = ktxFile->toDescriptor();
|
||||||
|
|
||||||
|
qDebug() << "Contains " << ktxDescriptor.keyValues.size() << " key value pairs";
|
||||||
|
for (const auto& kv : ktxDescriptor.keyValues) {
|
||||||
|
qDebug() << "\t" << kv._key.c_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto offsetToMinMipKV = ktxDescriptor.getValueOffsetForKey(ktx::HIFI_MIN_POPULATED_MIP_KEY);
|
||||||
|
if (offsetToMinMipKV) {
|
||||||
|
auto data = storage->data() + ktx::KTX_HEADER_SIZE + offsetToMinMipKV;
|
||||||
|
auto minMipLevelAvailable = *data;
|
||||||
|
qDebug() << "\tMin mip available " << minMipLevelAvailable;
|
||||||
|
assert(minMipLevelAvailable < ktxDescriptor.header.numberOfMipmapLevels);
|
||||||
|
}
|
||||||
|
auto storageSize = storage->size();
|
||||||
|
for (const auto& faceImageDesc : ktxDescriptor.images) {
|
||||||
|
//assert(0 == (faceImageDesc._faceSize % 4));
|
||||||
|
for (const auto& faceOffset : faceImageDesc._faceOffsets) {
|
||||||
|
assert(0 == (faceOffset % 4));
|
||||||
|
auto faceEndOffset = faceOffset + faceImageDesc._faceSize;
|
||||||
|
assert(faceEndOffset <= storageSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& faceImage : ktxFile->_images) {
|
||||||
|
for (const ktx::Byte* faceBytes : faceImage._faceBytes) {
|
||||||
|
assert(0 == (reinterpret_cast<size_t>(faceBytes) % 4));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "main.moc"
|
#include "main.moc"
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue