diff --git a/COPYRIGHT.txt b/COPYRIGHT.txt index f884c690fa4e..aa98d69ca4d3 100644 --- a/COPYRIGHT.txt +++ b/COPYRIGHT.txt @@ -256,6 +256,12 @@ Comment: jpeg-compressor Copyright: 2012, Rich Geldreich License: public-domain or Apache-2.0 +Files: ./thirdparty/libktx/ +Comment: KTX +Copyright: 2013-2020, Mark Callow + 2010-2020 The Khronos Group, Inc. +License: Apache-2.0 + Files: ./thirdparty/libogg/ Comment: OggVorbis Copyright: 2002, Xiph.org Foundation diff --git a/core/io/image.cpp b/core/io/image.cpp index a5fea09113f1..3ca39f98c052 100644 --- a/core/io/image.cpp +++ b/core/io/image.cpp @@ -3018,6 +3018,7 @@ ImageMemLoadFunc Image::_tga_mem_loader_func = nullptr; ImageMemLoadFunc Image::_bmp_mem_loader_func = nullptr; ScalableImageMemLoadFunc Image::_svg_scalable_mem_loader_func = nullptr; ImageMemLoadFunc Image::_dds_mem_loader_func = nullptr; +ImageMemLoadFunc Image::_ktx_mem_loader_func = nullptr; void (*Image::_image_compress_bc_func)(Image *, Image::UsedChannels) = nullptr; void (*Image::_image_compress_bptc_func)(Image *, Image::UsedChannels) = nullptr; @@ -3490,6 +3491,7 @@ void Image::_bind_methods() { ClassDB::bind_method(D_METHOD("load_tga_from_buffer", "buffer"), &Image::load_tga_from_buffer); ClassDB::bind_method(D_METHOD("load_bmp_from_buffer", "buffer"), &Image::load_bmp_from_buffer); ClassDB::bind_method(D_METHOD("load_dds_from_buffer", "buffer"), &Image::load_dds_from_buffer); + ClassDB::bind_method(D_METHOD("load_ktx_from_buffer", "buffer"), &Image::load_ktx_from_buffer); ClassDB::bind_method(D_METHOD("load_svg_from_buffer", "buffer", "scale"), &Image::load_svg_from_buffer, DEFVAL(1.0)); ClassDB::bind_method(D_METHOD("load_svg_from_string", "svg_str", "scale"), &Image::load_svg_from_string, DEFVAL(1.0)); @@ -3873,6 +3875,14 @@ Error Image::load_dds_from_buffer(const Vector &p_array) { return _load_from_buffer(p_array, _dds_mem_loader_func); } +Error Image::load_ktx_from_buffer(const Vector &p_array) { + ERR_FAIL_NULL_V_MSG( + _ktx_mem_loader_func, + ERR_UNAVAILABLE, + "The KTX module isn't enabled. Recompile the Godot editor or export template binary with the `module_ktx_enabled=yes` SCons option."); + return _load_from_buffer(p_array, _ktx_mem_loader_func); +} + void Image::convert_rg_to_ra_rgba8() { ERR_FAIL_COND(format != FORMAT_RGBA8); ERR_FAIL_COND(!data.size()); diff --git a/core/io/image.h b/core/io/image.h index f68543ba2469..cb7c6bff5296 100644 --- a/core/io/image.h +++ b/core/io/image.h @@ -151,6 +151,7 @@ class Image : public Resource { static ImageMemLoadFunc _bmp_mem_loader_func; static ScalableImageMemLoadFunc _svg_scalable_mem_loader_func; static ImageMemLoadFunc _dds_mem_loader_func; + static ImageMemLoadFunc _ktx_mem_loader_func; static void (*_image_compress_bc_func)(Image *, UsedChannels p_channels); static void (*_image_compress_bptc_func)(Image *, UsedChannels p_channels); @@ -404,6 +405,7 @@ class Image : public Resource { Error load_tga_from_buffer(const Vector &p_array); Error load_bmp_from_buffer(const Vector &p_array); Error load_dds_from_buffer(const Vector &p_array); + Error load_ktx_from_buffer(const Vector &p_array); Error load_svg_from_buffer(const Vector &p_array, float scale = 1.0); Error load_svg_from_string(const String &p_svg_str, float scale = 1.0); diff --git a/doc/classes/Image.xml b/doc/classes/Image.xml index 14869909959b..6451062fc552 100644 --- a/doc/classes/Image.xml +++ b/doc/classes/Image.xml @@ -333,6 +333,13 @@ Loads an image from the binary contents of a JPEG file. + + + + + Loads an image from the binary contents of a KTX file. + + diff --git a/modules/gltf/extensions/gltf_document_extension_texture_ktx.cpp b/modules/gltf/extensions/gltf_document_extension_texture_ktx.cpp new file mode 100644 index 000000000000..ca61a24201a5 --- /dev/null +++ b/modules/gltf/extensions/gltf_document_extension_texture_ktx.cpp @@ -0,0 +1,66 @@ +/**************************************************************************/ +/* gltf_document_extension_texture_ktx.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#include "gltf_document_extension_texture_ktx.h" + +// Import process. +Error GLTFDocumentExtensionTextureKTX::import_preflight(Ref p_state, Vector p_extensions) { + if (!p_extensions.has("KHR_texture_basisu")) { + return ERR_SKIP; + } + return OK; +} + +Vector GLTFDocumentExtensionTextureKTX::get_supported_extensions() { + Vector ret; + ret.push_back("KHR_texture_basisu"); + return ret; +} + +Error GLTFDocumentExtensionTextureKTX::parse_image_data(Ref p_state, const PackedByteArray &p_image_data, const String &p_mime_type, Ref r_image) { + if (p_mime_type == "image/ktx2") { + return r_image->load_ktx_from_buffer(p_image_data); + } + return OK; +} + +Error GLTFDocumentExtensionTextureKTX::parse_texture_json(Ref p_state, const Dictionary &p_texture_json, Ref r_gltf_texture) { + if (!p_texture_json.has("extensions")) { + return OK; + } + const Dictionary &extensions = p_texture_json["extensions"]; + if (!extensions.has("KHR_texture_basisu")) { + return OK; + } + const Dictionary &texture_ktx = extensions["KHR_texture_basisu"]; + ERR_FAIL_COND_V(!texture_ktx.has("source"), ERR_PARSE_ERROR); + r_gltf_texture->set_src_image(texture_ktx["source"]); + return OK; +} diff --git a/modules/gltf/extensions/gltf_document_extension_texture_ktx.h b/modules/gltf/extensions/gltf_document_extension_texture_ktx.h new file mode 100644 index 000000000000..e4cb38a0441e --- /dev/null +++ b/modules/gltf/extensions/gltf_document_extension_texture_ktx.h @@ -0,0 +1,47 @@ +/**************************************************************************/ +/* gltf_document_extension_texture_ktx.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#ifndef GLTF_DOCUMENT_EXTENSION_TEXTURE_KTX_H +#define GLTF_DOCUMENT_EXTENSION_TEXTURE_KTX_H + +#include "gltf_document_extension.h" + +class GLTFDocumentExtensionTextureKTX : public GLTFDocumentExtension { + GDCLASS(GLTFDocumentExtensionTextureKTX, GLTFDocumentExtension); + +public: + // Import process. + Error import_preflight(Ref p_state, Vector p_extensions) override; + Vector get_supported_extensions() override; + Error parse_image_data(Ref p_state, const PackedByteArray &p_image_data, const String &p_mime_type, Ref r_image) override; + Error parse_texture_json(Ref p_state, const Dictionary &p_texture_json, Ref r_gltf_texture) override; +}; + +#endif // GLTF_DOCUMENT_EXTENSION_TEXTURE_KTX_H diff --git a/modules/gltf/register_types.cpp b/modules/gltf/register_types.cpp index 1788ffac3aed..c56ad6aeddc5 100644 --- a/modules/gltf/register_types.cpp +++ b/modules/gltf/register_types.cpp @@ -31,6 +31,7 @@ #include "register_types.h" #include "extensions/gltf_document_extension_convert_importer_mesh.h" +#include "extensions/gltf_document_extension_texture_ktx.h" #include "extensions/gltf_document_extension_texture_webp.h" #include "extensions/gltf_spec_gloss.h" #include "extensions/physics/gltf_document_extension_physics.h" @@ -133,6 +134,7 @@ void initialize_gltf_module(ModuleInitializationLevel p_level) { GDREGISTER_CLASS(GLTFTextureSampler); // Register GLTFDocumentExtension classes with GLTFDocument. GLTF_REGISTER_DOCUMENT_EXTENSION(GLTFDocumentExtensionPhysics); + GLTF_REGISTER_DOCUMENT_EXTENSION(GLTFDocumentExtensionTextureKTX); GLTF_REGISTER_DOCUMENT_EXTENSION(GLTFDocumentExtensionTextureWebP); bool is_editor = ::Engine::get_singleton()->is_editor_hint(); if (!is_editor) { diff --git a/modules/ktx/SCsub b/modules/ktx/SCsub new file mode 100644 index 000000000000..9e4531370175 --- /dev/null +++ b/modules/ktx/SCsub @@ -0,0 +1,60 @@ +#!/usr/bin/env python + +Import("env") +Import("env_modules") + +env_ktx = env_modules.Clone() + +# libktx thirdparty source files + +thirdparty_obj = [] + +thirdparty_dir = "#thirdparty/libktx/" +thirdparty_sources = [ + "lib/checkheader.c", + "lib/filestream.c", + "lib/hashlist.c", + "lib/memstream.c", + "lib/swap.c", + "lib/texture.c", + "lib/texture1.c", + "lib/texture2.c", + "lib/dfdutils/createdfd.c", + "lib/dfdutils/colourspaces.c", + "lib/dfdutils/interpretdfd.c", + "lib/dfdutils/printdfd.c", + "lib/dfdutils/queries.c", + "lib/dfdutils/vk2dfd.c", +] +thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources] + +env_ktx.Prepend(CPPPATH=[thirdparty_dir + "include"]) +env_ktx.Prepend(CPPPATH=[thirdparty_dir + "utils"]) +env_ktx.Prepend(CPPPATH=[thirdparty_dir + "lib"]) +env_ktx.Prepend(CPPPATH=[thirdparty_dir + "other_include"]) + +if env["module_basis_universal_enabled"]: + thirdparty_sources += [thirdparty_dir + "lib/basis_transcode.cpp"] + env_ktx.Prepend(CPPPATH=["#thirdparty/basis_universal"]) + +if env["vulkan"]: + env_ktx.Prepend(CPPPATH=["#thirdparty/vulkan/include"]) +else: + # Falls back on bundled `vkformat_enum.h`. + env_ktx.Append(CPPDEFINES=["LIBKTX"]) + +env_ktx.Append(CPPDEFINES=[("KHRONOS_STATIC", 1)]) + +env_thirdparty = env_ktx.Clone() +env_thirdparty.disable_warnings() +env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources) +env.modules_sources += thirdparty_obj + +# Godot source files +module_obj = [] + +env_ktx.add_source_files(module_obj, "*.cpp") +env.modules_sources += module_obj + +# Needed to force rebuilding the module files when the thirdparty library is updated. +env.Depends(module_obj, thirdparty_obj) diff --git a/modules/ktx/config.py b/modules/ktx/config.py new file mode 100644 index 000000000000..d22f9454ed25 --- /dev/null +++ b/modules/ktx/config.py @@ -0,0 +1,6 @@ +def can_build(env, platform): + return True + + +def configure(env): + pass diff --git a/modules/ktx/register_types.cpp b/modules/ktx/register_types.cpp new file mode 100644 index 000000000000..1d48e05a909d --- /dev/null +++ b/modules/ktx/register_types.cpp @@ -0,0 +1,53 @@ +/**************************************************************************/ +/* register_types.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#include "register_types.h" + +#include "texture_loader_ktx.h" + +static Ref resource_loader_ktx; + +void initialize_ktx_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { + return; + } + + resource_loader_ktx.instantiate(); + ResourceLoader::add_resource_format_loader(resource_loader_ktx); +} + +void uninitialize_ktx_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { + return; + } + + ResourceLoader::remove_resource_format_loader(resource_loader_ktx); + resource_loader_ktx.unref(); +} diff --git a/modules/ktx/register_types.h b/modules/ktx/register_types.h new file mode 100644 index 000000000000..a50dc48b409d --- /dev/null +++ b/modules/ktx/register_types.h @@ -0,0 +1,39 @@ +/**************************************************************************/ +/* register_types.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#ifndef KTX_REGISTER_TYPES_H +#define KTX_REGISTER_TYPES_H + +#include "modules/register_module_types.h" + +void initialize_ktx_module(ModuleInitializationLevel p_level); +void uninitialize_ktx_module(ModuleInitializationLevel p_level); + +#endif // KTX_REGISTER_TYPES_H diff --git a/modules/ktx/texture_loader_ktx.cpp b/modules/ktx/texture_loader_ktx.cpp new file mode 100644 index 000000000000..155ed56bd089 --- /dev/null +++ b/modules/ktx/texture_loader_ktx.cpp @@ -0,0 +1,562 @@ +/**************************************************************************/ +/* texture_loader_ktx.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#include "texture_loader_ktx.h" + +#include "core/io/file_access.h" +#include "core/io/file_access_memory.h" +#include "scene/resources/image_texture.h" + +#include +#include + +KTX_error_code ktx_read(ktxStream *stream, void *dst, const ktx_size_t count) { + Ref *f = reinterpret_cast *>(stream->data.custom_ptr.address); + (*f)->get_buffer(reinterpret_cast(dst), count); + return KTX_SUCCESS; +} + +KTX_error_code ktx_skip(ktxStream *stream, const ktx_size_t count) { + Ref *f = reinterpret_cast *>(stream->data.custom_ptr.address); + for (ktx_size_t i = 0; i < count; ++i) { + (*f)->get_8(); + } + return KTX_SUCCESS; +} + +KTX_error_code ktx_write(ktxStream *stream, const void *src, const ktx_size_t size, const ktx_size_t count) { + Ref *f = reinterpret_cast *>(stream->data.custom_ptr.address); + (*f)->store_buffer(reinterpret_cast(src), size * count); + return KTX_SUCCESS; +} + +KTX_error_code ktx_getpos(ktxStream *stream, ktx_off_t *const offset) { + Ref *f = reinterpret_cast *>(stream->data.custom_ptr.address); + *offset = (*f)->get_position(); + return KTX_SUCCESS; +} + +KTX_error_code ktx_setpos(ktxStream *stream, const ktx_off_t offset) { + Ref *f = reinterpret_cast *>(stream->data.custom_ptr.address); + (*f)->seek(offset); + return KTX_SUCCESS; +} + +KTX_error_code ktx_getsize(ktxStream *stream, ktx_size_t *const size) { + Ref *f = reinterpret_cast *>(stream->data.custom_ptr.address); + *size = (*f)->get_length(); + return KTX_SUCCESS; +} + +void ktx_destruct(ktxStream *stream) { + (void)stream; +} + +static Ref load_from_file_access(Ref f, Error *r_error) { + ktxStream ktx_stream; + ktx_stream.read = ktx_read; + ktx_stream.skip = ktx_skip; + ktx_stream.write = ktx_write; + ktx_stream.getpos = ktx_getpos; + ktx_stream.setpos = ktx_setpos; + ktx_stream.getsize = ktx_getsize; + ktx_stream.destruct = ktx_destruct; + ktx_stream.type = eStreamTypeCustom; + ktx_stream.data.custom_ptr.address = &f; + ktx_stream.data.custom_ptr.allocatorAddress = NULL; + ktx_stream.data.custom_ptr.size = 0; + ktx_stream.readpos = 0; + ktx_stream.closeOnDestruct = false; + ktxTexture *ktx_texture; + KTX_error_code result = ktxTexture_CreateFromStream(&ktx_stream, + KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT, + &ktx_texture); + if (result != KTX_SUCCESS) { + ERR_FAIL_V_MSG(Ref(), "Invalid or unsupported KTX texture file."); + } + + if (ktx_texture->numDimensions != 2) { + ktxTexture_Destroy(ktx_texture); + ERR_FAIL_V_MSG(Ref(), "Unsupported non-2D KTX texture file."); + } + + if (ktx_texture->isCubemap || ktx_texture->numFaces != 1) { + ktxTexture_Destroy(ktx_texture); + ERR_FAIL_V_MSG(Ref(), "Unsupported cube map KTX texture file."); + } + + if (ktx_texture->isArray) { + ktxTexture_Destroy(ktx_texture); + ERR_FAIL_V_MSG(Ref(), "Unsupported array KTX texture file."); + } + + uint32_t width = ktx_texture->baseWidth; + uint32_t height = ktx_texture->baseHeight; + uint32_t mipmaps = ktx_texture->numLevels; + Image::Format format; + bool srgb = false; + + switch (ktx_texture->classId) { + case ktxTexture1_c: + switch (((ktxTexture1 *)ktx_texture)->glInternalformat) { + case GL_LUMINANCE: + format = Image::FORMAT_L8; + break; + case GL_LUMINANCE_ALPHA: + format = Image::FORMAT_LA8; + break; + case GL_SRGB8: + format = Image::FORMAT_RGB8; + srgb = true; + break; + case GL_SRGB8_ALPHA8: + format = Image::FORMAT_RGBA8; + srgb = true; + break; + case GL_R8: + case GL_R8UI: + format = Image::FORMAT_R8; + break; + case GL_RG8: + format = Image::FORMAT_RG8; + break; + case GL_RGB8: + format = Image::FORMAT_RGB8; + break; + case GL_RGBA8: + format = Image::FORMAT_RGBA8; + break; + case GL_RGBA4: + format = Image::FORMAT_RGBA4444; + break; + case GL_RGB565: + format = Image::FORMAT_RGB565; + break; + case GL_R32F: + format = Image::FORMAT_RF; + break; + case GL_RG32F: + format = Image::FORMAT_RGF; + break; + case GL_RGB32F: + format = Image::FORMAT_RGBF; + break; + case GL_RGBA32F: + format = Image::FORMAT_RGBAF; + break; + case GL_R16F: + format = Image::FORMAT_RH; + break; + case GL_RG16F: + format = Image::FORMAT_RGH; + break; + case GL_RGB16F: + format = Image::FORMAT_RGBH; + break; + case GL_RGBA16F: + format = Image::FORMAT_RGBAH; + break; + case GL_RGB9_E5: + format = Image::FORMAT_RGBE9995; + break; + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: + format = Image::FORMAT_DXT1; + break; + case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: + format = Image::FORMAT_DXT3; + break; + case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: + format = Image::FORMAT_DXT5; + break; + case GL_COMPRESSED_RED_RGTC1: + format = Image::FORMAT_RGTC_R; + break; + case GL_COMPRESSED_RG_RGTC2: + format = Image::FORMAT_RGTC_RG; + break; + case GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT: + format = Image::FORMAT_BPTC_RGBFU; + break; + case GL_COMPRESSED_RGBA_BPTC_UNORM: + format = Image::FORMAT_BPTC_RGBA; + break; +#if 0 // TODO: ETC compression is bogus. + case GL_ETC1_RGB8_OES: + format = Image::FORMAT_ETC; + break; + case GL_COMPRESSED_R11_EAC: + format = Image::FORMAT_ETC2_R11; + break; + case GL_COMPRESSED_SIGNED_R11_EAC: + format = Image::FORMAT_ETC2_R11S; + break; + case GL_COMPRESSED_RG11_EAC: + format = Image::FORMAT_ETC2_RG11; + break; + case GL_COMPRESSED_SIGNED_RG11_EAC: + format = Image::FORMAT_ETC2_RG11S; + break; + case GL_COMPRESSED_RGB8_ETC2: + format = Image::FORMAT_ETC2_RGB8; + break; + case GL_COMPRESSED_RGBA8_ETC2_EAC: + format = Image::FORMAT_ETC2_RGBA8; + break; + case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2: + format = Image::FORMAT_ETC2_RGB8A1; + break; +#endif + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR: + format = Image::FORMAT_ASTC_4x4; + break; + case GL_COMPRESSED_RGBA_ASTC_4x4_KHR: + format = Image::FORMAT_ASTC_4x4_HDR; + break; + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR: + format = Image::FORMAT_ASTC_8x8; + break; + case GL_COMPRESSED_RGBA_ASTC_8x8_KHR: + format = Image::FORMAT_ASTC_8x8_HDR; + break; + default: + ktxTexture_Destroy(ktx_texture); + ERR_FAIL_V_MSG(Ref(), "Unsupported format " + itos(((ktxTexture1 *)ktx_texture)->glInternalformat) + " of KTX1 texture file."); + } + break; + case ktxTexture2_c: { + ktxTexture2 *ktx_texture2 = reinterpret_cast(ktx_texture); + if (ktx_texture2->vkFormat == VK_FORMAT_UNDEFINED) { + if (!ktxTexture2_NeedsTranscoding(ktx_texture2)) { + ktxTexture_Destroy(ktx_texture); + ERR_FAIL_V_MSG(Ref(), "Invalid VK_FORMAT_UNDEFINED of KTX2 texture file."); + } + ktx_transcode_fmt_e ktxfmt; + switch (ktxTexture2_GetNumComponents(ktx_texture2)) { + case 1: { + if (ktxTexture2_GetOETF_e(ktx_texture2) == KHR_DF_TRANSFER_SRGB) { // TODO srgb native support + ktxfmt = KTX_TTF_RGBA32; + } else if (RS::get_singleton()->has_os_feature("rgtc")) { + ktxfmt = KTX_TTF_BC4_R; + } else { + ktxfmt = KTX_TTF_RGBA32; + } + break; + } + case 2: { + if (ktxTexture2_GetOETF_e(ktx_texture2) == KHR_DF_TRANSFER_SRGB) { // TODO srgb native support + ktxfmt = KTX_TTF_RGBA32; + } else if (RS::get_singleton()->has_os_feature("rgtc")) { + ktxfmt = KTX_TTF_BC5_RG; + } else { + ktxfmt = KTX_TTF_RGBA32; + } + break; + } + case 3: { + if (ktxTexture2_GetOETF_e(ktx_texture2) == KHR_DF_TRANSFER_SRGB) { // TODO: srgb native support + ktxfmt = KTX_TTF_RGBA32; + } else if (RS::get_singleton()->has_os_feature("bptc")) { + ktxfmt = KTX_TTF_BC7_RGBA; + } else if (RS::get_singleton()->has_os_feature("s3tc")) { + ktxfmt = KTX_TTF_BC1_RGB; + } else if (RS::get_singleton()->has_os_feature("etc")) { + ktxfmt = KTX_TTF_ETC1_RGB; + } else { + ktxfmt = KTX_TTF_RGBA32; + } + break; + } + case 4: { + if (ktxTexture2_GetOETF_e(ktx_texture2) == KHR_DF_TRANSFER_SRGB) { // TODO srgb native support + ktxfmt = KTX_TTF_RGBA32; + } else if (RS::get_singleton()->has_os_feature("astc")) { + ktxfmt = KTX_TTF_ASTC_4x4_RGBA; + } else if (RS::get_singleton()->has_os_feature("bptc")) { + ktxfmt = KTX_TTF_BC7_RGBA; + } else if (RS::get_singleton()->has_os_feature("s3tc")) { + ktxfmt = KTX_TTF_BC3_RGBA; + } else if (RS::get_singleton()->has_os_feature("etc2")) { + ktxfmt = KTX_TTF_ETC2_RGBA; + } else { + ktxfmt = KTX_TTF_RGBA32; + } + break; + } + default: { + ktxTexture_Destroy(ktx_texture); + ERR_FAIL_V_MSG(Ref(), "Invalid components of KTX2 texture file."); + } + } + result = ktxTexture2_TranscodeBasis(ktx_texture2, ktxfmt, 0); + if (result != KTX_SUCCESS) { + ktxTexture_Destroy(ktx_texture); + ERR_FAIL_V_MSG(Ref(), "Failed to transcode KTX2 texture file."); + } + } + switch (ktx_texture2->vkFormat) { + case VK_FORMAT_R8_UNORM: + format = Image::FORMAT_L8; + break; + case VK_FORMAT_R8G8_UNORM: + format = Image::FORMAT_LA8; + break; + case VK_FORMAT_R8G8B8_SRGB: + format = Image::FORMAT_RGB8; + srgb = true; + break; + case VK_FORMAT_R8G8B8A8_SRGB: + format = Image::FORMAT_RGBA8; + srgb = true; + break; + case VK_FORMAT_R8_UINT: + format = Image::FORMAT_R8; + break; + case VK_FORMAT_R8G8_UINT: + format = Image::FORMAT_RG8; + break; + case VK_FORMAT_R8G8B8_UINT: + format = Image::FORMAT_RGB8; + break; + case VK_FORMAT_R8G8B8A8_UINT: + format = Image::FORMAT_RGBA8; + break; + case VK_FORMAT_R4G4B4A4_UNORM_PACK16: + format = Image::FORMAT_RGBA4444; + break; + case VK_FORMAT_R5G6B5_UNORM_PACK16: + format = Image::FORMAT_RGB565; + break; + case VK_FORMAT_R32_SFLOAT: + format = Image::FORMAT_RF; + break; + case VK_FORMAT_R32G32_SFLOAT: + format = Image::FORMAT_RGF; + break; + case VK_FORMAT_R32G32B32_SFLOAT: + format = Image::FORMAT_RGBF; + break; + case VK_FORMAT_R32G32B32A32_SFLOAT: + format = Image::FORMAT_RGBAF; + break; + case VK_FORMAT_R16_SFLOAT: + format = Image::FORMAT_RH; + break; + case VK_FORMAT_R16G16_SFLOAT: + format = Image::FORMAT_RGH; + break; + case VK_FORMAT_R16G16B16_SFLOAT: + format = Image::FORMAT_RGBH; + break; + case VK_FORMAT_R16G16B16A16_SFLOAT: + format = Image::FORMAT_RGBAH; + break; + case VK_FORMAT_E5B9G9R9_UFLOAT_PACK32: + format = Image::FORMAT_RGBE9995; + break; + case VK_FORMAT_BC1_RGB_UNORM_BLOCK: + case VK_FORMAT_BC1_RGBA_UNORM_BLOCK: + format = Image::FORMAT_DXT1; + break; + case VK_FORMAT_BC2_UNORM_BLOCK: + format = Image::FORMAT_DXT3; + break; + case VK_FORMAT_BC3_UNORM_BLOCK: + format = Image::FORMAT_DXT5; + break; + case VK_FORMAT_BC4_UNORM_BLOCK: + format = Image::FORMAT_RGTC_R; + break; + case VK_FORMAT_BC5_UNORM_BLOCK: + format = Image::FORMAT_RGTC_RG; + break; + case VK_FORMAT_BC6H_UFLOAT_BLOCK: + format = Image::FORMAT_BPTC_RGBFU; + break; + case VK_FORMAT_BC6H_SFLOAT_BLOCK: + format = Image::FORMAT_BPTC_RGBF; + break; + case VK_FORMAT_BC7_UNORM_BLOCK: + format = Image::FORMAT_BPTC_RGBA; + break; +#if 0 // TODO: ETC compression is bogus. + case VK_FORMAT_EAC_R11_UNORM_BLOCK: + format = Image::FORMAT_ETC2_R11; + break; + case VK_FORMAT_EAC_R11_SNORM_BLOCK: + format = Image::FORMAT_ETC2_R11S; + break; + case VK_FORMAT_EAC_R11G11_UNORM_BLOCK: + format = Image::FORMAT_ETC2_RG11; + break; + case VK_FORMAT_EAC_R11G11_SNORM_BLOCK: + format = Image::FORMAT_ETC2_RG11S; + break; + case VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK: + format = Image::FORMAT_ETC2_RGB8; + break; + case VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK: + format = Image::FORMAT_ETC2_RGBA8; + break; + case VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK: + format = Image::FORMAT_ETC2_RGB8A1; + break; +#endif + case VK_FORMAT_ASTC_4x4_SRGB_BLOCK: + format = Image::FORMAT_ASTC_4x4; + break; + case VK_FORMAT_ASTC_4x4_UNORM_BLOCK: + format = Image::FORMAT_ASTC_4x4_HDR; + break; + case VK_FORMAT_ASTC_8x8_SRGB_BLOCK: + format = Image::FORMAT_ASTC_8x8; + break; + case VK_FORMAT_ASTC_8x8_UNORM_BLOCK: + format = Image::FORMAT_ASTC_8x8_HDR; + break; + default: + ktxTexture_Destroy(ktx_texture); + ERR_FAIL_V_MSG(Ref(), "Unsupported format " + itos(((ktxTexture2 *)ktx_texture)->vkFormat) + " of KTX2 texture file."); + break; + } + break; + } + default: + ktxTexture_Destroy(ktx_texture); + ERR_FAIL_V_MSG(Ref(), "Unsupported version KTX texture file."); + break; + } + + Vector src_data; + + // KTX use 4-bytes padding, don't use mipmaps if padding is effective + // TODO: unpad dynamically + int pixel_size = Image::get_format_pixel_size(format); + int pixel_rshift = Image::get_format_pixel_rshift(format); + int block = Image::get_format_block_size(format); + int minw, minh; + Image::get_format_min_pixel_size(format, minw, minh); + int w = width; + int h = height; + for (uint32_t i = 0; i < mipmaps; ++i) { + ktx_size_t mip_size = ktxTexture_GetImageSize(ktx_texture, i); + size_t bw = w % block != 0 ? w + (block - w % block) : w; + size_t bh = h % block != 0 ? h + (block - h % block) : h; + size_t s = bw * bh; + s *= pixel_size; + s >>= pixel_rshift; + if (mip_size != static_cast(s)) { + if (!i) { + ktxTexture_Destroy(ktx_texture); + ERR_FAIL_V_MSG(Ref(), "Unsupported padded KTX texture file."); + } + mipmaps = 1; + break; + } + w = MAX(minw, w >> 1); + h = MAX(minh, h >> 1); + } + + for (uint32_t i = 0; i < mipmaps; ++i) { + ktx_size_t mip_size = ktxTexture_GetImageSize(ktx_texture, i); + ktx_size_t offset; + if (ktxTexture_GetImageOffset(ktx_texture, i, 0, 0, &offset) != KTX_SUCCESS) { + ktxTexture_Destroy(ktx_texture); + ERR_FAIL_V_MSG(Ref(), "Invalid KTX texture file."); + } + int prev_size = src_data.size(); + src_data.resize(prev_size + mip_size); + memcpy(src_data.ptrw() + prev_size, ktxTexture_GetData(ktx_texture) + offset, mip_size); + } + + Ref img = memnew(Image(width, height, mipmaps - 1, format, src_data)); + if (srgb) { + img->srgb_to_linear(); + } + + if (r_error) { + *r_error = OK; + } + + ktxTexture_Destroy(ktx_texture); + return img; +} + +Ref ResourceFormatKTX::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) { + if (r_error) { + *r_error = ERR_CANT_OPEN; + } + + Error err; + Ref f = FileAccess::open(p_path, FileAccess::READ, &err); + if (f.is_null()) { + return Ref(); + } + + Ref fref(f); + if (r_error) { + *r_error = ERR_FILE_CORRUPT; + } + + ERR_FAIL_COND_V_MSG(err != OK, Ref(), "Unable to open KTX texture file '" + p_path + "'."); + Ref img = load_from_file_access(f, r_error); + Ref texture = ImageTexture::create_from_image(img); + return texture; +} + +static Ref _ktx_mem_loader_func(const uint8_t *p_ktx, int p_size) { + Ref f; + f.instantiate(); + f->open_custom(p_ktx, p_size); + Error err; + Ref img = load_from_file_access(f, &err); + ERR_FAIL_COND_V(err, Ref()); + return img; +} + +void ResourceFormatKTX::get_recognized_extensions(List *p_extensions) const { + p_extensions->push_back("ktx"); + p_extensions->push_back("ktx2"); +} + +bool ResourceFormatKTX::handles_type(const String &p_type) const { + return ClassDB::is_parent_class(p_type, "Texture2D"); +} + +String ResourceFormatKTX::get_resource_type(const String &p_path) const { + if (p_path.get_extension().to_lower() == "ktx" || p_path.get_extension().to_lower() == "ktx2") { + return "ImageTexture"; + } + return ""; +} + +ResourceFormatKTX::ResourceFormatKTX() { + Image::_ktx_mem_loader_func = _ktx_mem_loader_func; +} diff --git a/modules/ktx/texture_loader_ktx.h b/modules/ktx/texture_loader_ktx.h new file mode 100644 index 000000000000..0ea676be6b24 --- /dev/null +++ b/modules/ktx/texture_loader_ktx.h @@ -0,0 +1,48 @@ +/**************************************************************************/ +/* texture_loader_ktx.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#ifndef TEXTURE_LOADER_KTX_H +#define TEXTURE_LOADER_KTX_H + +#include "core/io/resource_loader.h" +#include "scene/resources/texture.h" + +class ResourceFormatKTX : public ResourceFormatLoader { +public: + virtual Ref load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE); + virtual void get_recognized_extensions(List *p_extensions) const; + virtual bool handles_type(const String &p_type) const; + virtual String get_resource_type(const String &p_path) const; + + virtual ~ResourceFormatKTX() {} + ResourceFormatKTX(); +}; + +#endif // TEXTURE_LOADER_KTX_H diff --git a/thirdparty/README.md b/thirdparty/README.md index 505350297121..ac2111389866 100644 --- a/thirdparty/README.md +++ b/thirdparty/README.md @@ -299,6 +299,25 @@ Files extracted from upstream source: - `jpge*.{c,h}` +## libktx + +- Upstream: https://github.com/KhronosGroup/KTX-Software +- Version: 4.1.0 (d7255fe73cd53b856731ceb9f2c279181d0dbbca, 2023) +- License: Apache-2.0 + +Files extracted from upstream source: + +- `LICENSE.md` +- `include/*` +- `lib/dfdutils/{LICENSES/Apache-2.0.txt,KHR,*.c,*.h,*.inl}` +- `lib/{basis_sgd.h,basis_transcode.cpp,checkheader.c,filestream.*,formatsize.h,gl_format.h,hashlist.c,ktxint.h,memstream.*,swap.c,texture*,uthash.h,vk_format.h,vkformat_enum.h` +- `utils/unused.h` +- `other_include/KHR/*` +- ifndef-protect NOMINMAX define in `lib/gl_format.h` (see godot.patch) +- remove `basisu/` prefix from `thirdparty/libktx/lib/basis_transcode.cpp` basisu includes (see godot.patch) +- comment `VK_FORMAT_ASTC_*x*x*_UNORM_BLOCK_EXT` cases in `lib/dfdutils/vk2dfd.inl` (see godot.patch) + + ## libogg - Upstream: https://www.xiph.org/ogg diff --git a/thirdparty/libktx/Apache-2.0.txt b/thirdparty/libktx/Apache-2.0.txt new file mode 100644 index 000000000000..4ed90b952240 --- /dev/null +++ b/thirdparty/libktx/Apache-2.0.txt @@ -0,0 +1,208 @@ +Apache License + +Version 2.0, January 2004 + +http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, +AND DISTRIBUTION + + 1. Definitions. + + + +"License" shall mean the terms and conditions for use, reproduction, and distribution +as defined by Sections 1 through 9 of this document. + + + +"Licensor" shall mean the copyright owner or entity authorized by the copyright +owner that is granting the License. + + + +"Legal Entity" shall mean the union of the acting entity and all other entities +that control, are controlled by, or are under common control with that entity. +For the purposes of this definition, "control" means (i) the power, direct +or indirect, to cause the direction or management of such entity, whether +by contract or otherwise, or (ii) ownership of fifty percent (50%) or more +of the outstanding shares, or (iii) beneficial ownership of such entity. + + + +"You" (or "Your") shall mean an individual or Legal Entity exercising permissions +granted by this License. + + + +"Source" form shall mean the preferred form for making modifications, including +but not limited to software source code, documentation source, and configuration +files. + + + +"Object" form shall mean any form resulting from mechanical transformation +or translation of a Source form, including but not limited to compiled object +code, generated documentation, and conversions to other media types. + + + +"Work" shall mean the work of authorship, whether in Source or Object form, +made available under the License, as indicated by a copyright notice that +is included in or attached to the work (an example is provided in the Appendix +below). + + + +"Derivative Works" shall mean any work, whether in Source or Object form, +that is based on (or derived from) the Work and for which the editorial revisions, +annotations, elaborations, or other modifications represent, as a whole, an +original work of authorship. For the purposes of this License, Derivative +Works shall not include works that remain separable from, or merely link (or +bind by name) to the interfaces of, the Work and Derivative Works thereof. + + + +"Contribution" shall mean any work of authorship, including the original version +of the Work and any modifications or additions to that Work or Derivative +Works thereof, that is intentionally submitted to Licensor for inclusion in +the Work by the copyright owner or by an individual or Legal Entity authorized +to submit on behalf of the copyright owner. For the purposes of this definition, +"submitted" means any form of electronic, verbal, or written communication +sent to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, and +issue tracking systems that are managed by, or on behalf of, the Licensor +for the purpose of discussing and improving the Work, but excluding communication +that is conspicuously marked or otherwise designated in writing by the copyright +owner as "Not a Contribution." + + + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf +of whom a Contribution has been received by Licensor and subsequently incorporated +within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of this +License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, +no-charge, royalty-free, irrevocable copyright license to reproduce, prepare +Derivative Works of, publicly display, publicly perform, sublicense, and distribute +the Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of this License, +each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, +no-charge, royalty-free, irrevocable (except as stated in this section) patent +license to make, have made, use, offer to sell, sell, import, and otherwise +transfer the Work, where such license applies only to those patent claims +licensable by such Contributor that are necessarily infringed by their Contribution(s) +alone or by combination of their Contribution(s) with the Work to which such +Contribution(s) was submitted. If You institute patent litigation against +any entity (including a cross-claim or counterclaim in a lawsuit) alleging +that the Work or a Contribution incorporated within the Work constitutes direct +or contributory patent infringement, then any patent licenses granted to You +under this License for that Work shall terminate as of the date such litigation +is filed. + +4. Redistribution. You may reproduce and distribute copies of the Work or +Derivative Works thereof in any medium, with or without modifications, and +in Source or Object form, provided that You meet the following conditions: + +(a) You must give any other recipients of the Work or Derivative Works a copy +of this License; and + +(b) You must cause any modified files to carry prominent notices stating that +You changed the files; and + +(c) You must retain, in the Source form of any Derivative Works that You distribute, +all copyright, patent, trademark, and attribution notices from the Source +form of the Work, excluding those notices that do not pertain to any part +of the Derivative Works; and + +(d) If the Work includes a "NOTICE" text file as part of its distribution, +then any Derivative Works that You distribute must include a readable copy +of the attribution notices contained within such NOTICE file, excluding those +notices that do not pertain to any part of the Derivative Works, in at least +one of the following places: within a NOTICE text file distributed as part +of the Derivative Works; within the Source form or documentation, if provided +along with the Derivative Works; or, within a display generated by the Derivative +Works, if and wherever such third-party notices normally appear. The contents +of the NOTICE file are for informational purposes only and do not modify the +License. You may add Your own attribution notices within Derivative Works +that You distribute, alongside or as an addendum to the NOTICE text from the +Work, provided that such additional attribution notices cannot be construed +as modifying the License. + +You may add Your own copyright statement to Your modifications and may provide +additional or different license terms and conditions for use, reproduction, +or distribution of Your modifications, or for any such Derivative Works as +a whole, provided Your use, reproduction, and distribution of the Work otherwise +complies with the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, any +Contribution intentionally submitted for inclusion in the Work by You to the +Licensor shall be under the terms and conditions of this License, without +any additional terms or conditions. Notwithstanding the above, nothing herein +shall supersede or modify the terms of any separate license agreement you +may have executed with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade names, +trademarks, service marks, or product names of the Licensor, except as required +for reasonable and customary use in describing the origin of the Work and +reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or agreed to +in writing, Licensor provides the Work (and each Contributor provides its +Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied, including, without limitation, any warranties +or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR +A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness +of using or redistributing the Work and assume any risks associated with Your +exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, whether +in tort (including negligence), contract, or otherwise, unless required by +applicable law (such as deliberate and grossly negligent acts) or agreed to +in writing, shall any Contributor be liable to You for damages, including +any direct, indirect, special, incidental, or consequential damages of any +character arising as a result of this License or out of the use or inability +to use the Work (including but not limited to damages for loss of goodwill, +work stoppage, computer failure or malfunction, or any and all other commercial +damages or losses), even if such Contributor has been advised of the possibility +of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing the Work +or Derivative Works thereof, You may choose to offer, and charge a fee for, +acceptance of support, warranty, indemnity, or other liability obligations +and/or rights consistent with this License. However, in accepting such obligations, +You may act only on Your own behalf and on Your sole responsibility, not on +behalf of any other Contributor, and only if You agree to indemnify, defend, +and hold each Contributor harmless for any liability incurred by, or claims +asserted against, such Contributor by reason of your accepting any such warranty +or additional liability. END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + +To apply the Apache License to your work, attach the following boilerplate +notice, with the fields enclosed by brackets "[]" replaced with your own identifying +information. (Don't include the brackets!) The text should be enclosed in +the appropriate comment syntax for the file format. We also recommend that +a file or class name and description of purpose be included on the same "printed +page" as the copyright notice for easier identification within third-party +archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); + +you may not use this file except in compliance with the License. + +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software + +distributed under the License is distributed on an "AS IS" BASIS, + +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + +See the License for the specific language governing permissions and + +limitations under the License. diff --git a/thirdparty/libktx/LICENSE.dfdutils.adoc b/thirdparty/libktx/LICENSE.dfdutils.adoc new file mode 100644 index 000000000000..f206249940cf --- /dev/null +++ b/thirdparty/libktx/LICENSE.dfdutils.adoc @@ -0,0 +1,10 @@ += LICENSE file for the KhronosGroup/dfdutils project + +Files in this repository fall under this license: + + * SPDX license identifier: "`Apache-2.0`" + ** Apache License 2.0 + +Full license text is available at: + + * Apache-2.0: https://opensource.org/licenses/Apache-2.0 diff --git a/thirdparty/libktx/LICENSE.md b/thirdparty/libktx/LICENSE.md new file mode 100644 index 000000000000..7b6d05fe4807 --- /dev/null +++ b/thirdparty/libktx/LICENSE.md @@ -0,0 +1,36 @@ +LICENSE file for the KhronosGroup/KTX-Software project {#license} +====================================================== + + + +Files unique to this repository generally fall under the Apache 2.0 license +with copyright holders including Mark Callow, the KTX-Software author; The +Khronos Group Inc., which has supported KTX development; and other +contributors to the KTX project. + +Because KTX-Software incorporates material and contributions from many other +projects, which often have their own licenses, there are many other licenses +in use in this repository. While there are many licenses in this repository, +with rare exceptions all are open source licenses that we believe to be +mutually compatible. + +The complete text of each of the licenses used in this repository is found +in LICENSES/*.txt . Additionally, we have updated the repository to pass the +REUSE compliance checker tool (see https://reuse.software/). REUSE verifies +that every file in a git repository either incorporates a license, or that +the license is present in auxiliary files such as .reuse/dep5 . To obtain a +bill of materials for the repository identifying the license for each file, +install the REUSE tool and run + + reuse spdx + +inside the repository. + +## Special Cases + +The file lib/etcdec.cxx is not open source. It is made available under the +terms of an Ericsson license, found in the file itself. diff --git a/thirdparty/libktx/godot.patch b/thirdparty/libktx/godot.patch new file mode 100644 index 000000000000..8a492ee27ddf --- /dev/null +++ b/thirdparty/libktx/godot.patch @@ -0,0 +1,45 @@ +--- thirdparty/libktx/lib/gl_format.h ++++ thirdparty/libktx/lib/gl_format.h +@@ -92,7 +92,9 @@ + #include "vkformat_enum.h" + + #if defined(_WIN32) && !defined(__MINGW32__) ++#ifndef NOMINMAX + #define NOMINMAX ++#endif + #ifndef __cplusplus + #undef inline + #define inline __inline +--- thirdparty/libktx/lib/basis_transcode.cpp ++++ thirdparty/libktx/lib/basis_transcode.cpp +@@ -29,9 +29,9 @@ + #include "vkformat_enum.h" + #include "vk_format.h" + #include "basis_sgd.h" +-#include "basisu/transcoder/basisu_file_headers.h" +-#include "basisu/transcoder/basisu_transcoder.h" +-#include "basisu/transcoder/basisu_transcoder_internal.h" ++#include "transcoder/basisu_file_headers.h" ++#include "transcoder/basisu_transcoder.h" ++#include "transcoder/basisu_transcoder_internal.h" + + #undef DECLARE_PRIVATE + #undef DECLARE_PROTECTED +--- thirdparty/libktx/lib/dfdutils/vk2dfd.inl ++++ thirdparty/libktx/lib/dfdutils/vk2dfd.inl +@@ -298,6 +298,7 @@ + case VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK_EXT: return createDFDCompressed(c_ASTC, 10, 10, 1, s_SFLOAT); + case VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK_EXT: return createDFDCompressed(c_ASTC, 12, 10, 1, s_SFLOAT); + case VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK_EXT: return createDFDCompressed(c_ASTC, 12, 12, 1, s_SFLOAT); ++#if 0 + case VK_FORMAT_ASTC_3x3x3_UNORM_BLOCK_EXT: return createDFDCompressed(c_ASTC, 3, 3, 3, s_UNORM); + case VK_FORMAT_ASTC_3x3x3_SRGB_BLOCK_EXT: return createDFDCompressed(c_ASTC, 3, 3, 3, s_SRGB); + case VK_FORMAT_ASTC_3x3x3_SFLOAT_BLOCK_EXT: return createDFDCompressed(c_ASTC, 3, 3, 3, s_SFLOAT); +@@ -328,6 +329,7 @@ + case VK_FORMAT_ASTC_6x6x6_UNORM_BLOCK_EXT: return createDFDCompressed(c_ASTC, 6, 6, 6, s_UNORM); + case VK_FORMAT_ASTC_6x6x6_SRGB_BLOCK_EXT: return createDFDCompressed(c_ASTC, 6, 6, 6, s_SRGB); + case VK_FORMAT_ASTC_6x6x6_SFLOAT_BLOCK_EXT: return createDFDCompressed(c_ASTC, 6, 6, 6, s_SFLOAT); ++#endif + case VK_FORMAT_A4R4G4B4_UNORM_PACK16_EXT: { + int channels[] = {2,1,0,3}; int bits[] = {4,4,4,4}; + return createDFDPacked(0, 4, bits, channels, s_UNORM); diff --git a/thirdparty/libktx/include/KHR/khr_df.h b/thirdparty/libktx/include/KHR/khr_df.h new file mode 100644 index 000000000000..bbd0d14bd90c --- /dev/null +++ b/thirdparty/libktx/include/KHR/khr_df.h @@ -0,0 +1,619 @@ +/* The Khronos Data Format Specification (version 1.3) */ +/* +** Copyright 2015-2020 The Khronos Group Inc. +** SPDX-License-Identifier: Apache-2.0 +*/ + +/* This header defines a structure that can describe the layout of image + formats in memory. This means that the data format is transparent to + the application, and the expectation is that this should be used when + the layout is defined external to the API. Many Khronos APIs deliberately + keep the internal layout of images opaque, to allow proprietary layouts + and optimisations. This structure is not appropriate for describing + opaque layouts. */ + +/* We stick to standard C89 constructs for simplicity and portability. */ + +#ifndef _KHR_DATA_FORMAT_H_ +#define _KHR_DATA_FORMAT_H_ + +/* Accessors */ +typedef enum _khr_word_e { + KHR_DF_WORD_VENDORID = 0U, + KHR_DF_WORD_DESCRIPTORTYPE = 0U, + KHR_DF_WORD_VERSIONNUMBER = 1U, + KHR_DF_WORD_DESCRIPTORBLOCKSIZE = 1U, + KHR_DF_WORD_MODEL = 2U, + KHR_DF_WORD_PRIMARIES = 2U, + KHR_DF_WORD_TRANSFER = 2U, + KHR_DF_WORD_FLAGS = 2U, + KHR_DF_WORD_TEXELBLOCKDIMENSION0 = 3U, + KHR_DF_WORD_TEXELBLOCKDIMENSION1 = 3U, + KHR_DF_WORD_TEXELBLOCKDIMENSION2 = 3U, + KHR_DF_WORD_TEXELBLOCKDIMENSION3 = 3U, + KHR_DF_WORD_BYTESPLANE0 = 4U, + KHR_DF_WORD_BYTESPLANE1 = 4U, + KHR_DF_WORD_BYTESPLANE2 = 4U, + KHR_DF_WORD_BYTESPLANE3 = 4U, + KHR_DF_WORD_BYTESPLANE4 = 5U, + KHR_DF_WORD_BYTESPLANE5 = 5U, + KHR_DF_WORD_BYTESPLANE6 = 5U, + KHR_DF_WORD_BYTESPLANE7 = 5U, + KHR_DF_WORD_SAMPLESTART = 6U, + KHR_DF_WORD_SAMPLEWORDS = 4U +} khr_df_word_e; + +typedef enum _khr_df_shift_e { + KHR_DF_SHIFT_VENDORID = 0U, + KHR_DF_SHIFT_DESCRIPTORTYPE = 17U, + KHR_DF_SHIFT_VERSIONNUMBER = 0U, + KHR_DF_SHIFT_DESCRIPTORBLOCKSIZE = 16U, + KHR_DF_SHIFT_MODEL = 0U, + KHR_DF_SHIFT_PRIMARIES = 8U, + KHR_DF_SHIFT_TRANSFER = 16U, + KHR_DF_SHIFT_FLAGS = 24U, + KHR_DF_SHIFT_TEXELBLOCKDIMENSION0 = 0U, + KHR_DF_SHIFT_TEXELBLOCKDIMENSION1 = 8U, + KHR_DF_SHIFT_TEXELBLOCKDIMENSION2 = 16U, + KHR_DF_SHIFT_TEXELBLOCKDIMENSION3 = 24U, + KHR_DF_SHIFT_BYTESPLANE0 = 0U, + KHR_DF_SHIFT_BYTESPLANE1 = 8U, + KHR_DF_SHIFT_BYTESPLANE2 = 16U, + KHR_DF_SHIFT_BYTESPLANE3 = 24U, + KHR_DF_SHIFT_BYTESPLANE4 = 0U, + KHR_DF_SHIFT_BYTESPLANE5 = 8U, + KHR_DF_SHIFT_BYTESPLANE6 = 16U, + KHR_DF_SHIFT_BYTESPLANE7 = 24U +} khr_df_shift_e; + +typedef enum _khr_df_mask_e { + KHR_DF_MASK_VENDORID = 0x1FFFFU, + KHR_DF_MASK_DESCRIPTORTYPE = 0x7FFFU, + KHR_DF_MASK_VERSIONNUMBER = 0xFFFFU, + KHR_DF_MASK_DESCRIPTORBLOCKSIZE = 0xFFFFU, + KHR_DF_MASK_MODEL = 0xFFU, + KHR_DF_MASK_PRIMARIES = 0xFFU, + KHR_DF_MASK_TRANSFER = 0xFFU, + KHR_DF_MASK_FLAGS = 0xFFU, + KHR_DF_MASK_TEXELBLOCKDIMENSION0 = 0xFFU, + KHR_DF_MASK_TEXELBLOCKDIMENSION1 = 0xFFU, + KHR_DF_MASK_TEXELBLOCKDIMENSION2 = 0xFFU, + KHR_DF_MASK_TEXELBLOCKDIMENSION3 = 0xFFU, + KHR_DF_MASK_BYTESPLANE0 = 0xFFU, + KHR_DF_MASK_BYTESPLANE1 = 0xFFU, + KHR_DF_MASK_BYTESPLANE2 = 0xFFU, + KHR_DF_MASK_BYTESPLANE3 = 0xFFU, + KHR_DF_MASK_BYTESPLANE4 = 0xFFU, + KHR_DF_MASK_BYTESPLANE5 = 0xFFU, + KHR_DF_MASK_BYTESPLANE6 = 0xFFU, + KHR_DF_MASK_BYTESPLANE7 = 0xFFU +} khr_df_mask_e; + +/* Helper macro: + Extract field X from basic descriptor block BDB */ +#define KHR_DFDVAL(BDB, X) \ + (((BDB)[KHR_DF_WORD_ ## X] >> (KHR_DF_SHIFT_ ## X)) \ + & (KHR_DF_MASK_ ## X)) + +/* Helper macro: + Set field X of basic descriptor block BDB */ +#define KHR_DFDSETVAL(BDB, X, val) \ + ((BDB)[KHR_DF_WORD_ ## X] = \ + ((BDB)[KHR_DF_WORD_ ## X] & \ + ~((KHR_DF_MASK_ ## X) << (KHR_DF_SHIFT_ ## X))) | \ + (((val) & (KHR_DF_MASK_ ## X)) << (KHR_DF_SHIFT_ ## X))) + +/* Offsets relative to the start of a sample */ +typedef enum _khr_df_sampleword_e { + KHR_DF_SAMPLEWORD_BITOFFSET = 0U, + KHR_DF_SAMPLEWORD_BITLENGTH = 0U, + KHR_DF_SAMPLEWORD_CHANNELID = 0U, + KHR_DF_SAMPLEWORD_QUALIFIERS = 0U, + KHR_DF_SAMPLEWORD_SAMPLEPOSITION0 = 1U, + KHR_DF_SAMPLEWORD_SAMPLEPOSITION1 = 1U, + KHR_DF_SAMPLEWORD_SAMPLEPOSITION2 = 1U, + KHR_DF_SAMPLEWORD_SAMPLEPOSITION3 = 1U, + KHR_DF_SAMPLEWORD_SAMPLEPOSITION_ALL = 1U, + KHR_DF_SAMPLEWORD_SAMPLELOWER = 2U, + KHR_DF_SAMPLEWORD_SAMPLEUPPER = 3U +} khr_df_sampleword_e; + +typedef enum _khr_df_sampleshift_e { + KHR_DF_SAMPLESHIFT_BITOFFSET = 0U, + KHR_DF_SAMPLESHIFT_BITLENGTH = 16U, + KHR_DF_SAMPLESHIFT_CHANNELID = 24U, + /* N.B. Qualifiers are defined as an offset into a byte */ + KHR_DF_SAMPLESHIFT_QUALIFIERS = 24U, + KHR_DF_SAMPLESHIFT_SAMPLEPOSITION0 = 0U, + KHR_DF_SAMPLESHIFT_SAMPLEPOSITION1 = 8U, + KHR_DF_SAMPLESHIFT_SAMPLEPOSITION2 = 16U, + KHR_DF_SAMPLESHIFT_SAMPLEPOSITION3 = 24U, + KHR_DF_SAMPLESHIFT_SAMPLEPOSITION_ALL = 0U, + KHR_DF_SAMPLESHIFT_SAMPLELOWER = 0U, + KHR_DF_SAMPLESHIFT_SAMPLEUPPER = 0U +} khr_df_sampleshift_e; + +typedef enum _khr_df_samplemask_e { + KHR_DF_SAMPLEMASK_BITOFFSET = 0xFFFFU, + KHR_DF_SAMPLEMASK_BITLENGTH = 0xFF, + KHR_DF_SAMPLEMASK_CHANNELID = 0xF, + /* N.B. Qualifiers are defined as an offset into a byte */ + KHR_DF_SAMPLEMASK_QUALIFIERS = 0xF0, + KHR_DF_SAMPLEMASK_SAMPLEPOSITION0 = 0xFF, + KHR_DF_SAMPLEMASK_SAMPLEPOSITION1 = 0xFF, + KHR_DF_SAMPLEMASK_SAMPLEPOSITION2 = 0xFF, + KHR_DF_SAMPLEMASK_SAMPLEPOSITION3 = 0xFF, + /* ISO C restricts enum values to range of int hence the + cast. We do it verbosely instead of using -1 to ensure + it is a 32-bit value even if int is 64 bits. */ + KHR_DF_SAMPLEMASK_SAMPLEPOSITION_ALL = (int) 0xFFFFFFFFU, + KHR_DF_SAMPLEMASK_SAMPLELOWER = (int) 0xFFFFFFFFU, + KHR_DF_SAMPLEMASK_SAMPLEUPPER = (int) 0xFFFFFFFFU +} khr_df_samplemask_e; + +/* Helper macro: + Extract field X of sample S from basic descriptor block BDB */ +#define KHR_DFDSVAL(BDB, S, X) \ + (((BDB)[KHR_DF_WORD_SAMPLESTART + \ + ((S) * KHR_DF_WORD_SAMPLEWORDS) + \ + KHR_DF_SAMPLEWORD_ ## X] >> (KHR_DF_SAMPLESHIFT_ ## X)) \ + & (KHR_DF_SAMPLEMASK_ ## X)) + +/* Helper macro: + Set field X of sample S of basic descriptor block BDB */ +#define KHR_DFDSETSVAL(BDB, S, X, val) \ + ((BDB)[KHR_DF_WORD_SAMPLESTART + \ + ((S) * KHR_DF_WORD_SAMPLEWORDS) + \ + KHR_DF_SAMPLEWORD_ ## X] = \ + ((BDB)[KHR_DF_WORD_SAMPLESTART + \ + ((S) * KHR_DF_WORD_SAMPLEWORDS) + \ + KHR_DF_SAMPLEWORD_ ## X] & \ + ~((uint32_t)(KHR_DF_SAMPLEMASK_ ## X) << (KHR_DF_SAMPLESHIFT_ ## X))) | \ + (((val) & (uint32_t)(KHR_DF_SAMPLEMASK_ ## X)) << (KHR_DF_SAMPLESHIFT_ ## X))) + +/* Helper macro: + Number of samples in basic descriptor block BDB */ +#define KHR_DFDSAMPLECOUNT(BDB) \ + (((KHR_DFDVAL(BDB, DESCRIPTORBLOCKSIZE) >> 2) - \ + KHR_DF_WORD_SAMPLESTART) \ + / KHR_DF_WORD_SAMPLEWORDS) + +/* Helper macro: + Size in words of basic descriptor block for S samples */ +#define KHR_DFDSIZEWORDS(S) \ + (KHR_DF_WORD_SAMPLESTART + \ + (S) * KHR_DF_WORD_SAMPLEWORDS) + +/* Vendor ids */ +typedef enum _khr_df_vendorid_e { + /* Standard Khronos descriptor */ + KHR_DF_VENDORID_KHRONOS = 0U, + KHR_DF_VENDORID_MAX = 0x1FFFFU +} khr_df_vendorid_e; + +/* Descriptor types */ +typedef enum _khr_df_khr_descriptortype_e { + /* Default Khronos basic descriptor block */ + KHR_DF_KHR_DESCRIPTORTYPE_BASICFORMAT = 0U, + /* Extension descriptor block for additional planes */ + KHR_DF_KHR_DESCRIPTORTYPE_ADDITIONAL_PLANES = 0x6001U, + /* Extension descriptor block for additional dimensions */ + KHR_DF_KHR_DESCRIPTORTYPE_ADDITIONAL_DIMENSIONS = 0x6002U, + /* Bit indicates modifying requires understanding this extension */ + KHR_DF_KHR_DESCRIPTORTYPE_NEEDED_FOR_WRITE_BIT = 0x2000U, + /* Bit indicates processing requires understanding this extension */ + KHR_DF_KHR_DESCRIPTORTYPE_NEEDED_FOR_DECODE_BIT = 0x4000U, + KHR_DF_KHR_DESCRIPTORTYPE_MAX = 0x7FFFU +} khr_df_khr_descriptortype_e; + +/* Descriptor block version */ +typedef enum _khr_df_versionnumber_e { + /* Standard Khronos descriptor */ + KHR_DF_VERSIONNUMBER_1_0 = 0U, /* Version 1.0 of the specification */ + KHR_DF_VERSIONNUMBER_1_1 = 0U, /* Version 1.1 did not bump the version number */ + KHR_DF_VERSIONNUMBER_1_2 = 1U, /* Version 1.2 increased the version number */ + KHR_DF_VERSIONNUMBER_1_3 = 2U, /* Version 1.3 increased the version number */ + KHR_DF_VERSIONNUMBER_LATEST = KHR_DF_VERSIONNUMBER_1_3, + KHR_DF_VERSIONNUMBER_MAX = 0xFFFFU +} khr_df_versionnumber_e; + +/* Model in which the color coordinate space is defined. + There is no requirement that a color format use all the + channel types that are defined in the color model. */ +typedef enum _khr_df_model_e { + /* No interpretation of color channels defined */ + KHR_DF_MODEL_UNSPECIFIED = 0U, + /* Color primaries (red, green, blue) + alpha, depth and stencil */ + KHR_DF_MODEL_RGBSDA = 1U, + /* Color differences (Y', Cb, Cr) + alpha, depth and stencil */ + KHR_DF_MODEL_YUVSDA = 2U, + /* Color differences (Y', I, Q) + alpha, depth and stencil */ + KHR_DF_MODEL_YIQSDA = 3U, + /* Perceptual color (CIE L*a*b*) + alpha, depth and stencil */ + KHR_DF_MODEL_LABSDA = 4U, + /* Subtractive colors (cyan, magenta, yellow, black) + alpha */ + KHR_DF_MODEL_CMYKA = 5U, + /* Non-color coordinate data (X, Y, Z, W) */ + KHR_DF_MODEL_XYZW = 6U, + /* Hue, saturation, value, hue angle on color circle, plus alpha */ + KHR_DF_MODEL_HSVA_ANG = 7U, + /* Hue, saturation, lightness, hue angle on color circle, plus alpha */ + KHR_DF_MODEL_HSLA_ANG = 8U, + /* Hue, saturation, value, hue on color hexagon, plus alpha */ + KHR_DF_MODEL_HSVA_HEX = 9U, + /* Hue, saturation, lightness, hue on color hexagon, plus alpha */ + KHR_DF_MODEL_HSLA_HEX = 10U, + /* Lightweight approximate color difference (luma, orange, green) */ + KHR_DF_MODEL_YCGCOA = 11U, + /* ITU BT.2020 constant luminance YcCbcCrc */ + KHR_DF_MODEL_YCCBCCRC = 12U, + /* ITU BT.2100 constant intensity ICtCp */ + KHR_DF_MODEL_ICTCP = 13U, + /* CIE 1931 XYZ color coordinates (X, Y, Z) */ + KHR_DF_MODEL_CIEXYZ = 14U, + /* CIE 1931 xyY color coordinates (X, Y, Y) */ + KHR_DF_MODEL_CIEXYY = 15U, + + /* Compressed formats start at 128. */ + /* These compressed formats should generally have a single sample, + sited at the 0,0 position of the texel block. Where multiple + channels are used to distinguish formats, these should be cosited. */ + /* Direct3D (and S3) compressed formats */ + /* Note that premultiplied status is recorded separately */ + /* DXT1 "channels" are RGB (0), Alpha (1) */ + /* DXT1/BC1 with one channel is opaque */ + /* DXT1/BC1 with a cosited alpha sample is transparent */ + KHR_DF_MODEL_DXT1A = 128U, + KHR_DF_MODEL_BC1A = 128U, + /* DXT2/DXT3/BC2, with explicit 4-bit alpha */ + KHR_DF_MODEL_DXT2 = 129U, + KHR_DF_MODEL_DXT3 = 129U, + KHR_DF_MODEL_BC2 = 129U, + /* DXT4/DXT5/BC3, with interpolated alpha */ + KHR_DF_MODEL_DXT4 = 130U, + KHR_DF_MODEL_DXT5 = 130U, + KHR_DF_MODEL_BC3 = 130U, + /* BC4 - single channel interpolated 8-bit data */ + /* (The UNORM/SNORM variation is recorded in the channel data) */ + KHR_DF_MODEL_BC4 = 131U, + /* BC5 - two channel interpolated 8-bit data */ + /* (The UNORM/SNORM variation is recorded in the channel data) */ + KHR_DF_MODEL_BC5 = 132U, + /* BC6H - DX11 format for 16-bit float channels */ + KHR_DF_MODEL_BC6H = 133U, + /* BC7 - DX11 format */ + KHR_DF_MODEL_BC7 = 134U, + /* Gap left for future desktop expansion */ + + /* Mobile compressed formats follow */ + /* A format of ETC1 indicates that the format shall be decodable + by an ETC1-compliant decoder and not rely on ETC2 features */ + KHR_DF_MODEL_ETC1 = 160U, + /* A format of ETC2 is permitted to use ETC2 encodings on top of + the baseline ETC1 specification */ + /* The ETC2 format has channels "red", "green", "RGB" and "alpha", + which should be cosited samples */ + /* Punch-through alpha can be distinguished from full alpha by + the plane size in bytes required for the texel block */ + KHR_DF_MODEL_ETC2 = 161U, + /* Adaptive Scalable Texture Compression */ + /* ASTC HDR vs LDR is determined by the float flag in the channel */ + /* ASTC block size can be distinguished by texel block size */ + KHR_DF_MODEL_ASTC = 162U, + /* ETC1S is a simplified subset of ETC1 */ + KHR_DF_MODEL_ETC1S = 163U, + /* PowerVR Texture Compression */ + KHR_DF_MODEL_PVRTC = 164U, + KHR_DF_MODEL_PVRTC2 = 165U, + KHR_DF_MODEL_UASTC = 166U, + /* Proprietary formats (ATITC, etc.) should follow */ + KHR_DF_MODEL_MAX = 0xFFU +} khr_df_model_e; + +/* Definition of channel names for each color model */ +typedef enum _khr_df_model_channels_e { + /* Unspecified format with nominal channel numbering */ + KHR_DF_CHANNEL_UNSPECIFIED_0 = 0U, + KHR_DF_CHANNEL_UNSPECIFIED_1 = 1U, + KHR_DF_CHANNEL_UNSPECIFIED_2 = 2U, + KHR_DF_CHANNEL_UNSPECIFIED_3 = 3U, + KHR_DF_CHANNEL_UNSPECIFIED_4 = 4U, + KHR_DF_CHANNEL_UNSPECIFIED_5 = 5U, + KHR_DF_CHANNEL_UNSPECIFIED_6 = 6U, + KHR_DF_CHANNEL_UNSPECIFIED_7 = 7U, + KHR_DF_CHANNEL_UNSPECIFIED_8 = 8U, + KHR_DF_CHANNEL_UNSPECIFIED_9 = 9U, + KHR_DF_CHANNEL_UNSPECIFIED_10 = 10U, + KHR_DF_CHANNEL_UNSPECIFIED_11 = 11U, + KHR_DF_CHANNEL_UNSPECIFIED_12 = 12U, + KHR_DF_CHANNEL_UNSPECIFIED_13 = 13U, + KHR_DF_CHANNEL_UNSPECIFIED_14 = 14U, + KHR_DF_CHANNEL_UNSPECIFIED_15 = 15U, + /* MODEL_RGBSDA - red, green, blue, stencil, depth, alpha */ + KHR_DF_CHANNEL_RGBSDA_RED = 0U, + KHR_DF_CHANNEL_RGBSDA_R = 0U, + KHR_DF_CHANNEL_RGBSDA_GREEN = 1U, + KHR_DF_CHANNEL_RGBSDA_G = 1U, + KHR_DF_CHANNEL_RGBSDA_BLUE = 2U, + KHR_DF_CHANNEL_RGBSDA_B = 2U, + KHR_DF_CHANNEL_RGBSDA_STENCIL = 13U, + KHR_DF_CHANNEL_RGBSDA_S = 13U, + KHR_DF_CHANNEL_RGBSDA_DEPTH = 14U, + KHR_DF_CHANNEL_RGBSDA_D = 14U, + KHR_DF_CHANNEL_RGBSDA_ALPHA = 15U, + KHR_DF_CHANNEL_RGBSDA_A = 15U, + /* MODEL_YUVSDA - luma, Cb, Cr, stencil, depth, alpha */ + KHR_DF_CHANNEL_YUVSDA_Y = 0U, + KHR_DF_CHANNEL_YUVSDA_CB = 1U, + KHR_DF_CHANNEL_YUVSDA_U = 1U, + KHR_DF_CHANNEL_YUVSDA_CR = 2U, + KHR_DF_CHANNEL_YUVSDA_V = 2U, + KHR_DF_CHANNEL_YUVSDA_STENCIL = 13U, + KHR_DF_CHANNEL_YUVSDA_S = 13U, + KHR_DF_CHANNEL_YUVSDA_DEPTH = 14U, + KHR_DF_CHANNEL_YUVSDA_D = 14U, + KHR_DF_CHANNEL_YUVSDA_ALPHA = 15U, + KHR_DF_CHANNEL_YUVSDA_A = 15U, + /* MODEL_YIQSDA - luma, in-phase, quadrature, stencil, depth, alpha */ + KHR_DF_CHANNEL_YIQSDA_Y = 0U, + KHR_DF_CHANNEL_YIQSDA_I = 1U, + KHR_DF_CHANNEL_YIQSDA_Q = 2U, + KHR_DF_CHANNEL_YIQSDA_STENCIL = 13U, + KHR_DF_CHANNEL_YIQSDA_S = 13U, + KHR_DF_CHANNEL_YIQSDA_DEPTH = 14U, + KHR_DF_CHANNEL_YIQSDA_D = 14U, + KHR_DF_CHANNEL_YIQSDA_ALPHA = 15U, + KHR_DF_CHANNEL_YIQSDA_A = 15U, + /* MODEL_LABSDA - CIELAB/L*a*b* luma, red-green, blue-yellow, stencil, depth, alpha */ + KHR_DF_CHANNEL_LABSDA_L = 0U, + KHR_DF_CHANNEL_LABSDA_A = 1U, + KHR_DF_CHANNEL_LABSDA_B = 2U, + KHR_DF_CHANNEL_LABSDA_STENCIL = 13U, + KHR_DF_CHANNEL_LABSDA_S = 13U, + KHR_DF_CHANNEL_LABSDA_DEPTH = 14U, + KHR_DF_CHANNEL_LABSDA_D = 14U, + KHR_DF_CHANNEL_LABSDA_ALPHA = 15U, + /* NOTE: KHR_DF_CHANNEL_LABSDA_A is not a synonym for alpha! */ + /* MODEL_CMYKA - cyan, magenta, yellow, key/blacK, alpha */ + KHR_DF_CHANNEL_CMYKSDA_CYAN = 0U, + KHR_DF_CHANNEL_CMYKSDA_C = 0U, + KHR_DF_CHANNEL_CMYKSDA_MAGENTA = 1U, + KHR_DF_CHANNEL_CMYKSDA_M = 1U, + KHR_DF_CHANNEL_CMYKSDA_YELLOW = 2U, + KHR_DF_CHANNEL_CMYKSDA_Y = 2U, + KHR_DF_CHANNEL_CMYKSDA_KEY = 3U, + KHR_DF_CHANNEL_CMYKSDA_BLACK = 3U, + KHR_DF_CHANNEL_CMYKSDA_K = 3U, + KHR_DF_CHANNEL_CMYKSDA_ALPHA = 15U, + KHR_DF_CHANNEL_CMYKSDA_A = 15U, + /* MODEL_XYZW - coordinates x, y, z, w */ + KHR_DF_CHANNEL_XYZW_X = 0U, + KHR_DF_CHANNEL_XYZW_Y = 1U, + KHR_DF_CHANNEL_XYZW_Z = 2U, + KHR_DF_CHANNEL_XYZW_W = 3U, + /* MODEL_HSVA_ANG - value (luma), saturation, hue, alpha, angular projection, conical space */ + KHR_DF_CHANNEL_HSVA_ANG_VALUE = 0U, + KHR_DF_CHANNEL_HSVA_ANG_V = 0U, + KHR_DF_CHANNEL_HSVA_ANG_SATURATION = 1U, + KHR_DF_CHANNEL_HSVA_ANG_S = 1U, + KHR_DF_CHANNEL_HSVA_ANG_HUE = 2U, + KHR_DF_CHANNEL_HSVA_ANG_H = 2U, + KHR_DF_CHANNEL_HSVA_ANG_ALPHA = 15U, + KHR_DF_CHANNEL_HSVA_ANG_A = 15U, + /* MODEL_HSLA_ANG - lightness (luma), saturation, hue, alpha, angular projection, double conical space */ + KHR_DF_CHANNEL_HSLA_ANG_LIGHTNESS = 0U, + KHR_DF_CHANNEL_HSLA_ANG_L = 0U, + KHR_DF_CHANNEL_HSLA_ANG_SATURATION = 1U, + KHR_DF_CHANNEL_HSLA_ANG_S = 1U, + KHR_DF_CHANNEL_HSLA_ANG_HUE = 2U, + KHR_DF_CHANNEL_HSLA_ANG_H = 2U, + KHR_DF_CHANNEL_HSLA_ANG_ALPHA = 15U, + KHR_DF_CHANNEL_HSLA_ANG_A = 15U, + /* MODEL_HSVA_HEX - value (luma), saturation, hue, alpha, hexagonal projection, conical space */ + KHR_DF_CHANNEL_HSVA_HEX_VALUE = 0U, + KHR_DF_CHANNEL_HSVA_HEX_V = 0U, + KHR_DF_CHANNEL_HSVA_HEX_SATURATION = 1U, + KHR_DF_CHANNEL_HSVA_HEX_S = 1U, + KHR_DF_CHANNEL_HSVA_HEX_HUE = 2U, + KHR_DF_CHANNEL_HSVA_HEX_H = 2U, + KHR_DF_CHANNEL_HSVA_HEX_ALPHA = 15U, + KHR_DF_CHANNEL_HSVA_HEX_A = 15U, + /* MODEL_HSLA_HEX - lightness (luma), saturation, hue, alpha, hexagonal projection, double conical space */ + KHR_DF_CHANNEL_HSLA_HEX_LIGHTNESS = 0U, + KHR_DF_CHANNEL_HSLA_HEX_L = 0U, + KHR_DF_CHANNEL_HSLA_HEX_SATURATION = 1U, + KHR_DF_CHANNEL_HSLA_HEX_S = 1U, + KHR_DF_CHANNEL_HSLA_HEX_HUE = 2U, + KHR_DF_CHANNEL_HSLA_HEX_H = 2U, + KHR_DF_CHANNEL_HSLA_HEX_ALPHA = 15U, + KHR_DF_CHANNEL_HSLA_HEX_A = 15U, + /* MODEL_YCGCOA - luma, green delta, orange delta, alpha */ + KHR_DF_CHANNEL_YCGCOA_Y = 0U, + KHR_DF_CHANNEL_YCGCOA_CG = 1U, + KHR_DF_CHANNEL_YCGCOA_CO = 2U, + KHR_DF_CHANNEL_YCGCOA_ALPHA = 15U, + KHR_DF_CHANNEL_YCGCOA_A = 15U, + /* MODEL_CIEXYZ - CIE 1931 X, Y, Z */ + KHR_DF_CHANNEL_CIEXYZ_X = 0U, + KHR_DF_CHANNEL_CIEXYZ_Y = 1U, + KHR_DF_CHANNEL_CIEXYZ_Z = 2U, + /* MODEL_CIEXYY - CIE 1931 x, y, Y */ + KHR_DF_CHANNEL_CIEXYY_X = 0U, + KHR_DF_CHANNEL_CIEXYY_YCHROMA = 1U, + KHR_DF_CHANNEL_CIEXYY_YLUMA = 2U, + + /* Compressed formats */ + /* MODEL_DXT1A/MODEL_BC1A */ + KHR_DF_CHANNEL_DXT1A_COLOR = 0U, + KHR_DF_CHANNEL_BC1A_COLOR = 0U, + KHR_DF_CHANNEL_DXT1A_ALPHAPRESENT = 1U, + KHR_DF_CHANNEL_DXT1A_ALPHA = 1U, + KHR_DF_CHANNEL_BC1A_ALPHAPRESENT = 1U, + KHR_DF_CHANNEL_BC1A_ALPHA = 1U, + /* MODEL_DXT2/3/MODEL_BC2 */ + KHR_DF_CHANNEL_DXT2_COLOR = 0U, + KHR_DF_CHANNEL_DXT3_COLOR = 0U, + KHR_DF_CHANNEL_BC2_COLOR = 0U, + KHR_DF_CHANNEL_DXT2_ALPHA = 15U, + KHR_DF_CHANNEL_DXT3_ALPHA = 15U, + KHR_DF_CHANNEL_BC2_ALPHA = 15U, + /* MODEL_DXT4/5/MODEL_BC3 */ + KHR_DF_CHANNEL_DXT4_COLOR = 0U, + KHR_DF_CHANNEL_DXT5_COLOR = 0U, + KHR_DF_CHANNEL_BC3_COLOR = 0U, + KHR_DF_CHANNEL_DXT4_ALPHA = 15U, + KHR_DF_CHANNEL_DXT5_ALPHA = 15U, + KHR_DF_CHANNEL_BC3_ALPHA = 15U, + /* MODEL_BC4 */ + KHR_DF_CHANNEL_BC4_DATA = 0U, + /* MODEL_BC5 */ + KHR_DF_CHANNEL_BC5_RED = 0U, + KHR_DF_CHANNEL_BC5_R = 0U, + KHR_DF_CHANNEL_BC5_GREEN = 1U, + KHR_DF_CHANNEL_BC5_G = 1U, + /* MODEL_BC6H */ + KHR_DF_CHANNEL_BC6H_COLOR = 0U, + KHR_DF_CHANNEL_BC6H_DATA = 0U, + /* MODEL_BC7 */ + KHR_DF_CHANNEL_BC7_DATA = 0U, + KHR_DF_CHANNEL_BC7_COLOR = 0U, + /* MODEL_ETC1 */ + KHR_DF_CHANNEL_ETC1_DATA = 0U, + KHR_DF_CHANNEL_ETC1_COLOR = 0U, + /* MODEL_ETC2 */ + KHR_DF_CHANNEL_ETC2_RED = 0U, + KHR_DF_CHANNEL_ETC2_R = 0U, + KHR_DF_CHANNEL_ETC2_GREEN = 1U, + KHR_DF_CHANNEL_ETC2_G = 1U, + KHR_DF_CHANNEL_ETC2_COLOR = 2U, + KHR_DF_CHANNEL_ETC2_ALPHA = 15U, + KHR_DF_CHANNEL_ETC2_A = 15U, + /* MODEL_ASTC */ + KHR_DF_CHANNEL_ASTC_DATA = 0U, + /* MODEL_ETC1S */ + KHR_DF_CHANNEL_ETC1S_RGB = 0U, + KHR_DF_CHANNEL_ETC1S_RRR = 3U, + KHR_DF_CHANNEL_ETC1S_GGG = 4U, + KHR_DF_CHANNEL_ETC1S_AAA = 15U, + /* MODEL_PVRTC */ + KHR_DF_CHANNEL_PVRTC_DATA = 0U, + KHR_DF_CHANNEL_PVRTC_COLOR = 0U, + /* MODEL_PVRTC2 */ + KHR_DF_CHANNEL_PVRTC2_DATA = 0U, + KHR_DF_CHANNEL_PVRTC2_COLOR = 0U, + /* MODEL UASTC */ + KHR_DF_CHANNEL_UASTC_DATA = 0U, + KHR_DF_CHANNEL_UASTC_RGB = 0U, + KHR_DF_CHANNEL_UASTC_RGBA = 3U, + KHR_DF_CHANNEL_UASTC_RRR = 4U, + KHR_DF_CHANNEL_UASTC_RRRG = 5U, + KHR_DF_CHANNEL_UASTC_RG = 6U, + + /* Common channel names shared by multiple formats */ + KHR_DF_CHANNEL_COMMON_LUMA = 0U, + KHR_DF_CHANNEL_COMMON_L = 0U, + KHR_DF_CHANNEL_COMMON_STENCIL = 13U, + KHR_DF_CHANNEL_COMMON_S = 13U, + KHR_DF_CHANNEL_COMMON_DEPTH = 14U, + KHR_DF_CHANNEL_COMMON_D = 14U, + KHR_DF_CHANNEL_COMMON_ALPHA = 15U, + KHR_DF_CHANNEL_COMMON_A = 15U +} khr_df_model_channels_e; + +/* Definition of the primary colors in color coordinates. + This is implicitly responsible for defining the conversion + between RGB an YUV color spaces. + LAB and related absolute color models should use + KHR_DF_PRIMARIES_CIEXYZ. */ +typedef enum _khr_df_primaries_e { + /* No color primaries defined */ + KHR_DF_PRIMARIES_UNSPECIFIED = 0U, + /* Color primaries of ITU-R BT.709 and sRGB */ + KHR_DF_PRIMARIES_BT709 = 1U, + /* Synonym for KHR_DF_PRIMARIES_BT709 */ + KHR_DF_PRIMARIES_SRGB = 1U, + /* Color primaries of ITU-R BT.601 (625-line EBU variant) */ + KHR_DF_PRIMARIES_BT601_EBU = 2U, + /* Color primaries of ITU-R BT.601 (525-line SMPTE C variant) */ + KHR_DF_PRIMARIES_BT601_SMPTE = 3U, + /* Color primaries of ITU-R BT.2020 */ + KHR_DF_PRIMARIES_BT2020 = 4U, + /* CIE theoretical color coordinate space */ + KHR_DF_PRIMARIES_CIEXYZ = 5U, + /* Academy Color Encoding System primaries */ + KHR_DF_PRIMARIES_ACES = 6U, + /* Color primaries of ACEScc */ + KHR_DF_PRIMARIES_ACESCC = 7U, + /* Legacy NTSC 1953 primaries */ + KHR_DF_PRIMARIES_NTSC1953 = 8U, + /* Legacy PAL 525-line primaries */ + KHR_DF_PRIMARIES_PAL525 = 9U, + /* Color primaries of Display P3 */ + KHR_DF_PRIMARIES_DISPLAYP3 = 10U, + /* Color primaries of Adobe RGB (1998) */ + KHR_DF_PRIMARIES_ADOBERGB = 11U, + KHR_DF_PRIMARIES_MAX = 0xFFU +} khr_df_primaries_e; + +/* Definition of the optical to digital transfer function + ("gamma correction"). Most transfer functions are not a pure + power function and also include a linear element. + LAB and related absolute color representations should use + KHR_DF_TRANSFER_UNSPECIFIED. */ +typedef enum _khr_df_transfer_e { + /* No transfer function defined */ + KHR_DF_TRANSFER_UNSPECIFIED = 0U, + /* Linear transfer function (value proportional to intensity) */ + KHR_DF_TRANSFER_LINEAR = 1U, + /* Perceptually-linear transfer function of sRGH (~2.4) */ + KHR_DF_TRANSFER_SRGB = 2U, + /* Perceptually-linear transfer function of ITU BT.601, BT.709 and BT.2020 (~1/.45) */ + KHR_DF_TRANSFER_ITU = 3U, + /* SMTPE170M (digital NTSC) defines an alias for the ITU transfer function (~1/.45) */ + KHR_DF_TRANSFER_SMTPE170M = 3U, + /* Perceptually-linear gamma function of original NTSC (simple 2.2 gamma) */ + KHR_DF_TRANSFER_NTSC = 4U, + /* Sony S-log used by Sony video cameras */ + KHR_DF_TRANSFER_SLOG = 5U, + /* Sony S-log 2 used by Sony video cameras */ + KHR_DF_TRANSFER_SLOG2 = 6U, + /* ITU BT.1886 EOTF */ + KHR_DF_TRANSFER_BT1886 = 7U, + /* ITU BT.2100 HLG OETF */ + KHR_DF_TRANSFER_HLG_OETF = 8U, + /* ITU BT.2100 HLG EOTF */ + KHR_DF_TRANSFER_HLG_EOTF = 9U, + /* ITU BT.2100 PQ EOTF */ + KHR_DF_TRANSFER_PQ_EOTF = 10U, + /* ITU BT.2100 PQ OETF */ + KHR_DF_TRANSFER_PQ_OETF = 11U, + /* DCI P3 transfer function */ + KHR_DF_TRANSFER_DCIP3 = 12U, + /* Legacy PAL OETF */ + KHR_DF_TRANSFER_PAL_OETF = 13U, + /* Legacy PAL 625-line EOTF */ + KHR_DF_TRANSFER_PAL625_EOTF = 14U, + /* Legacy ST240 transfer function */ + KHR_DF_TRANSFER_ST240 = 15U, + /* ACEScc transfer function */ + KHR_DF_TRANSFER_ACESCC = 16U, + /* ACEScct transfer function */ + KHR_DF_TRANSFER_ACESCCT = 17U, + /* Adobe RGB (1998) transfer function */ + KHR_DF_TRANSFER_ADOBERGB = 18U, + KHR_DF_TRANSFER_MAX = 0xFFU +} khr_df_transfer_e; + +typedef enum _khr_df_flags_e { + KHR_DF_FLAG_ALPHA_STRAIGHT = 0U, + KHR_DF_FLAG_ALPHA_PREMULTIPLIED = 1U +} khr_df_flags_e; + +typedef enum _khr_df_sample_datatype_qualifiers_e { + KHR_DF_SAMPLE_DATATYPE_LINEAR = 1U << 4U, + KHR_DF_SAMPLE_DATATYPE_EXPONENT = 1U << 5U, + KHR_DF_SAMPLE_DATATYPE_SIGNED = 1U << 6U, + KHR_DF_SAMPLE_DATATYPE_FLOAT = 1U << 7U +} khr_df_sample_datatype_qualifiers_e; + +#endif diff --git a/thirdparty/libktx/include/ktx.h b/thirdparty/libktx/include/ktx.h new file mode 100644 index 000000000000..0af87f251903 --- /dev/null +++ b/thirdparty/libktx/include/ktx.h @@ -0,0 +1,1810 @@ +/* -*- tab-width: 4; -*- */ +/* vi: set sw=2 ts=4 expandtab: */ + +#ifndef KTX_H_A55A6F00956F42F3A137C11929827FE1 +#define KTX_H_A55A6F00956F42F3A137C11929827FE1 + +/* + * Copyright 2010-2018 The Khronos Group, Inc. + * SPDX-License-Identifier: Apache-2.0 + * + * See the accompanying LICENSE.md for licensing details for all files in + * the KTX library and KTX loader tests. + */ + +/** + * @file + * @~English + * + * @brief Declares the public functions and structures of the + * KTX API. + * + * @author Mark Callow, Edgewise Consulting and while at HI Corporation + * @author Based on original work by Georg Kolling, Imagination Technology + * + * @snippet{doc} version.h API version + */ + +#include +#include +#include + +#include + +/* + * Don't use khrplatform.h in order not to break apps existing + * before these definitions were needed. + */ +#if defined(KHRONOS_STATIC) + #define KTX_API +#elif defined(_WIN32) || defined(__CYGWIN__) + #if !defined(KTX_API) + #if __GNUC__ + #define KTX_API __attribute__ ((dllimport)) + #elif _MSC_VER + #define KTX_API __declspec(dllimport) + #else + #error "Your compiler's equivalent of dllimport is unknown" + #endif + #endif +#elif defined(__ANDROID__) + #define KTX_API __attribute__((visibility("default"))) +#else + #define KTX_API +#endif + +#if defined(_WIN32) && !defined(KHRONOS_STATIC) + #if !defined(KTX_APIENTRY) + #define KTX_APIENTRY __stdcall + #endif +#else + #define KTX_APIENTRY +#endif + +/* To avoid including define our own types. */ +typedef unsigned char ktx_uint8_t; +typedef bool ktx_bool_t; +#ifdef _MSC_VER +typedef unsigned __int16 ktx_uint16_t; +typedef signed __int16 ktx_int16_t; +typedef unsigned __int32 ktx_uint32_t; +typedef signed __int32 ktx_int32_t; +typedef size_t ktx_size_t; +typedef unsigned __int64 ktx_uint64_t; +typedef signed __int64 ktx_int64_t; +#else +#include +typedef uint16_t ktx_uint16_t; +typedef int16_t ktx_int16_t; +typedef uint32_t ktx_uint32_t; +typedef int32_t ktx_int32_t; +typedef size_t ktx_size_t; +typedef uint64_t ktx_uint64_t; +typedef int64_t ktx_int64_t; +#endif + +/* This will cause compilation to fail if size of uint32 != 4. */ +typedef unsigned char ktx_uint32_t_SIZE_ASSERT[sizeof(ktx_uint32_t) == 4]; + +/* + * This #if allows libktx to be compiled with strict c99. It avoids + * compiler warnings or even errors when a gl.h is already included. + * "Redefinition of (type) is a c11 feature". Obviously this doesn't help if + * gl.h comes after. However nobody has complained about the unguarded typedefs + * since they were introduced so this is unlikely to be a problem in practice. + * Presumably everybody is using platform default compilers not c99 or else + * they are using C++. + */ +#if !defined(GL_NO_ERROR) + /* + * To avoid having to including gl.h ... + */ + typedef unsigned char GLboolean; + typedef unsigned int GLenum; + typedef int GLint; + typedef int GLsizei; + typedef unsigned int GLuint; + typedef unsigned char GLubyte; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @~English + * @brief Key string for standard writer metadata. + */ +#define KTX_ANIMDATA_KEY "KTXanimData" +/** + * @~English + * @brief Key string for standard orientation metadata. + */ +#define KTX_ORIENTATION_KEY "KTXorientation" +/** + * @~English + * @brief Key string for standard swizzle metadata. + */ +#define KTX_SWIZZLE_KEY "KTXswizzle" +/** + * @~English + * @brief Key string for standard writer metadata. + */ +#define KTX_WRITER_KEY "KTXwriter" +/** + * @~English + * @brief Key string for standard writer supercompression parameter metadata. + */ +#define KTX_WRITER_SCPARAMS_KEY "KTXwriterScParams" +/** + * @~English + * @brief Standard KTX 1 format for 1D orientation value. + */ +#define KTX_ORIENTATION1_FMT "S=%c" +/** + * @~English + * @brief Standard KTX 1 format for 2D orientation value. + */ +#define KTX_ORIENTATION2_FMT "S=%c,T=%c" +/** + * @~English + * @brief Standard KTX 1 format for 3D orientation value. + */ +#define KTX_ORIENTATION3_FMT "S=%c,T=%c,R=%c" +/** + * @~English + * @brief Required unpack alignment + */ +#define KTX_GL_UNPACK_ALIGNMENT 4 + +#define KTX_TRUE true +#define KTX_FALSE false + +/** + * @~English + * @brief Error codes returned by library functions. + */ +typedef enum ktx_error_code_e { + KTX_SUCCESS = 0, /*!< Operation was successful. */ + KTX_FILE_DATA_ERROR, /*!< The data in the file is inconsistent with the spec. */ + KTX_FILE_ISPIPE, /*!< The file is a pipe or named pipe. */ + KTX_FILE_OPEN_FAILED, /*!< The target file could not be opened. */ + KTX_FILE_OVERFLOW, /*!< The operation would exceed the max file size. */ + KTX_FILE_READ_ERROR, /*!< An error occurred while reading from the file. */ + KTX_FILE_SEEK_ERROR, /*!< An error occurred while seeking in the file. */ + KTX_FILE_UNEXPECTED_EOF, /*!< File does not have enough data to satisfy request. */ + KTX_FILE_WRITE_ERROR, /*!< An error occurred while writing to the file. */ + KTX_GL_ERROR, /*!< GL operations resulted in an error. */ + KTX_INVALID_OPERATION, /*!< The operation is not allowed in the current state. */ + KTX_INVALID_VALUE, /*!< A parameter value was not valid */ + KTX_NOT_FOUND, /*!< Requested key was not found */ + KTX_OUT_OF_MEMORY, /*!< Not enough memory to complete the operation. */ + KTX_TRANSCODE_FAILED, /*!< Transcoding of block compressed texture failed. */ + KTX_UNKNOWN_FILE_FORMAT, /*!< The file not a KTX file */ + KTX_UNSUPPORTED_TEXTURE_TYPE, /*!< The KTX file specifies an unsupported texture type. */ + KTX_UNSUPPORTED_FEATURE, /*!< Feature not included in in-use library or not yet implemented. */ + KTX_LIBRARY_NOT_LINKED, /*!< Library dependency (OpenGL or Vulkan) not linked into application. */ + KTX_ERROR_MAX_ENUM = KTX_LIBRARY_NOT_LINKED /*!< For safety checks. */ +} ktx_error_code_e; +/** + * @deprecated + * @~English + * @brief For backward compatibility + */ +#define KTX_error_code ktx_error_code_e + +#define KTX_IDENTIFIER_REF { 0xAB, 0x4B, 0x54, 0x58, 0x20, 0x31, 0x31, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A } +#define KTX_ENDIAN_REF (0x04030201) +#define KTX_ENDIAN_REF_REV (0x01020304) +#define KTX_HEADER_SIZE (64) + +/** + * @~English + * @brief Result codes returned by library functions. + */ + typedef enum ktx_error_code_e ktxResult; + +/** + * @class ktxHashList + * @~English + * @brief Opaque handle to a ktxHashList. + */ +typedef struct ktxKVListEntry* ktxHashList; + +typedef struct ktxStream ktxStream; + +#define KTX_APIENTRYP KTX_APIENTRY * +/** + * @class ktxHashListEntry + * @~English + * @brief Opaque handle to an entry in a @ref ktxHashList. + */ +typedef struct ktxKVListEntry ktxHashListEntry; + +typedef enum ktxOrientationX { + KTX_ORIENT_X_LEFT = 'l', KTX_ORIENT_X_RIGHT = 'r' +} ktxOrientationX; + +typedef enum ktxOrientationY { + KTX_ORIENT_Y_UP = 'u', KTX_ORIENT_Y_DOWN = 'd' +} ktxOrientationY; + +typedef enum ktxOrientationZ { + KTX_ORIENT_Z_IN = 'i', KTX_ORIENT_Z_OUT = 'o' +} ktxOrientationZ; + +typedef enum class_id { + ktxTexture1_c = 1, + ktxTexture2_c = 2 +} class_id; + +/** + * @~English + * @brief Struct describing the logical orientation of an image. + */ +struct ktxOrientation { + ktxOrientationX x; /*!< Orientation in X */ + ktxOrientationY y; /*!< Orientation in Y */ + ktxOrientationZ z; /*!< Orientation in Z */ +}; + +#define KTXTEXTURECLASSDEFN \ + class_id classId; \ + struct ktxTexture_vtbl* vtbl; \ + struct ktxTexture_vvtbl* vvtbl; \ + struct ktxTexture_protected* _protected; \ + ktx_bool_t isArray; \ + ktx_bool_t isCubemap; \ + ktx_bool_t isCompressed; \ + ktx_bool_t generateMipmaps; \ + ktx_uint32_t baseWidth; \ + ktx_uint32_t baseHeight; \ + ktx_uint32_t baseDepth; \ + ktx_uint32_t numDimensions; \ + ktx_uint32_t numLevels; \ + ktx_uint32_t numLayers; \ + ktx_uint32_t numFaces; \ + struct ktxOrientation orientation; \ + ktxHashList kvDataHead; \ + ktx_uint32_t kvDataLen; \ + ktx_uint8_t* kvData; \ + ktx_size_t dataSize; \ + ktx_uint8_t* pData; + + +/** + * @class ktxTexture + * @~English + * @brief Base class representing a texture. + * + * ktxTextures should be created only by one of the provided + * functions and these fields should be considered read-only. + */ +typedef struct ktxTexture { + KTXTEXTURECLASSDEFN +} ktxTexture; +/** + * @typedef ktxTexture::classId + * @~English + * @brief Identify the class type. + * + * Since there are no public ktxTexture constructors, this can only have + * values of ktxTexture1_c or ktxTexture2_c. + */ +/** + * @typedef ktxTexture::vtbl + * @~English + * @brief Pointer to the class's vtble. + */ +/** + * @typedef ktxTexture::vvtbl + * @~English + * @brief Pointer to the class's vtble for Vulkan functions. + * + * A separate vtble is used so this header does not need to include vulkan.h. + */ +/** + * @typedef ktxTexture::_protected + * @~English + * @brief Opaque pointer to the class's protected variables. + */ +/** + * @typedef ktxTexture::isArray + * @~English + * + * KTX_TRUE if the texture is an array texture, i.e, + * a GL_TEXTURE_*_ARRAY target is to be used. + */ +/** + * @typedef ktxTexture::isCubemap + * @~English + * + * KTX_TRUE if the texture is a cubemap or cubemap array. + */ +/** + * @typedef ktxTexture::isCubemap + * @~English + * + * KTX_TRUE if the texture's format is a block compressed format. + */ +/** + * @typedef ktxTexture::generateMipmaps + * @~English + * + * KTX_TRUE if mipmaps should be generated for the texture by + * ktxTexture_GLUpload() or ktxTexture_VkUpload(). + */ +/**n + * @typedef ktxTexture::baseWidth + * @~English + * @brief Width of the texture's base level. + */ +/** + * @typedef ktxTexture::baseHeight + * @~English + * @brief Height of the texture's base level. + */ +/** + * @typedef ktxTexture::baseDepth + * @~English + * @brief Depth of the texture's base level. + */ +/** + * @typedef ktxTexture::numDimensions + * @~English + * @brief Number of dimensions in the texture: 1, 2 or 3. + */ +/** + * @typedef ktxTexture::numLevels + * @~English + * @brief Number of mip levels in the texture. + * + * Must be 1, if @c generateMipmaps is KTX_TRUE. Can be less than a + * full pyramid but always starts at the base level. + */ +/** + * @typedef ktxTexture::numLevels + * @~English + * @brief Number of array layers in the texture. + */ +/** + * @typedef ktxTexture::numFaces + * @~English + * @brief Number of faces: 6 for cube maps, 1 otherwise. + */ +/** + * @typedef ktxTexture::orientation + * @~English + * @brief Describes the logical orientation of the images in each dimension. + * + * ktxOrientationX for X, ktxOrientationY for Y and ktxOrientationZ for Z. + */ +/** + * @typedef ktxTexture::kvDataHead + * @~English + * @brief Head of the hash list of metadata. + */ +/** + * @typedef ktxTexture::kvDataLen + * @~English + * @brief Length of the metadata, if it has been extracted in its raw form, + * otherwise 0. + */ +/** + * @typedef ktxTexture::kvData + * @~English + * @brief Pointer to the metadata, if it has been extracted in its raw form, + * otherwise NULL. + */ +/** + * @typedef ktxTexture::dataSize + * @~English + * @brief Byte length of the texture's uncompressed image data. + */ +/** + * @typedef ktxTexture::pData + * @~English + * @brief Pointer to the start of the image data. + */ + +/** + * @memberof ktxTexture + * @~English + * @brief Signature of function called by the ktxTexture_Iterate* + * functions to receive image data. + * + * The function parameters are used to pass values which change for each image. + * Obtain values which are uniform across all images from the @c ktxTexture + * object. + * + * @param [in] miplevel MIP level from 0 to the max level which is + * dependent on the texture size. + * @param [in] face usually 0; for cube maps, one of the 6 cube + * faces in the order +X, -X, +Y, -Y, +Z, -Z, + * 0 to 5. + * @param [in] width width of the image. + * @param [in] height height of the image or, for 1D textures + * textures, 1. + * @param [in] depth depth of the image or, for 1D & 2D + * textures, 1. + * @param [in] faceLodSize number of bytes of data pointed at by + * @p pixels. + * @param [in] pixels pointer to the image data. + * @param [in,out] userdata pointer for the application to pass data to and + * from the callback function. + */ + +typedef KTX_error_code + (* PFNKTXITERCB)(int miplevel, int face, + int width, int height, int depth, + ktx_uint64_t faceLodSize, + void* pixels, void* userdata); + +/* Don't use KTX_APIENTRYP to avoid a Doxygen bug. */ +typedef void (KTX_APIENTRY* PFNKTEXDESTROY)(ktxTexture* This); +typedef KTX_error_code + (KTX_APIENTRY* PFNKTEXGETIMAGEOFFSET)(ktxTexture* This, ktx_uint32_t level, + ktx_uint32_t layer, + ktx_uint32_t faceSlice, + ktx_size_t* pOffset); +typedef ktx_size_t + (KTX_APIENTRY* PFNKTEXGETDATASIZEUNCOMPRESSED)(ktxTexture* This); +typedef ktx_size_t + (KTX_APIENTRY* PFNKTEXGETIMAGESIZE)(ktxTexture* This, ktx_uint32_t level); +typedef KTX_error_code + (KTX_APIENTRY* PFNKTEXITERATELEVELS)(ktxTexture* This, PFNKTXITERCB iterCb, + void* userdata); + +typedef KTX_error_code + (KTX_APIENTRY* PFNKTEXITERATELOADLEVELFACES)(ktxTexture* This, + PFNKTXITERCB iterCb, + void* userdata); +typedef KTX_error_code + (KTX_APIENTRY* PFNKTEXLOADIMAGEDATA)(ktxTexture* This, + ktx_uint8_t* pBuffer, + ktx_size_t bufSize); +typedef ktx_bool_t + (KTX_APIENTRY* PFNKTEXNEEDSTRANSCODING)(ktxTexture* This); + +typedef KTX_error_code + (KTX_APIENTRY* PFNKTEXSETIMAGEFROMMEMORY)(ktxTexture* This, + ktx_uint32_t level, + ktx_uint32_t layer, + ktx_uint32_t faceSlice, + const ktx_uint8_t* src, + ktx_size_t srcSize); + +typedef KTX_error_code + (KTX_APIENTRY* PFNKTEXSETIMAGEFROMSTDIOSTREAM)(ktxTexture* This, + ktx_uint32_t level, + ktx_uint32_t layer, + ktx_uint32_t faceSlice, + FILE* src, ktx_size_t srcSize); +typedef KTX_error_code + (KTX_APIENTRY* PFNKTEXWRITETOSTDIOSTREAM)(ktxTexture* This, FILE* dstsstr); +typedef KTX_error_code + (KTX_APIENTRY* PFNKTEXWRITETONAMEDFILE)(ktxTexture* This, + const char* const dstname); +typedef KTX_error_code + (KTX_APIENTRY* PFNKTEXWRITETOMEMORY)(ktxTexture* This, + ktx_uint8_t** bytes, ktx_size_t* size); +typedef KTX_error_code + (KTX_APIENTRY* PFNKTEXWRITETOSTREAM)(ktxTexture* This, + ktxStream* dststr); + +/** + * @memberof ktxTexture + * @~English + * @brief Table of virtual ktxTexture methods. + */ + struct ktxTexture_vtbl { + PFNKTEXDESTROY Destroy; + PFNKTEXGETIMAGEOFFSET GetImageOffset; + PFNKTEXGETDATASIZEUNCOMPRESSED GetDataSizeUncompressed; + PFNKTEXGETIMAGESIZE GetImageSize; + PFNKTEXITERATELEVELS IterateLevels; + PFNKTEXITERATELOADLEVELFACES IterateLoadLevelFaces; + PFNKTEXNEEDSTRANSCODING NeedsTranscoding; + PFNKTEXLOADIMAGEDATA LoadImageData; + PFNKTEXSETIMAGEFROMMEMORY SetImageFromMemory; + PFNKTEXSETIMAGEFROMSTDIOSTREAM SetImageFromStdioStream; + PFNKTEXWRITETOSTDIOSTREAM WriteToStdioStream; + PFNKTEXWRITETONAMEDFILE WriteToNamedFile; + PFNKTEXWRITETOMEMORY WriteToMemory; + PFNKTEXWRITETOSTREAM WriteToStream; +}; + +/**************************************************************** + * Macros to give some backward compatibility to the previous API + ****************************************************************/ + +/** + * @~English + * @brief Helper for calling the Destroy virtual method of a ktxTexture. + * @copydoc ktxTexture2.ktxTexture2_Destroy + */ +#define ktxTexture_Destroy(This) (This)->vtbl->Destroy(This) + +/** + * @~English + * @brief Helper for calling the GetImageOffset virtual method of a + * ktxTexture. + * @copydoc ktxTexture2.ktxTexture2_GetImageOffset + */ +#define ktxTexture_GetImageOffset(This, level, layer, faceSlice, pOffset) \ + (This)->vtbl->GetImageOffset(This, level, layer, faceSlice, pOffset) + +/** + * @~English + * @brief Helper for calling the GetDataSizeUncompressed virtual method of a ktxTexture. + * + * For a ktxTexture1 this will always return the value of This->dataSize. + * + * @copydetails ktxTexture2.ktxTexture2_GetDataSizeUncompressed + */ +#define ktxTexture_GetDataSizeUncompressed(This) \ + (This)->vtbl->GetDataSizeUncompressed(This) + +/** + * @~English + * @brief Helper for calling the GetImageSize virtual method of a ktxTexture. + * @copydoc ktxTexture2.ktxTexture2_GetImageSize + */ +#define ktxTexture_GetImageSize(This, level) \ + (This)->vtbl->GetImageSize(This, level) + +/** + * @~English + * @brief Helper for calling the IterateLevels virtual method of a ktxTexture. + * @copydoc ktxTexture2.ktxTexture2_IterateLevels + */ +#define ktxTexture_IterateLevels(This, iterCb, userdata) \ + (This)->vtbl->IterateLevels(This, iterCb, userdata) + +/** + * @~English + * @brief Helper for calling the IterateLoadLevelFaces virtual method of a + * ktxTexture. + * @copydoc ktxTexture2.ktxTexture2_IterateLoadLevelFaces + */ + #define ktxTexture_IterateLoadLevelFaces(This, iterCb, userdata) \ + (This)->vtbl->IterateLoadLevelFaces(This, iterCb, userdata) + +/** + * @~English + * @brief Helper for calling the LoadImageData virtual method of a ktxTexture. + * @copydoc ktxTexture2.ktxTexture2_LoadImageData + */ +#define ktxTexture_LoadImageData(This, pBuffer, bufSize) \ + (This)->vtbl->LoadImageData(This, pBuffer, bufSize) + +/** + * @~English + * @brief Helper for calling the NeedsTranscoding virtual method of a ktxTexture. + * @copydoc ktxTexture2.ktxTexture2_NeedsTranscoding + */ +#define ktxTexture_NeedsTranscoding(This) (This)->vtbl->NeedsTranscoding(This) + +/** + * @~English + * @brief Helper for calling the SetImageFromMemory virtual method of a + * ktxTexture. + * @copydoc ktxTexture2.ktxTexture2_SetImageFromMemory + */ +#define ktxTexture_SetImageFromMemory(This, level, layer, faceSlice, \ + src, srcSize) \ + (This)->vtbl->SetImageFromMemory(This, level, layer, faceSlice, src, srcSize) + +/** + * @~English + * @brief Helper for calling the SetImageFromStdioStream virtual method of a + * ktxTexture. + * @copydoc ktxTexture2.ktxTexture2_SetImageFromStdioStream + */ +#define ktxTexture_SetImageFromStdioStream(This, level, layer, faceSlice, \ + src, srcSize) \ + (This)->vtbl->SetImageFromStdioStream(This, level, layer, faceSlice, \ + src, srcSize) + +/** + * @~English + * @brief Helper for calling the WriteToStdioStream virtual method of a + * ktxTexture. + * @copydoc ktxTexture2.ktxTexture2_WriteToStdioStream + */ +#define ktxTexture_WriteToStdioStream(This, dstsstr) \ + (This)->vtbl->WriteToStdioStream(This, dstsstr) + +/** + * @~English + * @brief Helper for calling the WriteToNamedfile virtual method of a + * ktxTexture. + * @copydoc ktxTexture2.ktxTexture2_WriteToNamedFile + */ +#define ktxTexture_WriteToNamedFile(This, dstname) \ + (This)->vtbl->WriteToNamedFile(This, dstname) + +/** + * @~English + * @brief Helper for calling the WriteToMemory virtual method of a ktxTexture. + * @copydoc ktxTexture2.ktxTexture2_WriteToMemory + */ +#define ktxTexture_WriteToMemory(This, ppDstBytes, pSize) \ + (This)->vtbl->WriteToMemory(This, ppDstBytes, pSize) + +/** + * @~English + * @brief Helper for calling the WriteToStream virtual method of a ktxTexture. + * @copydoc ktxTexture2.ktxTexture2_WriteToStream + */ +#define ktxTexture_WriteToStream(This, dststr) \ + (This)->vtbl->WriteToStream(This, dststr) + + +/** + * @class ktxTexture1 + * @~English + * @brief Class representing a KTX version 1 format texture. + * + * ktxTextures should be created only by one of the ktxTexture_Create* + * functions and these fields should be considered read-only. + */ +typedef struct ktxTexture1 { + KTXTEXTURECLASSDEFN + ktx_uint32_t glFormat; /*!< Format of the texture data, e.g., GL_RGB. */ + ktx_uint32_t glInternalformat; /*!< Internal format of the texture data, + e.g., GL_RGB8. */ + ktx_uint32_t glBaseInternalformat; /*!< Base format of the texture data, + e.g., GL_RGB. */ + ktx_uint32_t glType; /*!< Type of the texture data, e.g, GL_UNSIGNED_BYTE.*/ + struct ktxTexture1_private* _private; /*!< Private data. */ +} ktxTexture1; + +/*===========================================================* +* KTX format version 2 * +*===========================================================*/ + +/** + * @~English + * @brief Enumerators identifying the supercompression scheme. + */ +typedef enum ktxSupercmpScheme { + KTX_SS_NONE = 0, /*!< No supercompression. */ + KTX_SS_BASIS_LZ = 1, /*!< Basis LZ supercompression. */ + KTX_SS_ZSTD = 2, /*!< ZStd supercompression. */ + KTX_SS_BEGIN_RANGE = KTX_SS_NONE, + KTX_SS_END_RANGE = KTX_SS_ZSTD, + KTX_SS_BEGIN_VENDOR_RANGE = 0x10000, + KTX_SS_END_VENDOR_RANGE = 0x1ffff, + KTX_SS_BEGIN_RESERVED = 0x20000, + KTX_SUPERCOMPRESSION_BASIS = KTX_SS_BASIS_LZ, + /*!< @deprecated Will be removed before v4 release. Use KTX_SS_BASIS_LZ instead. */ + KTX_SUPERCOMPRESSION_ZSTD = KTX_SS_ZSTD + /*!< @deprecated Will be removed before v4 release. Use KTX_SS_ZSTD instead. */ +} ktxSupercmpScheme; + +/** + * @class ktxTexture2 + * @~English + * @brief Class representing a KTX version 2 format texture. + * + * ktxTextures should be created only by one of the ktxTexture_Create* + * functions and these fields should be considered read-only. + */ +typedef struct ktxTexture2 { + KTXTEXTURECLASSDEFN + ktx_uint32_t vkFormat; + ktx_uint32_t* pDfd; + ktxSupercmpScheme supercompressionScheme; + ktx_bool_t isVideo; + ktx_uint32_t duration; + ktx_uint32_t timescale; + ktx_uint32_t loopcount; + struct ktxTexture2_private* _private; /*!< Private data. */ +} ktxTexture2; + +#define ktxTexture(t) ((ktxTexture*)t) + +/** + * @memberof ktxTexture + * @~English + * @brief Structure for passing texture information to ktxTexture1_Create() and + * ktxTexture2_Create(). + * + * @sa ktxTexture1_Create() and ktxTexture2_Create(). + */ +typedef struct +{ + ktx_uint32_t glInternalformat; /*!< Internal format for the texture, e.g., + GL_RGB8. Ignored when creating a + ktxTexture2. */ + ktx_uint32_t vkFormat; /*!< VkFormat for texture. Ignored when creating a + ktxTexture1. */ + ktx_uint32_t* pDfd; /*!< Pointer to DFD. Used only when creating a + ktxTexture2 and only if vkFormat is + VK_FORMAT_UNDEFINED. */ + ktx_uint32_t baseWidth; /*!< Width of the base level of the texture. */ + ktx_uint32_t baseHeight; /*!< Height of the base level of the texture. */ + ktx_uint32_t baseDepth; /*!< Depth of the base level of the texture. */ + ktx_uint32_t numDimensions; /*!< Number of dimensions in the texture, 1, 2 + or 3. */ + ktx_uint32_t numLevels; /*!< Number of mip levels in the texture. Should be + 1 if @c generateMipmaps is KTX_TRUE; */ + ktx_uint32_t numLayers; /*!< Number of array layers in the texture. */ + ktx_uint32_t numFaces; /*!< Number of faces: 6 for cube maps, 1 otherwise. */ + ktx_bool_t isArray; /*!< Set to KTX_TRUE if the texture is to be an + array texture. Means OpenGL will use a + GL_TEXTURE_*_ARRAY target. */ + ktx_bool_t generateMipmaps; /*!< Set to KTX_TRUE if mipmaps should be + generated for the texture when loading + into a 3D API. */ +} ktxTextureCreateInfo; + +/** + * @memberof ktxTexture + * @~English + * @brief Enum for requesting, or not, allocation of storage for images. + * + * @sa ktxTexture1_Create() and ktxTexture2_Create(). + */ +typedef enum { + KTX_TEXTURE_CREATE_NO_STORAGE = 0, /*!< Don't allocate any image storage. */ + KTX_TEXTURE_CREATE_ALLOC_STORAGE = 1 /*!< Allocate image storage. */ +} ktxTextureCreateStorageEnum; + +/** + * @memberof ktxTexture + * @~English + * @brief Flags for requesting services during creation. + * + * @sa ktxTexture_CreateFrom* + */ +enum ktxTextureCreateFlagBits { + KTX_TEXTURE_CREATE_NO_FLAGS = 0x00, + KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT = 0x01, + /*!< Load the images from the KTX source. */ + KTX_TEXTURE_CREATE_RAW_KVDATA_BIT = 0x02, + /*!< Load the raw key-value data instead of + creating a @c ktxHashList from it. */ + KTX_TEXTURE_CREATE_SKIP_KVDATA_BIT = 0x04 + /*!< Skip any key-value data. This overrides + the RAW_KVDATA_BIT. */ +}; +/** + * @memberof ktxTexture + * @~English + * @brief Type for TextureCreateFlags parameters. + * + * @sa ktxTexture_CreateFrom*() + */ +typedef ktx_uint32_t ktxTextureCreateFlags; + +/*===========================================================* +* ktxStream +*===========================================================*/ + +/* + * This is unsigned to allow ktxmemstreams to use the + * full amount of memory available. Platforms will + * limit the size of ktxfilestreams to, e.g, MAX_LONG + * on 32-bit and ktxfilestreams raises errors if + * offset values exceed the limits. This choice may + * need to be revisited if we ever start needing -ve + * offsets. + * + * Should the 2GB file size handling limit on 32-bit + * platforms become a problem, ktxfilestream will have + * to be changed to explicitly handle large files by + * using the 64-bit stream functions. + */ +#if defined(_MSC_VER) && defined(_WIN64) + typedef unsigned __int64 ktx_off_t; +#else + typedef off_t ktx_off_t; +#endif +typedef struct ktxMem ktxMem; +typedef struct ktxStream ktxStream; + +enum streamType { eStreamTypeFile = 1, eStreamTypeMemory = 2, eStreamTypeCustom = 3 }; + +/** + * @~English + * @brief type for a pointer to a stream reading function + */ +typedef KTX_error_code (*ktxStream_read)(ktxStream* str, void* dst, + const ktx_size_t count); +/** + * @~English + * @brief type for a pointer to a stream skipping function + */ +typedef KTX_error_code (*ktxStream_skip)(ktxStream* str, + const ktx_size_t count); + +/** + * @~English + * @brief type for a pointer to a stream writing function + */ +typedef KTX_error_code (*ktxStream_write)(ktxStream* str, const void *src, + const ktx_size_t size, + const ktx_size_t count); + +/** + * @~English + * @brief type for a pointer to a stream position query function + */ +typedef KTX_error_code (*ktxStream_getpos)(ktxStream* str, ktx_off_t* const offset); + +/** + * @~English + * @brief type for a pointer to a stream position query function + */ +typedef KTX_error_code (*ktxStream_setpos)(ktxStream* str, const ktx_off_t offset); + +/** + * @~English + * @brief type for a pointer to a stream size query function + */ +typedef KTX_error_code (*ktxStream_getsize)(ktxStream* str, ktx_size_t* const size); + +/** + * @~English + * @brief Destruct a stream + */ +typedef void (*ktxStream_destruct)(ktxStream* str); + +/** + * @~English + * + * @brief Interface of ktxStream. + * + * @author Maksim Kolesin + * @author Georg Kolling, Imagination Technology + * @author Mark Callow, HI Corporation + */ +struct ktxStream +{ + ktxStream_read read; /*!< pointer to function for reading bytes. */ + ktxStream_skip skip; /*!< pointer to function for skipping bytes. */ + ktxStream_write write; /*!< pointer to function for writing bytes. */ + ktxStream_getpos getpos; /*!< pointer to function for getting current position in stream. */ + ktxStream_setpos setpos; /*!< pointer to function for setting current position in stream. */ + ktxStream_getsize getsize; /*!< pointer to function for querying size. */ + ktxStream_destruct destruct; /*!< destruct the stream. */ + + enum streamType type; + union { + FILE* file; /**< a stdio FILE pointer for a ktxFileStream. */ + ktxMem* mem; /**< a pointer to a ktxMem struct for a ktxMemStream. */ + struct + { + void* address; /**< pointer to the data. */ + void* allocatorAddress; /**< pointer to a memory allocator. */ + ktx_size_t size; /**< size of the data. */ + } custom_ptr; /**< pointer to a struct for custom streams. */ + } data; /**< pointer to the stream data. */ + ktx_off_t readpos; /**< used by FileStream for stdin. */ + ktx_bool_t closeOnDestruct; /**< Close FILE* or dispose of memory on destruct. */ +}; + +/* + * See the implementation files for the full documentation of the following + * functions. + */ + +/* + * These four create a ktxTexture1 or ktxTexture2 according to the data + * header, and return a pointer to the base ktxTexture class. + */ +KTX_API KTX_error_code KTX_APIENTRY +ktxTexture_CreateFromStdioStream(FILE* stdioStream, + ktxTextureCreateFlags createFlags, + ktxTexture** newTex); + +KTX_API KTX_error_code KTX_APIENTRY +ktxTexture_CreateFromNamedFile(const char* const filename, + ktxTextureCreateFlags createFlags, + ktxTexture** newTex); + +KTX_API KTX_error_code KTX_APIENTRY +ktxTexture_CreateFromMemory(const ktx_uint8_t* bytes, ktx_size_t size, + ktxTextureCreateFlags createFlags, + ktxTexture** newTex); + +KTX_API KTX_error_code KTX_APIENTRY +ktxTexture_CreateFromStream(ktxStream* stream, + ktxTextureCreateFlags createFlags, + ktxTexture** newTex); + +/* + * Returns a pointer to the image data of a ktxTexture object. + */ +KTX_API ktx_uint8_t* KTX_APIENTRY +ktxTexture_GetData(ktxTexture* This); + +/* + * Returns the pitch of a row of an image at the specified level. + * Similar to the rowPitch in a VkSubResourceLayout. + */ +KTX_API ktx_uint32_t KTX_APIENTRY +ktxTexture_GetRowPitch(ktxTexture* This, ktx_uint32_t level); + + /* + * Return the element size of the texture's images. + */ +KTX_API ktx_uint32_t KTX_APIENTRY +ktxTexture_GetElementSize(ktxTexture* This); + +/* + * Returns the size of all the image data of a ktxTexture object in bytes. + */ +KTX_API ktx_size_t KTX_APIENTRY +ktxTexture_GetDataSize(ktxTexture* This); + +/* Uploads a texture to OpenGL {,ES}. */ +KTX_API KTX_error_code KTX_APIENTRY +ktxTexture_GLUpload(ktxTexture* This, GLuint* pTexture, GLenum* pTarget, + GLenum* pGlerror); + +/* + * Iterate over the levels or faces in a ktxTexture object. + */ +KTX_API KTX_error_code KTX_APIENTRY +ktxTexture_IterateLevelFaces(ktxTexture* This, PFNKTXITERCB iterCb, + void* userdata); +/* + * Create a new ktxTexture1. + */ +KTX_API KTX_error_code KTX_APIENTRY +ktxTexture1_Create(ktxTextureCreateInfo* createInfo, + ktxTextureCreateStorageEnum storageAllocation, + ktxTexture1** newTex); + +/* + * These four create a ktxTexture1 provided the data is in KTX format. + */ +KTX_API KTX_error_code KTX_APIENTRY +ktxTexture1_CreateFromStdioStream(FILE* stdioStream, + ktxTextureCreateFlags createFlags, + ktxTexture1** newTex); + +KTX_API KTX_error_code KTX_APIENTRY +ktxTexture1_CreateFromNamedFile(const char* const filename, + ktxTextureCreateFlags createFlags, + ktxTexture1** newTex); + +KTX_API KTX_error_code KTX_APIENTRY +ktxTexture1_CreateFromMemory(const ktx_uint8_t* bytes, ktx_size_t size, + ktxTextureCreateFlags createFlags, + ktxTexture1** newTex); + +KTX_API KTX_error_code KTX_APIENTRY +ktxTexture1_CreateFromStream(ktxStream* stream, + ktxTextureCreateFlags createFlags, + ktxTexture1** newTex); + +KTX_API ktx_bool_t KTX_APIENTRY +ktxTexture1_NeedsTranscoding(ktxTexture1* This); + +/* + * Write a ktxTexture object to a stdio stream in KTX format. + */ +KTX_API KTX_error_code KTX_APIENTRY +ktxTexture1_WriteKTX2ToStdioStream(ktxTexture1* This, FILE* dstsstr); + +/* + * Write a ktxTexture object to a named file in KTX format. + */ +KTX_API KTX_error_code KTX_APIENTRY +ktxTexture1_WriteKTX2ToNamedFile(ktxTexture1* This, const char* const dstname); + +/* + * Write a ktxTexture object to a block of memory in KTX format. + */ +KTX_API KTX_error_code KTX_APIENTRY +ktxTexture1_WriteKTX2ToMemory(ktxTexture1* This, + ktx_uint8_t** bytes, ktx_size_t* size); + +/* + * Write a ktxTexture object to a ktxStream in KTX format. + */ +KTX_API KTX_error_code KTX_APIENTRY +ktxTexture1_WriteKTX2ToStream(ktxTexture1* This, ktxStream *dststr); + +/* + * Create a new ktxTexture2. + */ +KTX_API KTX_error_code KTX_APIENTRY +ktxTexture2_Create(ktxTextureCreateInfo* createInfo, + ktxTextureCreateStorageEnum storageAllocation, + ktxTexture2** newTex); + +/* + * Create a new ktxTexture2 as a copy of an existing texture. + */ +KTX_API KTX_error_code KTX_APIENTRY +ktxTexture2_CreateCopy(ktxTexture2* orig, ktxTexture2** newTex); + + /* + * These four create a ktxTexture2 provided the data is in KTX2 format. + */ +KTX_API KTX_error_code KTX_APIENTRY +ktxTexture2_CreateFromStdioStream(FILE* stdioStream, + ktxTextureCreateFlags createFlags, + ktxTexture2** newTex); + +KTX_API KTX_error_code KTX_APIENTRY +ktxTexture2_CreateFromNamedFile(const char* const filename, + ktxTextureCreateFlags createFlags, + ktxTexture2** newTex); + +KTX_API KTX_error_code KTX_APIENTRY +ktxTexture2_CreateFromMemory(const ktx_uint8_t* bytes, ktx_size_t size, + ktxTextureCreateFlags createFlags, + ktxTexture2** newTex); + +KTX_API KTX_error_code KTX_APIENTRY +ktxTexture2_CreateFromStream(ktxStream* stream, + ktxTextureCreateFlags createFlags, + ktxTexture2** newTex); + +KTX_API KTX_error_code KTX_APIENTRY +ktxTexture2_CompressBasis(ktxTexture2* This, ktx_uint32_t quality); + +KTX_API KTX_error_code KTX_APIENTRY +ktxTexture2_DeflateZstd(ktxTexture2* This, ktx_uint32_t level); + +KTX_API void KTX_APIENTRY +ktxTexture2_GetComponentInfo(ktxTexture2* This, ktx_uint32_t* numComponents, + ktx_uint32_t* componentByteLength); + +KTX_API ktx_uint32_t KTX_APIENTRY +ktxTexture2_GetNumComponents(ktxTexture2* This); + +KTX_API khr_df_transfer_e KTX_APIENTRY +ktxTexture2_GetOETF_e(ktxTexture2* This); + +// For backward compatibility +KTX_API ktx_uint32_t KTX_APIENTRY +ktxTexture2_GetOETF(ktxTexture2* This); + +KTX_API khr_df_model_e KTX_APIENTRY +ktxTexture2_GetColorModel_e(ktxTexture2* This); + +KTX_API ktx_bool_t KTX_APIENTRY +ktxTexture2_GetPremultipliedAlpha(ktxTexture2* This); + +KTX_API ktx_bool_t KTX_APIENTRY +ktxTexture2_NeedsTranscoding(ktxTexture2* This); + +/** + * @~English + * @brief Flags specifiying UASTC encoding options. + */ +typedef enum ktx_pack_uastc_flag_bits_e { + KTX_PACK_UASTC_LEVEL_FASTEST = 0, + /*!< Fastest compression. 43.45dB. */ + KTX_PACK_UASTC_LEVEL_FASTER = 1, + /*!< Faster compression. 46.49dB. */ + KTX_PACK_UASTC_LEVEL_DEFAULT = 2, + /*!< Default compression. 47.47dB. */ + KTX_PACK_UASTC_LEVEL_SLOWER = 3, + /*!< Slower compression. 48.01dB. */ + KTX_PACK_UASTC_LEVEL_VERYSLOW = 4, + /*!< Very slow compression. 48.24dB. */ + KTX_PACK_UASTC_MAX_LEVEL = KTX_PACK_UASTC_LEVEL_VERYSLOW, + /*!< Maximum supported quality level. */ + KTX_PACK_UASTC_LEVEL_MASK = 0xF, + /*!< Mask to extract the level from the other bits. */ + KTX_PACK_UASTC_FAVOR_UASTC_ERROR = 8, + /*!< Optimize for lowest UASTC error. */ + KTX_PACK_UASTC_FAVOR_BC7_ERROR = 16, + /*!< Optimize for lowest BC7 error. */ + KTX_PACK_UASTC_ETC1_FASTER_HINTS = 64, + /*!< Optimize for faster transcoding to ETC1. */ + KTX_PACK_UASTC_ETC1_FASTEST_HINTS = 128, + /*!< Optimize for fastest transcoding to ETC1. */ + KTX_PACK_UASTC__ETC1_DISABLE_FLIP_AND_INDIVIDUAL = 256 + /*!< Not documented in BasisU code. */ +} ktx_pack_uastc_flag_bits_e; +typedef ktx_uint32_t ktx_pack_uastc_flags; + +/** + * @~English + * @brief Options specifiying ASTC encoding quality levels. + */ +typedef enum ktx_pack_astc_quality_levels_e { + KTX_PACK_ASTC_QUALITY_LEVEL_FASTEST = 0, + /*!< Fastest compression. */ + KTX_PACK_ASTC_QUALITY_LEVEL_FAST = 10, + /*!< Fast compression. */ + KTX_PACK_ASTC_QUALITY_LEVEL_MEDIUM = 60, + /*!< Medium compression. */ + KTX_PACK_ASTC_QUALITY_LEVEL_THOROUGH = 98, + /*!< Slower compression. */ + KTX_PACK_ASTC_QUALITY_LEVEL_EXHAUSTIVE = 100, + /*!< Very slow compression. */ + KTX_PACK_ASTC_QUALITY_LEVEL_MAX = KTX_PACK_ASTC_QUALITY_LEVEL_EXHAUSTIVE, + /*!< Maximum supported quality level. */ +} ktx_pack_astc_quality_levels_e; + +/** + * @~English + * @brief Options specifiying ASTC encoding block dimensions + */ +typedef enum ktx_pack_astc_block_dimension_e { + // 2D formats + KTX_PACK_ASTC_BLOCK_DIMENSION_4x4, //: 8.00 bpp + KTX_PACK_ASTC_BLOCK_DIMENSION_5x4, //: 6.40 bpp + KTX_PACK_ASTC_BLOCK_DIMENSION_5x5, //: 5.12 bpp + KTX_PACK_ASTC_BLOCK_DIMENSION_6x5, //: 4.27 bpp + KTX_PACK_ASTC_BLOCK_DIMENSION_6x6, //: 3.56 bpp + KTX_PACK_ASTC_BLOCK_DIMENSION_8x5, //: 3.20 bpp + KTX_PACK_ASTC_BLOCK_DIMENSION_8x6, //: 2.67 bpp + KTX_PACK_ASTC_BLOCK_DIMENSION_10x5, //: 2.56 bpp + KTX_PACK_ASTC_BLOCK_DIMENSION_10x6, //: 2.13 bpp + KTX_PACK_ASTC_BLOCK_DIMENSION_8x8, //: 2.00 bpp + KTX_PACK_ASTC_BLOCK_DIMENSION_10x8, //: 1.60 bpp + KTX_PACK_ASTC_BLOCK_DIMENSION_10x10, //: 1.28 bpp + KTX_PACK_ASTC_BLOCK_DIMENSION_12x10, //: 1.07 bpp + KTX_PACK_ASTC_BLOCK_DIMENSION_12x12, //: 0.89 bpp + // 3D formats + KTX_PACK_ASTC_BLOCK_DIMENSION_3x3x3, //: 4.74 bpp + KTX_PACK_ASTC_BLOCK_DIMENSION_4x3x3, //: 3.56 bpp + KTX_PACK_ASTC_BLOCK_DIMENSION_4x4x3, //: 2.67 bpp + KTX_PACK_ASTC_BLOCK_DIMENSION_4x4x4, //: 2.00 bpp + KTX_PACK_ASTC_BLOCK_DIMENSION_5x4x4, //: 1.60 bpp + KTX_PACK_ASTC_BLOCK_DIMENSION_5x5x4, //: 1.28 bpp + KTX_PACK_ASTC_BLOCK_DIMENSION_5x5x5, //: 1.02 bpp + KTX_PACK_ASTC_BLOCK_DIMENSION_6x5x5, //: 0.85 bpp + KTX_PACK_ASTC_BLOCK_DIMENSION_6x6x5, //: 0.71 bpp + KTX_PACK_ASTC_BLOCK_DIMENSION_6x6x6, //: 0.59 bpp + KTX_PACK_ASTC_BLOCK_DIMENSION_MAX = KTX_PACK_ASTC_BLOCK_DIMENSION_6x6x6 + /*!< Maximum supported blocks. */ +} ktx_pack_astc_block_dimension_e; + +/** + * @~English + * @brief Options specifying ASTC encoder profile mode + * This and function is used later to derive the profile. + */ +typedef enum ktx_pack_astc_encoder_mode_e { + KTX_PACK_ASTC_ENCODER_MODE_DEFAULT, + KTX_PACK_ASTC_ENCODER_MODE_LDR, + KTX_PACK_ASTC_ENCODER_MODE_HDR, + KTX_PACK_ASTC_ENCODER_MODE_MAX = KTX_PACK_ASTC_ENCODER_MODE_HDR +} ktx_pack_astc_encoder_mode_e; + +extern KTX_API const ktx_uint32_t KTX_ETC1S_DEFAULT_COMPRESSION_LEVEL; + +/** + * @memberof ktxTexture + * @~English + * @brief Structure for passing extended parameters to + * ktxTexture_CompressAstc. + * + * Passing a struct initialized to 0 (e.g. " = {0};") will use blockDimension + * 4x4, mode LDR and qualityLevel FASTEST. Setting qualityLevel to + * KTX_PACK_ASTC_QUALITY_LEVEL_MEDIUM is recommended. + */ +typedef struct ktxAstcParams { + ktx_uint32_t structSize; + /*!< Size of this struct. Used so library can tell which version + of struct is being passed. + */ + + ktx_bool_t verbose; + /*!< If true, prints Astc encoder operation details to + @c stdout. Not recommended for GUI apps. + */ + + ktx_uint32_t threadCount; + /*!< Number of threads used for compression. Default is 1. + */ + + /* astcenc params */ + ktx_uint32_t blockDimension; + /*!< Combinations of block dimensions that astcenc supports + i.e. 6x6, 8x8, 6x5 etc + */ + + ktx_uint32_t mode; + /*!< Can be {ldr/hdr} from astcenc + */ + + ktx_uint32_t qualityLevel; + /*!< astcenc supports -fastest, -fast, -medium, -thorough, -exhaustive + */ + + ktx_bool_t normalMap; + /*!< Tunes codec parameters for better quality on normal maps + In this mode normals are compressed to X,Y components + Discarding Z component, reader will need to generate Z + component in shaders. + */ + + ktx_bool_t perceptual; + /*!< The codec should optimize for perceptual error, instead of direct + RMS error. This aims to improves perceived image quality, but + typically lowers the measured PSNR score. Perceptual methods are + currently only available for normal maps and RGB color data. + */ + + char inputSwizzle[4]; + /*!< A swizzle to provide as input to astcenc. It must match the regular + expression /^[rgba01]{4}$/. + */ +} ktxAstcParams; + +KTX_API KTX_error_code KTX_APIENTRY +ktxTexture2_CompressAstcEx(ktxTexture2* This, ktxAstcParams* params); + +KTX_API KTX_error_code KTX_APIENTRY +ktxTexture2_CompressAstc(ktxTexture2* This, ktx_uint32_t quality); + +/** + * @memberof ktxTexture2 + * @~English + * @brief Structure for passing extended parameters to + * ktxTexture2_CompressBasisEx(). + * + * If you only want default values, use ktxTexture2_CompressBasis(). Here, at a minimum you + * must initialize the structure as follows: + * @code + * ktxBasisParams params = {0}; + * params.structSize = sizeof(params); + * params.compressionLevel = KTX_ETC1S_DEFAULT_COMPRESSION_LEVEL; + * @endcode + * + * @e compressionLevel has to be explicitly set because 0 is a valid @e compressionLevel + * but is not the default used by the BasisU encoder when no value is set. Only the other + * settings that are to be non-default must be non-zero. + */ +typedef struct ktxBasisParams { + ktx_uint32_t structSize; + /*!< Size of this struct. Used so library can tell which version + of struct is being passed. + */ + ktx_bool_t uastc; + /*!< True to use UASTC base, false to use ETC1S base. */ + ktx_bool_t verbose; + /*!< If true, prints Basis Universal encoder operation details to + @c stdout. Not recommended for GUI apps. + */ + ktx_bool_t noSSE; + /*!< True to forbid use of the SSE instruction set. Ignored if CPU + does not support SSE. */ + ktx_uint32_t threadCount; + /*!< Number of threads used for compression. Default is 1. */ + + /* ETC1S params */ + + ktx_uint32_t compressionLevel; + /*!< Encoding speed vs. quality tradeoff. Range is [0,5]. Higher values + are slower, but give higher quality. There is no default. Callers + must explicitly set this value. Callers can use + KTX_ETC1S_DEFAULT_COMPRESSION_LEVEL as a default value. + Currently this is 2. + */ + ktx_uint32_t qualityLevel; + /*!< Compression quality. Range is [1,255]. Lower gives better + compression/lower quality/faster. Higher gives less compression + /higher quality/slower. This automatically determines values for + @c maxEndpoints, @c maxSelectors, + @c endpointRDOThreshold and @c selectorRDOThreshold + for the target quality level. Setting these parameters overrides + the values determined by @c qualityLevel which defaults to + 128 if neither it nor both of @c maxEndpoints and + @c maxSelectors have been set. + @note @e Both of @c maxEndpoints and @c maxSelectors + must be set for them to have any effect. + @note qualityLevel will only determine values for + @c endpointRDOThreshold and @c selectorRDOThreshold + when its value exceeds 128, otherwise their defaults will be used. + */ + ktx_uint32_t maxEndpoints; + /*!< Manually set the max number of color endpoint clusters. + Range is [1,16128]. Default is 0, unset. If this is set, maxSelectors + must also be set, otherwise the value will be ignored. + */ + float endpointRDOThreshold; + /*!< Set endpoint RDO quality threshold. The default is 1.25. Lower is + higher quality but less quality per output bit (try [1.0,3.0]. + This will override the value chosen by @c qualityLevel. + */ + ktx_uint32_t maxSelectors; + /*!< Manually set the max number of color selector clusters. Range + is [1,16128]. Default is 0, unset. If this is set, maxEndpoints + must also be set, otherwise the value will be ignored. + */ + float selectorRDOThreshold; + /*!< Set selector RDO quality threshold. The default is 1.5. Lower is + higher quality but less quality per output bit (try [1.0,3.0]). + This will override the value chosen by @c qualityLevel. + */ + char inputSwizzle[4]; + /*!< A swizzle to apply before encoding. It must match the regular + expression /^[rgba01]{4}$/. If both this and preSwizzle + are specified ktxTexture_CompressBasisEx will raise + KTX_INVALID_OPERATION. + */ + ktx_bool_t normalMap; + /*!< Tunes codec parameters for better quality on normal maps (no + selector RDO, no endpoint RDO) and sets the texture's DFD appropriately. + Only valid for linear textures. + */ + ktx_bool_t separateRGToRGB_A; + /*!< @deprecated. This was and is a no-op. 2-component inputs have always been + automatically separated using an "rrrg" inputSwizzle. @sa inputSwizzle and normalMode. + */ + ktx_bool_t preSwizzle; + /*!< If the texture has @c KTXswizzle metadata, apply it before + compressing. Swizzling, like @c rabb may yield drastically + different error metrics if done after supercompression. + */ + ktx_bool_t noEndpointRDO; + /*!< Disable endpoint rate distortion optimizations. Slightly faster, + less noisy output, but lower quality per output bit. Default is + KTX_FALSE. + */ + ktx_bool_t noSelectorRDO; + /*!< Disable selector rate distortion optimizations. Slightly faster, + less noisy output, but lower quality per output bit. Default is + KTX_FALSE. + */ + + /* UASTC params */ + + ktx_pack_uastc_flags uastcFlags; + /*!< A set of ::ktx_pack_uastc_flag_bits_e controlling UASTC + encoding. The most important value is the level given in the + least-significant 4 bits which selects a speed vs quality tradeoff + as shown in the following table: + + Level/Speed | Quality + :-----: | :-------: + KTX_PACK_UASTC_LEVEL_FASTEST | 43.45dB + KTX_PACK_UASTC_LEVEL_FASTER | 46.49dB + KTX_PACK_UASTC_LEVEL_DEFAULT | 47.47dB + KTX_PACK_UASTC_LEVEL_SLOWER | 48.01dB + KTX_PACK_UASTC_LEVEL_VERYSLOW | 48.24dB + */ + ktx_bool_t uastcRDO; + /*!< Enable Rate Distortion Optimization (RDO) post-processing. + */ + float uastcRDOQualityScalar; + /*!< UASTC RDO quality scalar (lambda). Lower values yield higher + quality/larger LZ compressed files, higher values yield lower + quality/smaller LZ compressed files. A good range to try is [.2,4]. + Full range is [.001,50.0]. Default is 1.0. + */ + ktx_uint32_t uastcRDODictSize; + /*!< UASTC RDO dictionary size in bytes. Default is 4096. Lower + values=faster, but give less compression. Range is [64,65536]. + */ + float uastcRDOMaxSmoothBlockErrorScale; + /*!< UASTC RDO max smooth block error scale. Range is [1,300]. + Default is 10.0, 1.0 is disabled. Larger values suppress more + artifacts (and allocate more bits) on smooth blocks. + */ + float uastcRDOMaxSmoothBlockStdDev; + /*!< UASTC RDO max smooth block standard deviation. Range is + [.01,65536.0]. Default is 18.0. Larger values expand the range of + blocks considered smooth. + */ + ktx_bool_t uastcRDODontFavorSimplerModes; + /*!< Do not favor simpler UASTC modes in RDO mode. + */ + ktx_bool_t uastcRDONoMultithreading; + /*!< Disable RDO multithreading (slightly higher compression, + deterministic). + */ + +} ktxBasisParams; + +KTX_API KTX_error_code KTX_APIENTRY +ktxTexture2_CompressBasisEx(ktxTexture2* This, ktxBasisParams* params); + +/** + * @~English + * @brief Enumerators for specifying the transcode target format. + * + * For BasisU/ETC1S format, @e Opaque and @e alpha here refer to 2 separate + * RGB images, a.k.a slices within the BasisU compressed data. For UASTC + * format they refer to the RGB and the alpha components of the UASTC data. If + * the original image had only 2 components, R will be in the opaque portion + * and G in the alpha portion. The R value will be replicated in the RGB + * components. In the case of BasisU the G value will be replicated in all 3 + * components of the alpha slice. If the original image had only 1 component + * it's value is replicated in all 3 components of the opaque portion and + * there is no alpha. + * + * @note You should not transcode sRGB encoded data to @c KTX_TTF_BC4_R, + * @c KTX_TTF_BC5_RG, @c KTX_TTF_ETC2_EAC_R{,G}11, @c KTX_TTF_RGB565, + * @c KTX_TTF_BGR565 or @c KTX_TTF_RGBA4444 formats as neither OpenGL nor + * Vulkan support sRGB variants of these. Doing sRGB decoding in the shader + * will not produce correct results if any texture filtering is being used. + */ +typedef enum ktx_transcode_fmt_e { + // Compressed formats + + // ETC1-2 + KTX_TTF_ETC1_RGB = 0, + /*!< Opaque only. Returns RGB or alpha data, if + KTX_TF_TRANSCODE_ALPHA_DATA_TO_OPAQUE_FORMATS flag is + specified. */ + KTX_TTF_ETC2_RGBA = 1, + /*!< Opaque+alpha. EAC_A8 block followed by an ETC1 block. The + alpha channel will be opaque for textures without an alpha + channel. */ + + // BC1-5, BC7 (desktop, some mobile devices) + KTX_TTF_BC1_RGB = 2, + /*!< Opaque only, no punchthrough alpha support yet. Returns RGB + or alpha data, if KTX_TF_TRANSCODE_ALPHA_DATA_TO_OPAQUE_FORMATS + flag is specified. */ + KTX_TTF_BC3_RGBA = 3, + /*!< Opaque+alpha. BC4 block with alpha followed by a BC1 block. The + alpha channel will be opaque for textures without an alpha + channel. */ + KTX_TTF_BC4_R = 4, + /*!< One BC4 block. R = opaque.g or alpha.g, if + KTX_TF_TRANSCODE_ALPHA_DATA_TO_OPAQUE_FORMATS flag is + specified. */ + KTX_TTF_BC5_RG = 5, + /*!< Two BC4 blocks, R=opaque.g and G=alpha.g The texture should + have an alpha channel (if not G will be all 255's. For tangent + space normal maps. */ + KTX_TTF_BC7_RGBA = 6, + /*!< RGB or RGBA mode 5 for ETC1S, modes 1, 2, 3, 4, 5, 6, 7 for + UASTC. */ + + // PVRTC1 4bpp (mobile, PowerVR devices) + KTX_TTF_PVRTC1_4_RGB = 8, + /*!< Opaque only. Returns RGB or alpha data, if + KTX_TF_TRANSCODE_ALPHA_DATA_TO_OPAQUE_FORMATS flag is + specified. */ + KTX_TTF_PVRTC1_4_RGBA = 9, + /*!< Opaque+alpha. Most useful for simple opacity maps. If the + texture doesn't have an alpha channel KTX_TTF_PVRTC1_4_RGB + will be used instead. Lowest quality of any supported + texture format. */ + + // ASTC (mobile, Intel devices, hopefully all desktop GPU's one day) + KTX_TTF_ASTC_4x4_RGBA = 10, + /*!< Opaque+alpha, ASTC 4x4. The alpha channel will be opaque for + textures without an alpha channel. The transcoder uses + RGB/RGBA/L/LA modes, void extent, and up to two ([0,47] and + [0,255]) endpoint precisions. */ + + // ATC and FXT1 formats are not supported by KTX2 as there + // are no equivalent VkFormats. + + KTX_TTF_PVRTC2_4_RGB = 18, + /*!< Opaque-only. Almost BC1 quality, much faster to transcode + and supports arbitrary texture dimensions (unlike + PVRTC1 RGB). */ + KTX_TTF_PVRTC2_4_RGBA = 19, + /*!< Opaque+alpha. Slower to transcode than cTFPVRTC2_4_RGB. + Premultiplied alpha is highly recommended, otherwise the + color channel can leak into the alpha channel on transparent + blocks. */ + + KTX_TTF_ETC2_EAC_R11 = 20, + /*!< R only (ETC2 EAC R11 unsigned). R = opaque.g or alpha.g, if + KTX_TF_TRANSCODE_ALPHA_DATA_TO_OPAQUE_FORMATS flag is + specified. */ + KTX_TTF_ETC2_EAC_RG11 = 21, + /*!< RG only (ETC2 EAC RG11 unsigned), R=opaque.g, G=alpha.g. The + texture should have an alpha channel (if not G will be all + 255's. For tangent space normal maps. */ + + // Uncompressed (raw pixel) formats + KTX_TTF_RGBA32 = 13, + /*!< 32bpp RGBA image stored in raster (not block) order in + memory, R is first byte, A is last byte. */ + KTX_TTF_RGB565 = 14, + /*!< 16bpp RGB image stored in raster (not block) order in memory, + R at bit position 11. */ + KTX_TTF_BGR565 = 15, + /*!< 16bpp RGB image stored in raster (not block) order in memory, + R at bit position 0. */ + KTX_TTF_RGBA4444 = 16, + /*!< 16bpp RGBA image stored in raster (not block) order in memory, + R at bit position 12, A at bit position 0. */ + + // Values for automatic selection of RGB or RGBA depending if alpha + // present. + KTX_TTF_ETC = 22, + /*!< Automatically selects @c KTX_TTF_ETC1_RGB or + @c KTX_TTF_ETC2_RGBA according to presence of alpha. */ + KTX_TTF_BC1_OR_3 = 23, + /*!< Automatically selects @c KTX_TTF_BC1_RGB or + @c KTX_TTF_BC3_RGBA according to presence of alpha. */ + + KTX_TTF_NOSELECTION = 0x7fffffff, + + // Old enums for compatibility with code compiled against previous + // versions of libktx. + KTX_TF_ETC1 = KTX_TTF_ETC1_RGB, + //!< @deprecated. Use #KTX_TTF_ETC1_RGB. + KTX_TF_ETC2 = KTX_TTF_ETC, + //!< @deprecated. Use #KTX_TTF_ETC. + KTX_TF_BC1 = KTX_TTF_BC1_RGB, + //!< @deprecated. Use #KTX_TTF_BC1_RGB. + KTX_TF_BC3 = KTX_TTF_BC3_RGBA, + //!< @deprecated. Use #KTX_TTF_BC3_RGBA. + KTX_TF_BC4 = KTX_TTF_BC4_R, + //!< @deprecated. Use #KTX_TTF_BC4_R. + KTX_TF_BC5 = KTX_TTF_BC5_RG, + //!< @deprecated. Use #KTX_TTF_BC5_RG. + KTX_TTF_BC7_M6_RGB = KTX_TTF_BC7_RGBA, + //!< @deprecated. Use #KTX_TTF_BC7_RGBA. + KTX_TTF_BC7_M5_RGBA = KTX_TTF_BC7_RGBA, + //!< @deprecated. Use #KTX_TTF_BC7_RGBA. + KTX_TF_BC7_M6_OPAQUE_ONLY = KTX_TTF_BC7_RGBA, + //!< @deprecated. Use #KTX_TTF_BC7_RGBA + KTX_TF_PVRTC1_4_OPAQUE_ONLY = KTX_TTF_PVRTC1_4_RGB + //!< @deprecated. Use #KTX_TTF_PVRTC1_4_RGB. +} ktx_transcode_fmt_e; + +/** + * @~English + * @brief Flags guiding transcoding of Basis Universal compressed textures. + */ +typedef enum ktx_transcode_flag_bits_e { + KTX_TF_PVRTC_DECODE_TO_NEXT_POW2 = 2, + /*!< PVRTC1: decode non-pow2 ETC1S texture level to the next larger + power of 2 (not implemented yet, but we're going to support it). + Ignored if the slice's dimensions are already a power of 2. + */ + KTX_TF_TRANSCODE_ALPHA_DATA_TO_OPAQUE_FORMATS = 4, + /*!< When decoding to an opaque texture format, if the Basis data has + alpha, decode the alpha slice instead of the color slice to the + output texture format. Has no effect if there is no alpha data. + */ + KTX_TF_HIGH_QUALITY = 32, + /*!< Request higher quality transcode of UASTC to BC1, BC3, ETC2_EAC_R11 and + ETC2_EAC_RG11. The flag is unused by other UASTC transcoders. + */ +} ktx_transcode_flag_bits_e; +typedef ktx_uint32_t ktx_transcode_flags; + +KTX_API KTX_error_code KTX_APIENTRY +ktxTexture2_TranscodeBasis(ktxTexture2* This, ktx_transcode_fmt_e fmt, + ktx_transcode_flags transcodeFlags); + +/* + * Returns a string corresponding to a KTX error code. + */ +KTX_API const char* KTX_APIENTRY +ktxErrorString(KTX_error_code error); + +/* + * Returns a string corresponding to a supercompression scheme. + */ +KTX_API const char* KTX_APIENTRY +ktxSupercompressionSchemeString(ktxSupercmpScheme scheme); + +/* + * Returns a string corresponding to a transcode target format. + */ +KTX_API const char* KTX_APIENTRY +ktxTranscodeFormatString(ktx_transcode_fmt_e format); + +KTX_API KTX_error_code KTX_APIENTRY ktxHashList_Create(ktxHashList** ppHl); +KTX_API KTX_error_code KTX_APIENTRY +ktxHashList_CreateCopy(ktxHashList** ppHl, ktxHashList orig); +KTX_API void KTX_APIENTRY ktxHashList_Construct(ktxHashList* pHl); +KTX_API void KTX_APIENTRY +ktxHashList_ConstructCopy(ktxHashList* pHl, ktxHashList orig); +KTX_API void KTX_APIENTRY ktxHashList_Destroy(ktxHashList* head); +KTX_API void KTX_APIENTRY ktxHashList_Destruct(ktxHashList* head); + +/* + * Adds a key-value pair to a hash list. + */ +KTX_API KTX_error_code KTX_APIENTRY +ktxHashList_AddKVPair(ktxHashList* pHead, const char* key, + unsigned int valueLen, const void* value); + +/* + * Deletes a ktxHashListEntry from a ktxHashList. + */ +KTX_API KTX_error_code KTX_APIENTRY +ktxHashList_DeleteEntry(ktxHashList* pHead, ktxHashListEntry* pEntry); + +/* + * Finds the entry for a key in a ktxHashList and deletes it. + */ +KTX_API KTX_error_code KTX_APIENTRY +ktxHashList_DeleteKVPair(ktxHashList* pHead, const char* key); + +/* + * Looks up a key and returns the ktxHashListEntry. + */ +KTX_API KTX_error_code KTX_APIENTRY +ktxHashList_FindEntry(ktxHashList* pHead, const char* key, + ktxHashListEntry** ppEntry); + +/* + * Looks up a key and returns the value. + */ +KTX_API KTX_error_code KTX_APIENTRY +ktxHashList_FindValue(ktxHashList* pHead, const char* key, + unsigned int* pValueLen, void** pValue); + +/* + * Return the next entry in a ktxHashList. + */ +KTX_API ktxHashListEntry* KTX_APIENTRY +ktxHashList_Next(ktxHashListEntry* entry); + +/* + * Sorts a ktxHashList into order of the key codepoints. + */ +KTX_API KTX_error_code KTX_APIENTRY +ktxHashList_Sort(ktxHashList* pHead); + +/* + * Serializes a ktxHashList to a block of memory suitable for + * writing to a KTX file. + */ +KTX_API KTX_error_code KTX_APIENTRY +ktxHashList_Serialize(ktxHashList* pHead, + unsigned int* kvdLen, unsigned char** kvd); + +/* + * Creates a hash table from the serialized data read from a + * a KTX file. + */ +KTX_API KTX_error_code KTX_APIENTRY +ktxHashList_Deserialize(ktxHashList* pHead, unsigned int kvdLen, void* kvd); + +/* + * Get the key from a ktxHashListEntry + */ +KTX_API KTX_error_code KTX_APIENTRY +ktxHashListEntry_GetKey(ktxHashListEntry* This, + unsigned int* pKeyLen, char** ppKey); + +/* + * Get the value from a ktxHashListEntry + */ +KTX_API KTX_error_code KTX_APIENTRY +ktxHashListEntry_GetValue(ktxHashListEntry* This, + unsigned int* pValueLen, void** ppValue); + +/*===========================================================* + * Utilities for printing info about a KTX file. * + *===========================================================*/ + +KTX_API KTX_error_code KTX_APIENTRY ktxPrintInfoForStdioStream(FILE* stdioStream); +KTX_API KTX_error_code KTX_APIENTRY ktxPrintInfoForNamedFile(const char* const filename); +KTX_API KTX_error_code KTX_APIENTRY ktxPrintInfoForMemory(const ktx_uint8_t* bytes, ktx_size_t size); + +#ifdef __cplusplus +} +#endif + +/*========================================================================* + * For backward compatibilty with the V3 & early versions of the V4 APIs. * + *========================================================================*/ + +/** + * @deprecated Will be dropped before V4 release. + */ +#define ktx_texture_transcode_fmt_e ktx_transcode_fmt_e + +/** + * @deprecated Will be dropped before V4 release. + */ +#define ktx_texture_decode_flags ktx_transcode_flag_bits + +/** + * @deprecated Will be dropped before V4 release. + */ +#define ktxTexture_GetSize ktxTexture_GetDatasize + +/** +@~English +@page libktx_history Revision History + +@section v8 Version 4.0 +Added: +@li Support for KTX Version 2. +@li Support for encoding and transcoding Basis Universal images in KTX Version 2 files. +@li Function to print info about a KTX file. + +@section v7 Version 3.0.1 +Fixed: +@li GitHub issue #159: compile failure with recent Vulkan SDKs. +@li Incorrect mapping of GL DXT3 and DXT5 formats to Vulkan equivalents. +@li Incorrect BC4 blocksize. +@li Missing mapping of PVRTC formats from GL to Vulkan. +@li Incorrect block width and height calculations for sizes that are not + a multiple of the block size. +@li Incorrect KTXorientation key in test images. + +@section v6 Version 3.0 +Added: +@li new ktxTexture object based API for reading KTX files without an OpenGL context. +@li Vulkan loader. @#include to use it. + +Changed: +@li ktx.h to not depend on KHR/khrplatform.h and GL{,ES*}/gl{corearb,}.h. + Applications using OpenGL must now include these files themselves. +@li ktxLoadTexture[FMN], removing the hack of loading 1D textures as 2D textures + when the OpenGL context does not support 1D textures. + KTX_UNSUPPORTED_TEXTURE_TYPE is now returned. + +@section v5 Version 2.0.2 +Added: +@li Support for cubemap arrays. + +Changed: +@li New build system + +Fixed: +@li GitHub issue #40: failure to byte-swap key-value lengths. +@li GitHub issue #33: returning incorrect target when loading cubemaps. +@li GitHub PR #42: loading of texture arrays. +@li GitHub PR #41: compilation error when KTX_OPENGL_ES2=1 defined. +@li GitHub issue #39: stack-buffer-overflow in toktx +@li Don't use GL_EXTENSIONS on recent OpenGL versions. + +@section v4 Version 2.0.1 +Added: +@li CMake build files. Thanks to Pavel Rotjberg for the initial version. + +Changed: +@li ktxWriteKTXF to check the validity of the type & format combinations + passed to it. + +Fixed: +@li Public Bugzilla 999: 16-bit luminance texture cannot be written. +@li compile warnings from compilers stricter than MS Visual C++. Thanks to + Pavel Rotjberg. + +@section v3 Version 2.0 +Added: +@li support for decoding ETC2 and EAC formats in the absence of a hardware + decoder. +@li support for converting textures with legacy LUMINANCE, LUMINANCE_ALPHA, + etc. formats to the equivalent R, RG, etc. format with an + appropriate swizzle, when loading in OpenGL Core Profile contexts. +@li ktxErrorString function to return a string corresponding to an error code. +@li tests for ktxLoadTexture[FN] that run under OpenGL ES 3.0 and OpenGL 3.3. + The latter includes an EGL on WGL wrapper that makes porting apps between + OpenGL ES and OpenGL easier on Windows. +@li more texture formats to ktxLoadTexture[FN] and toktx tests. + +Changed: +@li ktxLoadTexture[FMN] to discover the capabilities of the GL context at + run time and load textures, or not, according to those capabilities. + +Fixed: +@li failure of ktxWriteKTXF to pad image rows to 4 bytes as required by the KTX + format. +@li ktxWriteKTXF exiting with KTX_FILE_WRITE_ERROR when attempting to write + more than 1 byte of face-LOD padding. + +Although there is only a very minor API change, the addition of ktxErrorString, +the functional changes are large enough to justify bumping the major revision +number. + +@section v2 Version 1.0.1 +Implemented ktxLoadTextureM. +Fixed the following: +@li Public Bugzilla 571: crash when null passed for pIsMipmapped. +@li Public Bugzilla 572: memory leak when unpacking ETC textures. +@li Public Bugzilla 573: potential crash when unpacking ETC textures with unused padding pixels. +@li Public Bugzilla 576: various small fixes. + +Thanks to Krystian Bigaj for the ktxLoadTextureM implementation and these fixes. + +@section v1 Version 1.0 +Initial release. + +*/ + +#endif /* KTX_H_A55A6F00956F42F3A137C11929827FE1 */ diff --git a/thirdparty/libktx/include/ktxvulkan.h b/thirdparty/libktx/include/ktxvulkan.h new file mode 100644 index 000000000000..e695ee6863d7 --- /dev/null +++ b/thirdparty/libktx/include/ktxvulkan.h @@ -0,0 +1,253 @@ +/* -*- tab-width: 4; -*- */ +/* vi: set sw=2 ts=4 expandtab: */ + +#ifndef KTX_H_C54B42AEE39611E68E1E4FF8C51D1C66 +#define KTX_H_C54B42AEE39611E68E1E4FF8C51D1C66 + +/* + * Copyright 2017-2020 The Khronos Group, Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @internal + * @file + * @~English + * + * @brief Declares the public functions and structures of the + * KTX Vulkan texture loading API. + * + * A separate header file is used to avoid extra dependencies for those not + * using Vulkan. The nature of the Vulkan API, rampant structures and enums, + * means that vulkan.h must be included @e before including this file. The + * alternative is duplicating unattractively large parts of it. + * + * @author Mark Callow, Edgewise Consulting + * + * $Date$ + */ + +#include + +#if 0 +/* Avoid Vulkan include file */ +#define VK_DEFINE_HANDLE(object) typedef struct object##_T* object; + +#if defined(__LP64__) || defined(_WIN64) || defined(__x86_64__) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__) + #define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef struct object##_T *object; +#else + #define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef uint64_t object; +#endif + +VK_DEFINE_HANDLE(VkPhysicalDevice) +VK_DEFINE_HANDLE(VkDevice) +VK_DEFINE_HANDLE(VkQueue) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkCommandPool) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDeviceMemory) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkImage) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkImageView) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSampler) +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @struct ktxVulkanFunctions + * @~English + * @brief Struct for applications to pass Vulkan function pointers to the + * ktxTexture_VkUpload functions via a ktxVulkanDeviceInfo struct. + * + * @c vkGetInstanceProcAddr and @c vkGetDeviceProcAddr should be set, others + * are optional. + */ +typedef struct ktxVulkanFunctions { + // These are functions pointers we need to perform our vulkan duties. + PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr; + PFN_vkGetDeviceProcAddr vkGetDeviceProcAddr; + + // These we optionally specify + PFN_vkAllocateCommandBuffers vkAllocateCommandBuffers; + PFN_vkAllocateMemory vkAllocateMemory; + PFN_vkBeginCommandBuffer vkBeginCommandBuffer; + PFN_vkBindBufferMemory vkBindBufferMemory; + PFN_vkBindImageMemory vkBindImageMemory; + PFN_vkCmdBlitImage vkCmdBlitImage; + PFN_vkCmdCopyBufferToImage vkCmdCopyBufferToImage; + PFN_vkCmdPipelineBarrier vkCmdPipelineBarrier; + PFN_vkCreateImage vkCreateImage; + PFN_vkDestroyImage vkDestroyImage; + PFN_vkCreateBuffer vkCreateBuffer; + PFN_vkDestroyBuffer vkDestroyBuffer; + PFN_vkCreateFence vkCreateFence; + PFN_vkDestroyFence vkDestroyFence; + PFN_vkEndCommandBuffer vkEndCommandBuffer; + PFN_vkFreeCommandBuffers vkFreeCommandBuffers; + PFN_vkFreeMemory vkFreeMemory; + PFN_vkGetBufferMemoryRequirements vkGetBufferMemoryRequirements; + PFN_vkGetImageMemoryRequirements vkGetImageMemoryRequirements; + PFN_vkGetImageSubresourceLayout vkGetImageSubresourceLayout; + PFN_vkGetPhysicalDeviceImageFormatProperties vkGetPhysicalDeviceImageFormatProperties; + PFN_vkGetPhysicalDeviceFormatProperties vkGetPhysicalDeviceFormatProperties; + PFN_vkGetPhysicalDeviceMemoryProperties vkGetPhysicalDeviceMemoryProperties; + PFN_vkMapMemory vkMapMemory; + PFN_vkQueueSubmit vkQueueSubmit; + PFN_vkQueueWaitIdle vkQueueWaitIdle; + PFN_vkUnmapMemory vkUnmapMemory; + PFN_vkWaitForFences vkWaitForFences; +} ktxVulkanFunctions; + +/** + * @class ktxVulkanTexture + * @~English + * @brief Struct for returning information about the Vulkan texture image + * created by the ktxTexture_VkUpload* functions. + * + * Creation of these objects is internal to the upload functions. + */ +typedef struct ktxVulkanTexture +{ + PFN_vkDestroyImage vkDestroyImage; /*!< Pointer to vkDestroyImage function */ + PFN_vkFreeMemory vkFreeMemory; /*!< Pointer to vkFreeMemory function */ + + VkImage image; /*!< Handle to the Vulkan image created by the loader. */ + VkFormat imageFormat; /*!< Format of the image data. */ + VkImageLayout imageLayout; /*!< Layout of the created image. Has the same + value as @p layout parameter passed to the + loader. */ + VkDeviceMemory deviceMemory; /*!< The memory allocated for the image on + the Vulkan device. */ + VkImageViewType viewType; /*!< ViewType corresponding to @p image. Reflects + the dimensionality, cubeness and arrayness + of the image. */ + uint32_t width; /*!< The width of the image. */ + uint32_t height; /*!< The height of the image. */ + uint32_t depth; /*!< The depth of the image. */ + uint32_t levelCount; /*!< The number of MIP levels in the image. */ + uint32_t layerCount; /*!< The number of array layers in the image. */ +} ktxVulkanTexture; + +KTX_API void KTX_APIENTRY +ktxVulkanTexture_Destruct(ktxVulkanTexture* This, VkDevice device, + const VkAllocationCallbacks* pAllocator); + + + + +/** + * @class ktxVulkanDeviceInfo + * @~English + * @brief Struct for passing information about the Vulkan device on which + * to create images to the texture image loading functions. + * + * Avoids passing a large number of parameters to each loading function. + * Use of ktxVulkanDeviceInfo_create() or ktxVulkanDeviceInfo_construct() to + * populate this structure is highly recommended. + * + * @code + ktxVulkanDeviceInfo vdi; + ktxVulkanTexture texture; + + vdi = ktxVulkanDeviceInfo_create(physicalDevice, + device, + queue, + cmdPool, + &allocator); + ktxLoadVkTextureN("texture_1.ktx", vdi, &texture, NULL, NULL); + // ... + ktxLoadVkTextureN("texture_n.ktx", vdi, &texture, NULL, NULL); + ktxVulkanDeviceInfo_destroy(vdi); + * @endcode + */ +typedef struct ktxVulkanDeviceInfo { + VkInstance instance; /*!< Instance used to communicate with vulkan. */ + VkPhysicalDevice physicalDevice; /*!< Handle of the physical device. */ + VkDevice device; /*!< Handle of the logical device. */ + VkQueue queue; /*!< Handle to the queue to which to submit commands. */ + VkCommandBuffer cmdBuffer; /*!< Handle of the cmdBuffer to use. */ + /** Handle of the command pool from which to allocate the command buffer. */ + VkCommandPool cmdPool; + /** Pointer to the allocator to use for the command buffer and created + * images. + */ + const VkAllocationCallbacks* pAllocator; + /** Memory properties of the Vulkan physical device. */ + VkPhysicalDeviceMemoryProperties deviceMemoryProperties; + + /** The functions needed to operate functions */ + ktxVulkanFunctions vkFuncs; +} ktxVulkanDeviceInfo; + + +KTX_API ktxVulkanDeviceInfo* KTX_APIENTRY +ktxVulkanDeviceInfo_CreateEx(VkInstance instance, VkPhysicalDevice physicalDevice, VkDevice device, + VkQueue queue, VkCommandPool cmdPool, + const VkAllocationCallbacks* pAllocator, + const ktxVulkanFunctions* pFunctions); + +KTX_API ktxVulkanDeviceInfo* KTX_APIENTRY +ktxVulkanDeviceInfo_Create(VkPhysicalDevice physicalDevice, VkDevice device, + VkQueue queue, VkCommandPool cmdPool, + const VkAllocationCallbacks* pAllocator); + +KTX_API KTX_error_code KTX_APIENTRY +ktxVulkanDeviceInfo_Construct(ktxVulkanDeviceInfo* This, + VkPhysicalDevice physicalDevice, VkDevice device, + VkQueue queue, VkCommandPool cmdPool, + const VkAllocationCallbacks* pAllocator); + +KTX_API KTX_error_code KTX_APIENTRY +ktxVulkanDeviceInfo_ConstructEx(ktxVulkanDeviceInfo* This, + VkInstance instance, + VkPhysicalDevice physicalDevice, VkDevice device, + VkQueue queue, VkCommandPool cmdPool, + const VkAllocationCallbacks* pAllocator, + const ktxVulkanFunctions* pFunctions); + +KTX_API void KTX_APIENTRY +ktxVulkanDeviceInfo_Destruct(ktxVulkanDeviceInfo* This); +KTX_API void KTX_APIENTRY +ktxVulkanDeviceInfo_Destroy(ktxVulkanDeviceInfo* This); +KTX_API KTX_error_code KTX_APIENTRY +ktxTexture_VkUploadEx(ktxTexture* This, ktxVulkanDeviceInfo* vdi, + ktxVulkanTexture* vkTexture, + VkImageTiling tiling, + VkImageUsageFlags usageFlags, + VkImageLayout finalLayout); +KTX_API KTX_error_code KTX_APIENTRY +ktxTexture_VkUpload(ktxTexture* texture, ktxVulkanDeviceInfo* vdi, + ktxVulkanTexture *vkTexture); +KTX_API KTX_error_code KTX_APIENTRY +ktxTexture1_VkUploadEx(ktxTexture1* This, ktxVulkanDeviceInfo* vdi, + ktxVulkanTexture* vkTexture, + VkImageTiling tiling, + VkImageUsageFlags usageFlags, + VkImageLayout finalLayout); +KTX_API KTX_error_code KTX_APIENTRY +ktxTexture1_VkUpload(ktxTexture1* texture, ktxVulkanDeviceInfo* vdi, + ktxVulkanTexture *vkTexture); +KTX_API KTX_error_code KTX_APIENTRY +ktxTexture2_VkUploadEx(ktxTexture2* This, ktxVulkanDeviceInfo* vdi, + ktxVulkanTexture* vkTexture, + VkImageTiling tiling, + VkImageUsageFlags usageFlags, + VkImageLayout finalLayout); +KTX_API KTX_error_code KTX_APIENTRY +ktxTexture2_VkUpload(ktxTexture2* texture, ktxVulkanDeviceInfo* vdi, + ktxVulkanTexture *vkTexture); + +KTX_API VkFormat KTX_APIENTRY +ktxTexture_GetVkFormat(ktxTexture* This); + +KTX_API VkFormat KTX_APIENTRY +ktxTexture1_GetVkFormat(ktxTexture1* This); + +KTX_API VkFormat KTX_APIENTRY +ktxTexture2_GetVkFormat(ktxTexture2* This); + +#ifdef __cplusplus +} +#endif + +#endif /* KTX_H_A55A6F00956F42F3A137C11929827FE1 */ diff --git a/thirdparty/libktx/lib/basis_sgd.h b/thirdparty/libktx/lib/basis_sgd.h new file mode 100644 index 000000000000..6c5590965293 --- /dev/null +++ b/thirdparty/libktx/lib/basis_sgd.h @@ -0,0 +1,85 @@ +/* -*- tab-width: 4; -*- */ +/* vi: set sw=2 ts=4 expandtab textwidth=70: */ + +/* + * Copyright 2019-2020 The Khronos Group Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @internal + * @file basisu_sgd.h + * @~English + * + * @brief Declare global data for Basis LZ supercompression with ETC1S. + * + * These functions are private and should not be used outside the library. + */ + +#ifndef _BASIS_SGD_H_ +#define _BASIS_SGD_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// This must be the same value as cSliceDescFlagsFrameIsIFrame so we can just +// invert the bit when passing back & forth. As FrameIsIFrame is within +// a C namespace it can't easily be accessed from a c header. +enum bu_image_flags__bits_e { eBUImageIsPframe = 0x02 }; + +typedef uint32_t buFlags; + +typedef struct ktxBasisLzGlobalHeader { + uint16_t endpointCount; + uint16_t selectorCount; + uint32_t endpointsByteLength; + uint32_t selectorsByteLength; + uint32_t tablesByteLength; + uint32_t extendedByteLength; +} ktxBasisLzGlobalHeader; + +// This header is followed by imageCount "slice" descriptions. + +// 1, or 2 slices per image (i.e. layer, face & slice). +// These offsets are relative to start of a mip level as given by the +// main levelIndex. +typedef struct ktxBasisLzEtc1sImageDesc { + buFlags imageFlags; + uint32_t rgbSliceByteOffset; + uint32_t rgbSliceByteLength; + uint32_t alphaSliceByteOffset; + uint32_t alphaSliceByteLength; +} ktxBasisLzEtc1sImageDesc; + +#define BGD_ETC1S_IMAGE_DESCS(bgd) \ + reinterpret_cast(bgd + sizeof(ktxBasisLzGlobalHeader)) + +// The are followed in the global data by these ... +// uint8_t[endpointsByteLength] endpointsData; +// uint8_t[selectorsByteLength] selectorsData; +// uint8_t[tablesByteLength] tablesData; + +#define BGD_ENDPOINTS_ADDR(bgd, imageCount) \ + (bgd + sizeof(ktxBasisLzGlobalHeader) + sizeof(ktxBasisLzEtc1sImageDesc) * imageCount) + +#define BGD_SELECTORS_ADDR(bgd, bgdh, imageCount) (BGD_ENDPOINTS_ADDR(bgd, imageCount) + bgdh.endpointsByteLength) + +#define BGD_TABLES_ADDR(bgd, bgdh, imageCount) (BGD_SELECTORS_ADDR(bgd, bgdh, imageCount) + bgdh.selectorsByteLength) + +#define BGD_EXTENDED_ADDR(bgd, bgdh, imageCount) (BGD_TABLES_ADDR(bgd, bgdh, imageCount) + bgdh.tablesByteLength) + +// Just because this is a convenient place to put it for basis_{en,trans}code. +enum alpha_content_e { + eNone, + eAlpha, + eGreen +}; + +#ifdef __cplusplus +} +#endif + +#endif /* _BASIS_SGD_H_ */ diff --git a/thirdparty/libktx/lib/basis_transcode.cpp b/thirdparty/libktx/lib/basis_transcode.cpp new file mode 100644 index 000000000000..8df65bcb68f5 --- /dev/null +++ b/thirdparty/libktx/lib/basis_transcode.cpp @@ -0,0 +1,733 @@ +/* -*- tab-width: 4; -*- */ +/* vi: set sw=2 ts=4 expandtab: */ + +/* + * Copyright 2019-2020 The Khronos Group Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @internal + * @file basis_transcode.cpp + * @~English + * + * @brief Functions for transcoding Basis Universal BasisLZ/ETC1S and UASTC textures. + * + * Two worlds collide here too. More uglyness! + * + * @author Mark Callow, www.edgewise-consulting.com + */ + +#include +#include +#include + +#include "dfdutils/dfd.h" +#include "ktx.h" +#include "ktxint.h" +#include "texture2.h" +#include "vkformat_enum.h" +#include "vk_format.h" +#include "basis_sgd.h" +#include "transcoder/basisu_file_headers.h" +#include "transcoder/basisu_transcoder.h" +#include "transcoder/basisu_transcoder_internal.h" + +#undef DECLARE_PRIVATE +#undef DECLARE_PROTECTED +#define DECLARE_PRIVATE(n,t2) ktxTexture2_private& n = *(t2->_private) +#define DECLARE_PROTECTED(n,t2) ktxTexture_protected& n = *(t2->_protected) + +using namespace basisu; +using namespace basist; + +inline bool isPow2(uint32_t x) { return x && ((x & (x - 1U)) == 0U); } + +inline bool isPow2(uint64_t x) { return x && ((x & (x - 1U)) == 0U); } + +KTX_error_code +ktxTexture2_transcodeLzEtc1s(ktxTexture2* This, + alpha_content_e alphaContent, + ktxTexture2* prototype, + ktx_transcode_fmt_e outputFormat, + ktx_transcode_flags transcodeFlags); +KTX_error_code +ktxTexture2_transcodeUastc(ktxTexture2* This, + alpha_content_e alphaContent, + ktxTexture2* prototype, + ktx_transcode_fmt_e outputFormat, + ktx_transcode_flags transcodeFlags); + +/** + * @memberof ktxTexture2 + * @ingroup reader + * @~English + * @brief Transcode a KTX2 texture with BasisLZ/ETC1S or UASTC images. + * + * If the texture contains BasisLZ supercompressed images, Inflates them from + * back to ETC1S then transcodes them to the specified block-compressed + * format. If the texture contains UASTC images, inflates them, if they have been + * supercompressed with zstd, then transcodes then to the specified format, The + * transcoded images replace the original images and the texture's fields including + * the DFD are modified to reflect the new format. + * + * These types of textures must be transcoded to a desired target + * block-compressed format before they can be uploaded to a GPU via a + * graphics API. + * + * The following block compressed transcode targets are available: @c KTX_TTF_ETC1_RGB, + * @c KTX_TTF_ETC2_RGBA, @c KTX_TTF_BC1_RGB, @c KTX_TTF_BC3_RGBA, + * @c KTX_TTF_BC4_R, @c KTX_TTF_BC5_RG, @c KTX_TTF_BC7_RGBA, + * @c @c KTX_TTF_PVRTC1_4_RGB, @c KTX_TTF_PVRTC1_4_RGBA, + * @c KTX_TTF_PVRTC2_4_RGB, @c KTX_TTF_PVRTC2_4_RGBA, @c KTX_TTF_ASTC_4x4_RGBA, + * @c KTX_TTF_ETC2_EAC_R11, @c KTX_TTF_ETC2_EAC_RG11, @c KTX_TTF_ETC and + * @c KTX_TTF_BC1_OR_3. + * + * @c KTX_TTF_ETC automatically selects between @c KTX_TTF_ETC1_RGB and + * @c KTX_TTF_ETC2_RGBA according to whether an alpha channel is available. @c KTX_TTF_BC1_OR_3 + * does likewise between @c KTX_TTF_BC1_RGB and @c KTX_TTF_BC3_RGBA. Note that if + * @c KTX_TTF_PVRTC1_4_RGBA or @c KTX_TTF_PVRTC2_4_RGBA is specified and there is no alpha + * channel @c KTX_TTF_PVRTC1_4_RGB or @c KTX_TTF_PVRTC2_4_RGB respectively will be selected. + * + * Transcoding to ATC & FXT1 formats is not supported by libktx as there + * are no equivalent Vulkan formats. + * + * The following uncompressed transcode targets are also available: @c KTX_TTF_RGBA32, + * @c KTX_TTF_RGB565, KTX_TTF_BGR565 and KTX_TTF_RGBA4444. + * + * The following @p transcodeFlags are available. + * + * @sa ktxtexture2_CompressBasis(). + * + * @param[in] This pointer to the ktxTexture2 object of interest. + * @param[in] outputFormat a value from the ktx_texture_transcode_fmt_e enum + * specifying the target format. + * @param[in] transcodeFlags bitfield of flags modifying the transcode + * operation. @sa ktx_texture_decode_flags_e. + * + * @return KTX_SUCCESS on success, other KTX_* enum values on error. + * + * @exception KTX_FILE_DATA_ERROR + * Supercompression global data is corrupted. + * @exception KTX_INVALID_OPERATION + * The texture's format is not transcodable (not + * ETC1S/BasisLZ or UASTC). + * @exception KTX_INVALID_OPERATION + * Supercompression global data is missing, i.e., + * the texture object is invalid. + * @exception KTX_INVALID_OPERATION + * Image data is missing, i.e., the texture object + * is invalid. + * @exception KTX_INVALID_OPERATION + * @p outputFormat is PVRTC1 but the texture does + * does not have power-of-two dimensions. + * @exception KTX_INVALID_VALUE @p outputFormat is invalid. + * @exception KTX_TRANSCODE_FAILED + * Something went wrong during transcoding. + * @exception KTX_UNSUPPORTED_FEATURE + * KTX_TF_PVRTC_DECODE_TO_NEXT_POW2 was requested + * or the specified transcode target has not been + * included in the library being used. + * @exception KTX_OUT_OF_MEMORY Not enough memory to carry out transcoding. + */ + KTX_error_code + ktxTexture2_TranscodeBasis(ktxTexture2* This, + ktx_transcode_fmt_e outputFormat, + ktx_transcode_flags transcodeFlags) +{ + uint32_t* BDB = This->pDfd + 1; + khr_df_model_e colorModel = (khr_df_model_e)KHR_DFDVAL(BDB, MODEL); + if (colorModel != KHR_DF_MODEL_UASTC + // Constructor has checked color model matches BASIS_LZ. + && This->supercompressionScheme != KTX_SS_BASIS_LZ) + { + return KTX_INVALID_OPERATION; // Not in a transcodable format. + } + + DECLARE_PRIVATE(priv, This); + if (This->supercompressionScheme == KTX_SS_BASIS_LZ) { + if (!priv._supercompressionGlobalData || priv._sgdByteLength == 0) + return KTX_INVALID_OPERATION; + } + + if (transcodeFlags & KTX_TF_PVRTC_DECODE_TO_NEXT_POW2) { + debug_printf("ktxTexture_TranscodeBasis: KTX_TF_PVRTC_DECODE_TO_NEXT_POW2 currently unsupported\n"); + return KTX_UNSUPPORTED_FEATURE; + } + + if (outputFormat == KTX_TTF_PVRTC1_4_RGB + || outputFormat == KTX_TTF_PVRTC1_4_RGBA) { + if ((!isPow2(This->baseWidth)) || (!isPow2(This->baseHeight))) { + debug_printf("ktxTexture_TranscodeBasis: PVRTC1 only supports power of 2 dimensions\n"); + return KTX_INVALID_OPERATION; + } + } + + const bool srgb = (KHR_DFDVAL(BDB, TRANSFER) == KHR_DF_TRANSFER_SRGB); + alpha_content_e alphaContent = eNone; + if (colorModel == KHR_DF_MODEL_ETC1S) { + if (KHR_DFDSAMPLECOUNT(BDB) == 2) { + uint32_t channelId = KHR_DFDSVAL(BDB, 1, CHANNELID); + if (channelId == KHR_DF_CHANNEL_ETC1S_AAA) { + alphaContent = eAlpha; + } else if (channelId == KHR_DF_CHANNEL_ETC1S_GGG){ + alphaContent = eGreen; + } else { + return KTX_FILE_DATA_ERROR; + } + } + } else { + uint32_t channelId = KHR_DFDSVAL(BDB, 0, CHANNELID); + if (channelId == KHR_DF_CHANNEL_UASTC_RGBA) + alphaContent = eAlpha; + else if (channelId == KHR_DF_CHANNEL_UASTC_RRRG) + alphaContent = eGreen; + } + + VkFormat vkFormat; + + // Do some format mapping. + switch (outputFormat) { + case KTX_TTF_BC1_OR_3: + outputFormat = alphaContent != eNone ? KTX_TTF_BC3_RGBA + : KTX_TTF_BC1_RGB; + break; + case KTX_TTF_ETC: + outputFormat = alphaContent != eNone ? KTX_TTF_ETC2_RGBA + : KTX_TTF_ETC1_RGB; + break; + case KTX_TTF_PVRTC1_4_RGBA: + // This transcoder does not write opaque alpha blocks. + outputFormat = alphaContent != eNone ? KTX_TTF_PVRTC1_4_RGBA + : KTX_TTF_PVRTC1_4_RGB; + break; + case KTX_TTF_PVRTC2_4_RGBA: + // This transcoder does not write opaque alpha blocks. + outputFormat = alphaContent != eNone ? KTX_TTF_PVRTC2_4_RGBA + : KTX_TTF_PVRTC2_4_RGB; + break; + default: + /*NOP*/; + } + + switch (outputFormat) { + case KTX_TTF_ETC1_RGB: + vkFormat = srgb ? VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK + : VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK; + break; + case KTX_TTF_ETC2_RGBA: + vkFormat = srgb ? VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK + : VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK; + break; + case KTX_TTF_ETC2_EAC_R11: + vkFormat = VK_FORMAT_EAC_R11_UNORM_BLOCK; + break; + case KTX_TTF_ETC2_EAC_RG11: + vkFormat = VK_FORMAT_EAC_R11G11_UNORM_BLOCK; + break; + case KTX_TTF_BC1_RGB: + // Transcoding doesn't support BC1 alpha. + vkFormat = srgb ? VK_FORMAT_BC1_RGB_SRGB_BLOCK + : VK_FORMAT_BC1_RGB_UNORM_BLOCK; + break; + case KTX_TTF_BC3_RGBA: + vkFormat = srgb ? VK_FORMAT_BC3_SRGB_BLOCK + : VK_FORMAT_BC3_UNORM_BLOCK; + break; + case KTX_TTF_BC4_R: + vkFormat = VK_FORMAT_BC4_UNORM_BLOCK; + break; + case KTX_TTF_BC5_RG: + vkFormat = VK_FORMAT_BC5_UNORM_BLOCK; + break; + case KTX_TTF_PVRTC1_4_RGB: + case KTX_TTF_PVRTC1_4_RGBA: + vkFormat = srgb ? VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG + : VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG; + break; + case KTX_TTF_PVRTC2_4_RGB: + case KTX_TTF_PVRTC2_4_RGBA: + vkFormat = srgb ? VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG + : VK_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG; + break; + case KTX_TTF_BC7_RGBA: + vkFormat = srgb ? VK_FORMAT_BC7_SRGB_BLOCK + : VK_FORMAT_BC7_UNORM_BLOCK; + break; + case KTX_TTF_ASTC_4x4_RGBA: + vkFormat = srgb ? VK_FORMAT_ASTC_4x4_SRGB_BLOCK + : VK_FORMAT_ASTC_4x4_UNORM_BLOCK; + break; + case KTX_TTF_RGB565: + vkFormat = VK_FORMAT_R5G6B5_UNORM_PACK16; + break; + case KTX_TTF_BGR565: + vkFormat = VK_FORMAT_B5G6R5_UNORM_PACK16; + break; + case KTX_TTF_RGBA4444: + vkFormat = VK_FORMAT_R4G4B4A4_UNORM_PACK16; + break; + case KTX_TTF_RGBA32: + vkFormat = srgb ? VK_FORMAT_R8G8B8A8_SRGB + : VK_FORMAT_R8G8B8A8_UNORM; + break; + default: + return KTX_INVALID_VALUE; + } + + basis_tex_format textureFormat; + if (colorModel == KHR_DF_MODEL_UASTC) + textureFormat = basis_tex_format::cUASTC4x4; + else + textureFormat = basis_tex_format::cETC1S; + + if (!basis_is_format_supported((transcoder_texture_format)outputFormat, + textureFormat)) { + return KTX_UNSUPPORTED_FEATURE; + } + + + // Create a prototype texture to use for calculating sizes in the target + // format and, as useful side effects, provide us with a properly sized + // data allocation and the DFD for the target format. + ktxTextureCreateInfo createInfo; + createInfo.glInternalformat = 0; + createInfo.vkFormat = vkFormat; + createInfo.baseWidth = This->baseWidth; + createInfo.baseHeight = This->baseHeight; + createInfo.baseDepth = This->baseDepth; + createInfo.generateMipmaps = This->generateMipmaps; + createInfo.isArray = This->isArray; + createInfo.numDimensions = This->numDimensions; + createInfo.numFaces = This->numFaces; + createInfo.numLayers = This->numLayers; + createInfo.numLevels = This->numLevels; + createInfo.pDfd = nullptr; + + KTX_error_code result; + ktxTexture2* prototype; + result = ktxTexture2_Create(&createInfo, KTX_TEXTURE_CREATE_ALLOC_STORAGE, + &prototype); + + if (result != KTX_SUCCESS) { + assert(result == KTX_OUT_OF_MEMORY); // The only run time error + return result; + } + + if (!This->pData) { + if (ktxTexture_isActiveStream((ktxTexture*)This)) { + // Load pending. Complete it. + result = ktxTexture2_LoadImageData(This, NULL, 0); + if (result != KTX_SUCCESS) + { + ktxTexture2_Destroy(prototype); + return result; + } + } else { + // No data to transcode. + ktxTexture2_Destroy(prototype); + return KTX_INVALID_OPERATION; + } + } + + // Transcoder global initialization. Requires ~9 milliseconds when compiled + // and executed natively on a Core i7 2.2 GHz. If this is too slow, the + // tables it computes can easily be moved to be compiled in. + static bool transcoderInitialized; + if (!transcoderInitialized) { + basisu_transcoder_init(); + transcoderInitialized = true; + } + + if (textureFormat == basis_tex_format::cETC1S) { + result = ktxTexture2_transcodeLzEtc1s(This, alphaContent, + prototype, outputFormat, + transcodeFlags); + } else { + result = ktxTexture2_transcodeUastc(This, alphaContent, + prototype, outputFormat, + transcodeFlags); + } + + if (result == KTX_SUCCESS) { + // Fix up the current texture + DECLARE_PROTECTED(thisPrtctd, This); + DECLARE_PRIVATE(protoPriv, prototype); + DECLARE_PROTECTED(protoPrtctd, prototype); + memcpy(&thisPrtctd._formatSize, &protoPrtctd._formatSize, + sizeof(ktxFormatSize)); + This->vkFormat = vkFormat; + This->isCompressed = prototype->isCompressed; + This->supercompressionScheme = KTX_SS_NONE; + priv._requiredLevelAlignment = protoPriv._requiredLevelAlignment; + // Copy the levelIndex from the prototype to This. + memcpy(priv._levelIndex, protoPriv._levelIndex, + This->numLevels * sizeof(ktxLevelIndexEntry)); + // Move the DFD and data from the prototype to This. + free(This->pDfd); + This->pDfd = prototype->pDfd; + prototype->pDfd = 0; + free(This->pData); + This->pData = prototype->pData; + This->dataSize = prototype->dataSize; + prototype->pData = 0; + prototype->dataSize = 0; + } + ktxTexture2_Destroy(prototype); + return result; + } + +/** + * @memberof ktxTexture2 @private + * @ingroup reader + * @~English + * @brief Transcode a KTX2 texture with BasisLZ supercompressed ETC1S images. + * + * Inflates the images from BasisLZ supercompression back to ETC1S + * then transcodes them to the specified block-compressed format. The + * transcoded images replace the original images and the texture's fields + * including the DFD are modified to reflect the new format. + * + * BasisLZ supercompressed textures must be transcoded to a desired target + * block-compressed format before they can be uploaded to a GPU via a graphics + * API. + * + * The following block compressed transcode targets are available: @c KTX_TTF_ETC1_RGB, + * @c KTX_TTF_ETC2_RGBA, @c KTX_TTF_BC1_RGB, @c KTX_TTF_BC3_RGBA, + * @c KTX_TTF_BC4_R, @c KTX_TTF_BC5_RG, @c KTX_TTF_BC7_RGBA, + * @c @c KTX_TTF_PVRTC1_4_RGB, @c KTX_TTF_PVRTC1_4_RGBA, + * @c KTX_TTF_PVRTC2_4_RGB, @c KTX_TTF_PVRTC2_4_RGBA, @c KTX_TTF_ASTC_4x4_RGBA, + * @c KTX_TTF_ETC2_EAC_R11, @c KTX_TTF_ETC2_EAC_RG11, @c KTX_TTF_ETC and + * @c KTX_TTF_BC1_OR_3. + * + * @c KTX_TTF_ETC automatically selects between @c KTX_TTF_ETC1_RGB and + * @c KTX_TTF_ETC2_RGBA according to whether an alpha channel is available. @c KTX_TTF_BC1_OR_3 + * does likewise between @c KTX_TTF_BC1_RGB and @c KTX_TTF_BC3_RGBA. Note that if + * @c KTX_TTF_PVRTC1_4_RGBA or @c KTX_TTF_PVRTC2_4_RGBA is specified and there is no alpha + * channel @c KTX_TTF_PVRTC1_4_RGB or @c KTX_TTF_PVRTC2_4_RGB respectively will be selected. + * + * ATC & FXT1 formats are not supported by KTX2 & libktx as there are no equivalent Vulkan formats. + * + * The following uncompressed transcode targets are also available: @c KTX_TTF_RGBA32, + * @c KTX_TTF_RGB565, KTX_TTF_BGR565 and KTX_TTF_RGBA4444. + * + * The following @p transcodeFlags are available. + * + * @sa ktxtexture2_CompressBasis(). + * + * @param[in] This pointer to the ktxTexture2 object of interest. + * @param[in] outputFormat a value from the ktx_texture_transcode_fmt_e enum + * specifying the target format. + * @param[in] transcodeFlags bitfield of flags modifying the transcode + * operation. @sa ktx_texture_decode_flags_e. + * + * @return KTX_SUCCESS on success, other KTX_* enum values on error. + * + * @exception KTX_FILE_DATA_ERROR + * Supercompression global data is corrupted. + * @exception KTX_INVALID_OPERATION + * The texture's format is not transcodable (not + * ETC1S/BasisLZ or UASTC). + * @exception KTX_INVALID_OPERATION + * Supercompression global data is missing, i.e., + * the texture object is invalid. + * @exception KTX_INVALID_OPERATION + * Image data is missing, i.e., the texture object + * is invalid. + * @exception KTX_INVALID_OPERATION + * @p outputFormat is PVRTC1 but the texture does + * does not have power-of-two dimensions. + * @exception KTX_INVALID_VALUE @p outputFormat is invalid. + * @exception KTX_TRANSCODE_FAILED + * Something went wrong during transcoding. The + * texture object will be corrupted. + * @exception KTX_UNSUPPORTED_FEATURE + * KTX_TF_PVRTC_DECODE_TO_NEXT_POW2 was requested + * or the specified transcode target has not been + * included in the library being used. + * @exception KTX_OUT_OF_MEMORY Not enough memory to carry out transcoding. + */ +KTX_error_code +ktxTexture2_transcodeLzEtc1s(ktxTexture2* This, + alpha_content_e alphaContent, + ktxTexture2* prototype, + ktx_transcode_fmt_e outputFormat, + ktx_transcode_flags transcodeFlags) +{ + DECLARE_PRIVATE(priv, This); + DECLARE_PRIVATE(protoPriv, prototype); + KTX_error_code result = KTX_SUCCESS; + + assert(This->supercompressionScheme == KTX_SS_BASIS_LZ); + + uint8_t* bgd = priv._supercompressionGlobalData; + ktxBasisLzGlobalHeader& bgdh = *reinterpret_cast(bgd); + if (!(bgdh.endpointsByteLength && bgdh.selectorsByteLength && bgdh.tablesByteLength)) { + debug_printf("ktxTexture_TranscodeBasis: missing endpoints, selectors or tables"); + return KTX_FILE_DATA_ERROR; + } + + // Compute some helpful numbers. + // + // firstImages contains the indices of the first images for each level to + // ease finding the correct slice description when iterating from smallest + // level to largest or when randomly accessing them (t.b.c). The last array + // entry contains the total number of images, for calculating the offsets + // of the endpoints, etc. + uint32_t* firstImages = new uint32_t[This->numLevels+1]; + + // Temporary invariant value + uint32_t layersFaces = This->numLayers * This->numFaces; + firstImages[0] = 0; + for (uint32_t level = 1; level <= This->numLevels; level++) { + // NOTA BENE: numFaces * depth is only reasonable because they can't + // both be > 1. I.e there are no 3d cubemaps. + firstImages[level] = firstImages[level - 1] + + layersFaces * MAX(This->baseDepth >> (level - 1), 1); + } + uint32_t& imageCount = firstImages[This->numLevels]; + + if (BGD_TABLES_ADDR(0, bgdh, imageCount) + bgdh.tablesByteLength > priv._sgdByteLength) { + return KTX_FILE_DATA_ERROR; + } + // FIXME: Do more validation. + + // Prepare low-level transcoder for transcoding slices. + basist::basisu_lowlevel_etc1s_transcoder bit; + + // basisu_transcoder_state is used to find the previous frame when + // decoding a video P-Frame. It tracks the previous frame for each mip + // level. For cube map array textures we need to find the previous frame + // for each face so we a state per face. Although providing this is only + // needed for video, it is easier to always pass our own. + std::vector xcoderStates; + xcoderStates.resize(This->isVideo ? This->numFaces : 1); + + bit.decode_palettes(bgdh.endpointCount, BGD_ENDPOINTS_ADDR(bgd, imageCount), + bgdh.endpointsByteLength, + bgdh.selectorCount, BGD_SELECTORS_ADDR(bgd, bgdh, imageCount), + bgdh.selectorsByteLength); + + bit.decode_tables(BGD_TABLES_ADDR(bgd, bgdh, imageCount), + bgdh.tablesByteLength); + + // Find matching VkFormat and calculate output sizes. + + const bool isVideo = This->isVideo; + + ktx_uint8_t* pXcodedData = prototype->pData; + // Inconveniently, the output buffer size parameter of transcode_image + // has to be in pixels for uncompressed output and in blocks for + // compressed output. The only reason for humouring the API is so + // its buffer size tests provide a real check. An alternative is to + // always provide the size in bytes which will always pass. + ktx_uint32_t outputBlockByteLength + = prototype->_protected->_formatSize.blockSizeInBits / 8; + ktx_size_t xcodedDataLength + = prototype->dataSize / outputBlockByteLength; + ktxLevelIndexEntry* protoLevelIndex; + uint64_t levelOffsetWrite; + const ktxBasisLzEtc1sImageDesc* imageDescs = BGD_ETC1S_IMAGE_DESCS(bgd); + + // Finally we're ready to transcode the slices. + + // FIXME: Iframe flag needs to be queryable by the application. In Basis + // the app can query file_info and image_info from the transcoder which + // returns a structure with lots of info about the image. + + protoLevelIndex = protoPriv._levelIndex; + levelOffsetWrite = 0; + for (int32_t level = This->numLevels - 1; level >= 0; level--) { + uint64_t levelOffset = ktxTexture2_levelDataOffset(This, level); + uint64_t writeOffset = levelOffsetWrite; + uint64_t writeOffsetBlocks = levelOffsetWrite / outputBlockByteLength; + uint32_t levelWidth = MAX(1, This->baseWidth >> level); + uint32_t levelHeight = MAX(1, This->baseHeight >> level); + // ETC1S texel block dimensions + const uint32_t bw = 4, bh = 4; + uint32_t levelBlocksX = (levelWidth + (bw - 1)) / bw; + uint32_t levelBlocksY = (levelHeight + (bh - 1)) / bh; + uint32_t depth = MAX(1, This->baseDepth >> level); + //uint32_t faceSlices = This->numFaces == 1 ? depth : This->numFaces; + uint32_t faceSlices = This->numFaces * depth; + uint32_t numImages = This->numLayers * faceSlices; + uint32_t image = firstImages[level]; + uint32_t endImage = image + numImages; + ktx_size_t levelImageSizeOut, levelSizeOut; + uint32_t stateIndex = 0; + + levelSizeOut = 0; + // FIXME: Figure out a way to get the size out of the transcoder. + levelImageSizeOut = ktxTexture2_GetImageSize(prototype, level); + for (; image < endImage; image++) { + const ktxBasisLzEtc1sImageDesc& imageDesc = imageDescs[image]; + + basisu_transcoder_state& xcoderState = xcoderStates[stateIndex]; + // We have face0 [face1 ...] within each layer. Use `stateIndex` + // rather than a double loop of layers and faceSlices as this + // works for 3d texture and non-array cube maps as well as + // cube map arrays without special casing. + if (++stateIndex == xcoderStates.size()) + stateIndex = 0; + + if (alphaContent != eNone) + { + // The slice descriptions should have alpha information. + if (imageDesc.alphaSliceByteOffset == 0 + || imageDesc.alphaSliceByteLength == 0) + return KTX_FILE_DATA_ERROR; + } + + bool status; + status = bit.transcode_image( + (transcoder_texture_format)outputFormat, + pXcodedData + writeOffset, + (uint32_t)(xcodedDataLength - writeOffsetBlocks), + This->pData, + (uint32_t)This->dataSize, + levelBlocksX, + levelBlocksY, + levelWidth, + levelHeight, + level, + (uint32_t)(levelOffset + imageDesc.rgbSliceByteOffset), + imageDesc.rgbSliceByteLength, + (uint32_t)(levelOffset + imageDesc.alphaSliceByteOffset), + imageDesc.alphaSliceByteLength, + transcodeFlags, + alphaContent != eNone, + isVideo, + // Our P-Frame flag is in the same bit as + // cSliceDescFlagsFrameIsIFrame. We have to + // invert it to make it an I-Frame flag. + // + // API currently doesn't have any way to pass + // the I-Frame flag. + //imageDesc.imageFlags ^ cSliceDescFlagsFrameIsIFrame, + 0, // output_row_pitch_in_blocks_or_pixels + &xcoderState, + 0 // output_rows_in_pixels + ); + if (!status) { + result = KTX_TRANSCODE_FAILED; + goto cleanup; + } + + writeOffset += levelImageSizeOut; + levelSizeOut += levelImageSizeOut; + } // end images loop + protoLevelIndex[level].byteOffset = levelOffsetWrite; + protoLevelIndex[level].byteLength = levelSizeOut; + protoLevelIndex[level].uncompressedByteLength = levelSizeOut; + levelOffsetWrite += levelSizeOut; + assert(levelOffsetWrite == writeOffset); + // In case of transcoding to uncompressed. + levelOffsetWrite = _KTX_PADN(protoPriv._requiredLevelAlignment, + levelOffsetWrite); + } // level loop + + result = KTX_SUCCESS; + +cleanup: + delete[] firstImages; + return result; +} + + +KTX_error_code +ktxTexture2_transcodeUastc(ktxTexture2* This, + alpha_content_e alphaContent, + ktxTexture2* prototype, + ktx_transcode_fmt_e outputFormat, + ktx_transcode_flags transcodeFlags) +{ + assert(This->supercompressionScheme != KTX_SS_BASIS_LZ); + + ktx_uint8_t* pXcodedData = prototype->pData; + ktx_uint32_t outputBlockByteLength + = prototype->_protected->_formatSize.blockSizeInBits / 8; + ktx_size_t xcodedDataLength + = prototype->dataSize / outputBlockByteLength; + DECLARE_PRIVATE(protoPriv, prototype); + ktxLevelIndexEntry* protoLevelIndex = protoPriv._levelIndex; + ktx_size_t levelOffsetWrite = 0; + + basisu_lowlevel_uastc_transcoder uit; + // See comment on same declaration in transcodeEtc1s. + std::vector xcoderStates; + xcoderStates.resize(This->isVideo ? This->numFaces : 1); + + for (ktx_int32_t level = This->numLevels - 1; level >= 0; level--) + { + ktx_uint32_t depth; + uint64_t writeOffset = levelOffsetWrite; + uint64_t writeOffsetBlocks = levelOffsetWrite / outputBlockByteLength; + ktx_size_t levelImageSizeIn, levelImageOffsetIn; + ktx_size_t levelImageSizeOut, levelSizeOut; + ktx_uint32_t levelImageCount; + uint32_t levelWidth = MAX(1, This->baseWidth >> level); + uint32_t levelHeight = MAX(1, This->baseHeight >> level); + // UASTC texel block dimensions + const uint32_t bw = 4, bh = 4; + uint32_t levelBlocksX = (levelWidth + (bw - 1)) / bw; + uint32_t levelBlocksY = (levelHeight + (bh - 1)) / bh; + uint32_t stateIndex = 0; + + depth = MAX(1, This->baseDepth >> level); + + levelImageCount = This->numLayers * This->numFaces * depth; + levelImageSizeIn = ktxTexture_calcImageSize(ktxTexture(This), level, + KTX_FORMAT_VERSION_TWO); + levelImageSizeOut = ktxTexture_calcImageSize(ktxTexture(prototype), + level, + KTX_FORMAT_VERSION_TWO); + + levelImageOffsetIn = ktxTexture2_levelDataOffset(This, level); + levelSizeOut = 0; + bool status; + for (uint32_t image = 0; image < levelImageCount; image++) { + basisu_transcoder_state& xcoderState = xcoderStates[stateIndex]; + // See comment before same lines in transcodeEtc1s. + if (++stateIndex == xcoderStates.size()) + stateIndex = 0; + + status = uit.transcode_image( + (transcoder_texture_format)outputFormat, + pXcodedData + writeOffset, + (uint32_t)(xcodedDataLength - writeOffsetBlocks), + This->pData, + (uint32_t)This->dataSize, + levelBlocksX, + levelBlocksY, + levelWidth, + levelHeight, + level, + (uint32_t)levelImageOffsetIn, + (uint32_t)levelImageSizeIn, + transcodeFlags, + alphaContent != eNone, + This->isVideo, // is_video + //imageDesc.imageFlags ^ cSliceDescFlagsFrameIsIFrame, + 0, // output_row_pitch_in_blocks_or_pixels + &xcoderState, // pState + 0, // output_rows_in_pixels, + -1, // channel0 + -1 // channel1 + ); + if (!status) + return KTX_TRANSCODE_FAILED; + writeOffset += levelImageSizeOut; + levelSizeOut += levelImageSizeOut; + levelImageOffsetIn += levelImageSizeIn; + } + protoLevelIndex[level].byteOffset = levelOffsetWrite; + // writeOffset will be equal to total size of the images in the level. + protoLevelIndex[level].byteLength = levelSizeOut; + protoLevelIndex[level].uncompressedByteLength = levelSizeOut; + levelOffsetWrite += levelSizeOut; + } + // In case of transcoding to uncompressed. + levelOffsetWrite = _KTX_PADN(protoPriv._requiredLevelAlignment, + levelOffsetWrite); + return KTX_SUCCESS; +} diff --git a/thirdparty/libktx/lib/checkheader.c b/thirdparty/libktx/lib/checkheader.c new file mode 100644 index 000000000000..07e5d919c8ca --- /dev/null +++ b/thirdparty/libktx/lib/checkheader.c @@ -0,0 +1,259 @@ +/* -*- tab-width: 4; -*- */ +/* vi: set sw=2 ts=4 expandtab: */ + +/* $Id: ee6f7be4d43390de78e1815ed158012c78ddeff1 $ */ + +/* + * Copyright 2010-2020 The Khronos Group Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @internal + * @file checkheader.c + * @~English + * + * @brief Function to verify a KTX file header + * + * @author Mark Callow, HI Corporation + */ + +/* + * Author: Georg Kolling, Imagination Technology with modifications + * by Mark Callow, HI Corporation. + */ +#include +#include + +#include "ktx.h" +#include "ktxint.h" + +/** + * @internal + * @~English + * @brief Check a KTX file header. + * + * As well as checking that the header identifies a KTX file, the function + * sanity checks the values and returns information about the texture in a + * struct KTX_supplementary_info. + * + * @param pHeader pointer to the KTX header to check + * @param pSuppInfo pointer to a KTX_supplementary_info structure in which to + * return information about the texture. + * + * @author Georg Kolling, Imagination Technology + * @author Mark Callow, HI Corporation + */ + +KTX_error_code ktxCheckHeader1_(KTX_header* pHeader, + KTX_supplemental_info* pSuppInfo) +{ + ktx_uint8_t identifier_reference[12] = KTX_IDENTIFIER_REF; + ktx_uint32_t max_dim; + + assert(pHeader != NULL && pSuppInfo != NULL); + + /* Compare identifier, is this a KTX file? */ + if (memcmp(pHeader->identifier, identifier_reference, 12) != 0) + { + return KTX_UNKNOWN_FILE_FORMAT; + } + + if (pHeader->endianness == KTX_ENDIAN_REF_REV) + { + /* Convert endianness of pHeader fields. */ + _ktxSwapEndian32(&pHeader->glType, 12); + + if (pHeader->glTypeSize != 1 && + pHeader->glTypeSize != 2 && + pHeader->glTypeSize != 4) + { + /* Only 8-, 16-, and 32-bit types supported so far. */ + return KTX_FILE_DATA_ERROR; + } + } + else if (pHeader->endianness != KTX_ENDIAN_REF) + { + return KTX_FILE_DATA_ERROR; + } + + /* Check glType and glFormat */ + pSuppInfo->compressed = 0; + if (pHeader->glType == 0 || pHeader->glFormat == 0) + { + if (pHeader->glType + pHeader->glFormat != 0) + { + /* either both or none of glType, glFormat must be zero */ + return KTX_FILE_DATA_ERROR; + } + pSuppInfo->compressed = 1; + } + + if (pHeader->glFormat == pHeader->glInternalformat) { + // glInternalFormat is either unsized (which is no longer and should + // never have been supported by libktx) or glFormat is sized. + return KTX_FILE_DATA_ERROR; + } + + /* Check texture dimensions. KTX files can store 8 types of textures: + 1D, 2D, 3D, cube, and array variants of these. There is currently + no GL extension for 3D array textures. */ + if ((pHeader->pixelWidth == 0) || + (pHeader->pixelDepth > 0 && pHeader->pixelHeight == 0)) + { + /* texture must have width */ + /* texture must have height if it has depth */ + return KTX_FILE_DATA_ERROR; + } + + + if (pHeader->pixelDepth > 0) + { + if (pHeader->numberOfArrayElements > 0) + { + /* No 3D array textures yet. */ + return KTX_UNSUPPORTED_TEXTURE_TYPE; + } + pSuppInfo->textureDimension = 3; + } + else if (pHeader->pixelHeight > 0) + { + pSuppInfo->textureDimension = 2; + } + else + { + pSuppInfo->textureDimension = 1; + } + + if (pHeader->numberOfFaces == 6) + { + if (pSuppInfo->textureDimension != 2) + { + /* cube map needs 2D faces */ + return KTX_FILE_DATA_ERROR; + } + } + else if (pHeader->numberOfFaces != 1) + { + /* numberOfFaces must be either 1 or 6 */ + return KTX_FILE_DATA_ERROR; + } + + /* Check number of mipmap levels */ + if (pHeader->numberOfMipLevels == 0) + { + pSuppInfo->generateMipmaps = 1; + pHeader->numberOfMipLevels = 1; + } + else + { + pSuppInfo->generateMipmaps = 0; + } + + /* This test works for arrays too because height or depth will be 0. */ + max_dim = MAX(MAX(pHeader->pixelWidth, pHeader->pixelHeight), pHeader->pixelDepth); + if (max_dim < ((ktx_uint32_t)1 << (pHeader->numberOfMipLevels - 1))) + { + /* Can't have more mip levels than 1 + log2(max(width, height, depth)) */ + return KTX_FILE_DATA_ERROR; + } + + return KTX_SUCCESS; +} + +/** + * @internal + * @~English + * @brief Check a KTX2 file header. + * + * As well as checking that the header identifies a KTX 2 file, the function + * sanity checks the values and returns information about the texture in a + * struct KTX_supplementary_info. + * + * @param pHeader pointer to the KTX header to check + * @param pSuppInfo pointer to a KTX_supplementary_info structure in which to + * return information about the texture. + * + * @author Mark Callow, HI Corporation + */ +KTX_error_code ktxCheckHeader2_(KTX_header2* pHeader, + KTX_supplemental_info* pSuppInfo) +{ +// supp info is compressed, generateMipmaps and num dimensions. Don't need +// compressed as formatSize gives us that. I think the other 2 aren't needed. + ktx_uint8_t identifier_reference[12] = KTX2_IDENTIFIER_REF; + + assert(pHeader != NULL && pSuppInfo != NULL); + ktx_uint32_t max_dim; + + /* Compare identifier, is this a KTX file? */ + if (memcmp(pHeader->identifier, identifier_reference, 12) != 0) + { + return KTX_UNKNOWN_FILE_FORMAT; + } + + /* Check texture dimensions. KTX files can store 8 types of textures: + 1D, 2D, 3D, cube, and array variants of these. There is currently + no extension for 3D array textures in any 3D API. */ + if ((pHeader->pixelWidth == 0) || + (pHeader->pixelDepth > 0 && pHeader->pixelHeight == 0)) + { + /* texture must have width */ + /* texture must have height if it has depth */ + return KTX_FILE_DATA_ERROR; + } + + if (pHeader->pixelDepth > 0) + { + if (pHeader->layerCount > 0) + { + /* No 3D array textures yet. */ + return KTX_UNSUPPORTED_TEXTURE_TYPE; + } + pSuppInfo->textureDimension = 3; + } + else if (pHeader->pixelHeight > 0) + { + pSuppInfo->textureDimension = 2; + } + else + { + pSuppInfo->textureDimension = 1; + } + + if (pHeader->faceCount == 6) + { + if (pSuppInfo->textureDimension != 2) + { + /* cube map needs 2D faces */ + return KTX_FILE_DATA_ERROR; + } + } + else if (pHeader->faceCount != 1) + { + /* numberOfFaces must be either 1 or 6 */ + return KTX_FILE_DATA_ERROR; + } + + // Check number of mipmap levels + if (pHeader->levelCount == 0) + { + pSuppInfo->generateMipmaps = 1; + pHeader->levelCount = 1; + } + else + { + pSuppInfo->generateMipmaps = 0; + } + + // This test works for arrays too because height or depth will be 0. + max_dim = MAX(MAX(pHeader->pixelWidth, pHeader->pixelHeight), pHeader->pixelDepth); + if (max_dim < ((ktx_uint32_t)1 << (pHeader->levelCount - 1))) + { + // Can't have more mip levels than 1 + log2(max(width, height, depth)) + return KTX_FILE_DATA_ERROR; + } + + return KTX_SUCCESS; + +} diff --git a/thirdparty/libktx/lib/dfdutils/KHR/khr_df.h b/thirdparty/libktx/lib/dfdutils/KHR/khr_df.h new file mode 100644 index 000000000000..bbd0d14bd90c --- /dev/null +++ b/thirdparty/libktx/lib/dfdutils/KHR/khr_df.h @@ -0,0 +1,619 @@ +/* The Khronos Data Format Specification (version 1.3) */ +/* +** Copyright 2015-2020 The Khronos Group Inc. +** SPDX-License-Identifier: Apache-2.0 +*/ + +/* This header defines a structure that can describe the layout of image + formats in memory. This means that the data format is transparent to + the application, and the expectation is that this should be used when + the layout is defined external to the API. Many Khronos APIs deliberately + keep the internal layout of images opaque, to allow proprietary layouts + and optimisations. This structure is not appropriate for describing + opaque layouts. */ + +/* We stick to standard C89 constructs for simplicity and portability. */ + +#ifndef _KHR_DATA_FORMAT_H_ +#define _KHR_DATA_FORMAT_H_ + +/* Accessors */ +typedef enum _khr_word_e { + KHR_DF_WORD_VENDORID = 0U, + KHR_DF_WORD_DESCRIPTORTYPE = 0U, + KHR_DF_WORD_VERSIONNUMBER = 1U, + KHR_DF_WORD_DESCRIPTORBLOCKSIZE = 1U, + KHR_DF_WORD_MODEL = 2U, + KHR_DF_WORD_PRIMARIES = 2U, + KHR_DF_WORD_TRANSFER = 2U, + KHR_DF_WORD_FLAGS = 2U, + KHR_DF_WORD_TEXELBLOCKDIMENSION0 = 3U, + KHR_DF_WORD_TEXELBLOCKDIMENSION1 = 3U, + KHR_DF_WORD_TEXELBLOCKDIMENSION2 = 3U, + KHR_DF_WORD_TEXELBLOCKDIMENSION3 = 3U, + KHR_DF_WORD_BYTESPLANE0 = 4U, + KHR_DF_WORD_BYTESPLANE1 = 4U, + KHR_DF_WORD_BYTESPLANE2 = 4U, + KHR_DF_WORD_BYTESPLANE3 = 4U, + KHR_DF_WORD_BYTESPLANE4 = 5U, + KHR_DF_WORD_BYTESPLANE5 = 5U, + KHR_DF_WORD_BYTESPLANE6 = 5U, + KHR_DF_WORD_BYTESPLANE7 = 5U, + KHR_DF_WORD_SAMPLESTART = 6U, + KHR_DF_WORD_SAMPLEWORDS = 4U +} khr_df_word_e; + +typedef enum _khr_df_shift_e { + KHR_DF_SHIFT_VENDORID = 0U, + KHR_DF_SHIFT_DESCRIPTORTYPE = 17U, + KHR_DF_SHIFT_VERSIONNUMBER = 0U, + KHR_DF_SHIFT_DESCRIPTORBLOCKSIZE = 16U, + KHR_DF_SHIFT_MODEL = 0U, + KHR_DF_SHIFT_PRIMARIES = 8U, + KHR_DF_SHIFT_TRANSFER = 16U, + KHR_DF_SHIFT_FLAGS = 24U, + KHR_DF_SHIFT_TEXELBLOCKDIMENSION0 = 0U, + KHR_DF_SHIFT_TEXELBLOCKDIMENSION1 = 8U, + KHR_DF_SHIFT_TEXELBLOCKDIMENSION2 = 16U, + KHR_DF_SHIFT_TEXELBLOCKDIMENSION3 = 24U, + KHR_DF_SHIFT_BYTESPLANE0 = 0U, + KHR_DF_SHIFT_BYTESPLANE1 = 8U, + KHR_DF_SHIFT_BYTESPLANE2 = 16U, + KHR_DF_SHIFT_BYTESPLANE3 = 24U, + KHR_DF_SHIFT_BYTESPLANE4 = 0U, + KHR_DF_SHIFT_BYTESPLANE5 = 8U, + KHR_DF_SHIFT_BYTESPLANE6 = 16U, + KHR_DF_SHIFT_BYTESPLANE7 = 24U +} khr_df_shift_e; + +typedef enum _khr_df_mask_e { + KHR_DF_MASK_VENDORID = 0x1FFFFU, + KHR_DF_MASK_DESCRIPTORTYPE = 0x7FFFU, + KHR_DF_MASK_VERSIONNUMBER = 0xFFFFU, + KHR_DF_MASK_DESCRIPTORBLOCKSIZE = 0xFFFFU, + KHR_DF_MASK_MODEL = 0xFFU, + KHR_DF_MASK_PRIMARIES = 0xFFU, + KHR_DF_MASK_TRANSFER = 0xFFU, + KHR_DF_MASK_FLAGS = 0xFFU, + KHR_DF_MASK_TEXELBLOCKDIMENSION0 = 0xFFU, + KHR_DF_MASK_TEXELBLOCKDIMENSION1 = 0xFFU, + KHR_DF_MASK_TEXELBLOCKDIMENSION2 = 0xFFU, + KHR_DF_MASK_TEXELBLOCKDIMENSION3 = 0xFFU, + KHR_DF_MASK_BYTESPLANE0 = 0xFFU, + KHR_DF_MASK_BYTESPLANE1 = 0xFFU, + KHR_DF_MASK_BYTESPLANE2 = 0xFFU, + KHR_DF_MASK_BYTESPLANE3 = 0xFFU, + KHR_DF_MASK_BYTESPLANE4 = 0xFFU, + KHR_DF_MASK_BYTESPLANE5 = 0xFFU, + KHR_DF_MASK_BYTESPLANE6 = 0xFFU, + KHR_DF_MASK_BYTESPLANE7 = 0xFFU +} khr_df_mask_e; + +/* Helper macro: + Extract field X from basic descriptor block BDB */ +#define KHR_DFDVAL(BDB, X) \ + (((BDB)[KHR_DF_WORD_ ## X] >> (KHR_DF_SHIFT_ ## X)) \ + & (KHR_DF_MASK_ ## X)) + +/* Helper macro: + Set field X of basic descriptor block BDB */ +#define KHR_DFDSETVAL(BDB, X, val) \ + ((BDB)[KHR_DF_WORD_ ## X] = \ + ((BDB)[KHR_DF_WORD_ ## X] & \ + ~((KHR_DF_MASK_ ## X) << (KHR_DF_SHIFT_ ## X))) | \ + (((val) & (KHR_DF_MASK_ ## X)) << (KHR_DF_SHIFT_ ## X))) + +/* Offsets relative to the start of a sample */ +typedef enum _khr_df_sampleword_e { + KHR_DF_SAMPLEWORD_BITOFFSET = 0U, + KHR_DF_SAMPLEWORD_BITLENGTH = 0U, + KHR_DF_SAMPLEWORD_CHANNELID = 0U, + KHR_DF_SAMPLEWORD_QUALIFIERS = 0U, + KHR_DF_SAMPLEWORD_SAMPLEPOSITION0 = 1U, + KHR_DF_SAMPLEWORD_SAMPLEPOSITION1 = 1U, + KHR_DF_SAMPLEWORD_SAMPLEPOSITION2 = 1U, + KHR_DF_SAMPLEWORD_SAMPLEPOSITION3 = 1U, + KHR_DF_SAMPLEWORD_SAMPLEPOSITION_ALL = 1U, + KHR_DF_SAMPLEWORD_SAMPLELOWER = 2U, + KHR_DF_SAMPLEWORD_SAMPLEUPPER = 3U +} khr_df_sampleword_e; + +typedef enum _khr_df_sampleshift_e { + KHR_DF_SAMPLESHIFT_BITOFFSET = 0U, + KHR_DF_SAMPLESHIFT_BITLENGTH = 16U, + KHR_DF_SAMPLESHIFT_CHANNELID = 24U, + /* N.B. Qualifiers are defined as an offset into a byte */ + KHR_DF_SAMPLESHIFT_QUALIFIERS = 24U, + KHR_DF_SAMPLESHIFT_SAMPLEPOSITION0 = 0U, + KHR_DF_SAMPLESHIFT_SAMPLEPOSITION1 = 8U, + KHR_DF_SAMPLESHIFT_SAMPLEPOSITION2 = 16U, + KHR_DF_SAMPLESHIFT_SAMPLEPOSITION3 = 24U, + KHR_DF_SAMPLESHIFT_SAMPLEPOSITION_ALL = 0U, + KHR_DF_SAMPLESHIFT_SAMPLELOWER = 0U, + KHR_DF_SAMPLESHIFT_SAMPLEUPPER = 0U +} khr_df_sampleshift_e; + +typedef enum _khr_df_samplemask_e { + KHR_DF_SAMPLEMASK_BITOFFSET = 0xFFFFU, + KHR_DF_SAMPLEMASK_BITLENGTH = 0xFF, + KHR_DF_SAMPLEMASK_CHANNELID = 0xF, + /* N.B. Qualifiers are defined as an offset into a byte */ + KHR_DF_SAMPLEMASK_QUALIFIERS = 0xF0, + KHR_DF_SAMPLEMASK_SAMPLEPOSITION0 = 0xFF, + KHR_DF_SAMPLEMASK_SAMPLEPOSITION1 = 0xFF, + KHR_DF_SAMPLEMASK_SAMPLEPOSITION2 = 0xFF, + KHR_DF_SAMPLEMASK_SAMPLEPOSITION3 = 0xFF, + /* ISO C restricts enum values to range of int hence the + cast. We do it verbosely instead of using -1 to ensure + it is a 32-bit value even if int is 64 bits. */ + KHR_DF_SAMPLEMASK_SAMPLEPOSITION_ALL = (int) 0xFFFFFFFFU, + KHR_DF_SAMPLEMASK_SAMPLELOWER = (int) 0xFFFFFFFFU, + KHR_DF_SAMPLEMASK_SAMPLEUPPER = (int) 0xFFFFFFFFU +} khr_df_samplemask_e; + +/* Helper macro: + Extract field X of sample S from basic descriptor block BDB */ +#define KHR_DFDSVAL(BDB, S, X) \ + (((BDB)[KHR_DF_WORD_SAMPLESTART + \ + ((S) * KHR_DF_WORD_SAMPLEWORDS) + \ + KHR_DF_SAMPLEWORD_ ## X] >> (KHR_DF_SAMPLESHIFT_ ## X)) \ + & (KHR_DF_SAMPLEMASK_ ## X)) + +/* Helper macro: + Set field X of sample S of basic descriptor block BDB */ +#define KHR_DFDSETSVAL(BDB, S, X, val) \ + ((BDB)[KHR_DF_WORD_SAMPLESTART + \ + ((S) * KHR_DF_WORD_SAMPLEWORDS) + \ + KHR_DF_SAMPLEWORD_ ## X] = \ + ((BDB)[KHR_DF_WORD_SAMPLESTART + \ + ((S) * KHR_DF_WORD_SAMPLEWORDS) + \ + KHR_DF_SAMPLEWORD_ ## X] & \ + ~((uint32_t)(KHR_DF_SAMPLEMASK_ ## X) << (KHR_DF_SAMPLESHIFT_ ## X))) | \ + (((val) & (uint32_t)(KHR_DF_SAMPLEMASK_ ## X)) << (KHR_DF_SAMPLESHIFT_ ## X))) + +/* Helper macro: + Number of samples in basic descriptor block BDB */ +#define KHR_DFDSAMPLECOUNT(BDB) \ + (((KHR_DFDVAL(BDB, DESCRIPTORBLOCKSIZE) >> 2) - \ + KHR_DF_WORD_SAMPLESTART) \ + / KHR_DF_WORD_SAMPLEWORDS) + +/* Helper macro: + Size in words of basic descriptor block for S samples */ +#define KHR_DFDSIZEWORDS(S) \ + (KHR_DF_WORD_SAMPLESTART + \ + (S) * KHR_DF_WORD_SAMPLEWORDS) + +/* Vendor ids */ +typedef enum _khr_df_vendorid_e { + /* Standard Khronos descriptor */ + KHR_DF_VENDORID_KHRONOS = 0U, + KHR_DF_VENDORID_MAX = 0x1FFFFU +} khr_df_vendorid_e; + +/* Descriptor types */ +typedef enum _khr_df_khr_descriptortype_e { + /* Default Khronos basic descriptor block */ + KHR_DF_KHR_DESCRIPTORTYPE_BASICFORMAT = 0U, + /* Extension descriptor block for additional planes */ + KHR_DF_KHR_DESCRIPTORTYPE_ADDITIONAL_PLANES = 0x6001U, + /* Extension descriptor block for additional dimensions */ + KHR_DF_KHR_DESCRIPTORTYPE_ADDITIONAL_DIMENSIONS = 0x6002U, + /* Bit indicates modifying requires understanding this extension */ + KHR_DF_KHR_DESCRIPTORTYPE_NEEDED_FOR_WRITE_BIT = 0x2000U, + /* Bit indicates processing requires understanding this extension */ + KHR_DF_KHR_DESCRIPTORTYPE_NEEDED_FOR_DECODE_BIT = 0x4000U, + KHR_DF_KHR_DESCRIPTORTYPE_MAX = 0x7FFFU +} khr_df_khr_descriptortype_e; + +/* Descriptor block version */ +typedef enum _khr_df_versionnumber_e { + /* Standard Khronos descriptor */ + KHR_DF_VERSIONNUMBER_1_0 = 0U, /* Version 1.0 of the specification */ + KHR_DF_VERSIONNUMBER_1_1 = 0U, /* Version 1.1 did not bump the version number */ + KHR_DF_VERSIONNUMBER_1_2 = 1U, /* Version 1.2 increased the version number */ + KHR_DF_VERSIONNUMBER_1_3 = 2U, /* Version 1.3 increased the version number */ + KHR_DF_VERSIONNUMBER_LATEST = KHR_DF_VERSIONNUMBER_1_3, + KHR_DF_VERSIONNUMBER_MAX = 0xFFFFU +} khr_df_versionnumber_e; + +/* Model in which the color coordinate space is defined. + There is no requirement that a color format use all the + channel types that are defined in the color model. */ +typedef enum _khr_df_model_e { + /* No interpretation of color channels defined */ + KHR_DF_MODEL_UNSPECIFIED = 0U, + /* Color primaries (red, green, blue) + alpha, depth and stencil */ + KHR_DF_MODEL_RGBSDA = 1U, + /* Color differences (Y', Cb, Cr) + alpha, depth and stencil */ + KHR_DF_MODEL_YUVSDA = 2U, + /* Color differences (Y', I, Q) + alpha, depth and stencil */ + KHR_DF_MODEL_YIQSDA = 3U, + /* Perceptual color (CIE L*a*b*) + alpha, depth and stencil */ + KHR_DF_MODEL_LABSDA = 4U, + /* Subtractive colors (cyan, magenta, yellow, black) + alpha */ + KHR_DF_MODEL_CMYKA = 5U, + /* Non-color coordinate data (X, Y, Z, W) */ + KHR_DF_MODEL_XYZW = 6U, + /* Hue, saturation, value, hue angle on color circle, plus alpha */ + KHR_DF_MODEL_HSVA_ANG = 7U, + /* Hue, saturation, lightness, hue angle on color circle, plus alpha */ + KHR_DF_MODEL_HSLA_ANG = 8U, + /* Hue, saturation, value, hue on color hexagon, plus alpha */ + KHR_DF_MODEL_HSVA_HEX = 9U, + /* Hue, saturation, lightness, hue on color hexagon, plus alpha */ + KHR_DF_MODEL_HSLA_HEX = 10U, + /* Lightweight approximate color difference (luma, orange, green) */ + KHR_DF_MODEL_YCGCOA = 11U, + /* ITU BT.2020 constant luminance YcCbcCrc */ + KHR_DF_MODEL_YCCBCCRC = 12U, + /* ITU BT.2100 constant intensity ICtCp */ + KHR_DF_MODEL_ICTCP = 13U, + /* CIE 1931 XYZ color coordinates (X, Y, Z) */ + KHR_DF_MODEL_CIEXYZ = 14U, + /* CIE 1931 xyY color coordinates (X, Y, Y) */ + KHR_DF_MODEL_CIEXYY = 15U, + + /* Compressed formats start at 128. */ + /* These compressed formats should generally have a single sample, + sited at the 0,0 position of the texel block. Where multiple + channels are used to distinguish formats, these should be cosited. */ + /* Direct3D (and S3) compressed formats */ + /* Note that premultiplied status is recorded separately */ + /* DXT1 "channels" are RGB (0), Alpha (1) */ + /* DXT1/BC1 with one channel is opaque */ + /* DXT1/BC1 with a cosited alpha sample is transparent */ + KHR_DF_MODEL_DXT1A = 128U, + KHR_DF_MODEL_BC1A = 128U, + /* DXT2/DXT3/BC2, with explicit 4-bit alpha */ + KHR_DF_MODEL_DXT2 = 129U, + KHR_DF_MODEL_DXT3 = 129U, + KHR_DF_MODEL_BC2 = 129U, + /* DXT4/DXT5/BC3, with interpolated alpha */ + KHR_DF_MODEL_DXT4 = 130U, + KHR_DF_MODEL_DXT5 = 130U, + KHR_DF_MODEL_BC3 = 130U, + /* BC4 - single channel interpolated 8-bit data */ + /* (The UNORM/SNORM variation is recorded in the channel data) */ + KHR_DF_MODEL_BC4 = 131U, + /* BC5 - two channel interpolated 8-bit data */ + /* (The UNORM/SNORM variation is recorded in the channel data) */ + KHR_DF_MODEL_BC5 = 132U, + /* BC6H - DX11 format for 16-bit float channels */ + KHR_DF_MODEL_BC6H = 133U, + /* BC7 - DX11 format */ + KHR_DF_MODEL_BC7 = 134U, + /* Gap left for future desktop expansion */ + + /* Mobile compressed formats follow */ + /* A format of ETC1 indicates that the format shall be decodable + by an ETC1-compliant decoder and not rely on ETC2 features */ + KHR_DF_MODEL_ETC1 = 160U, + /* A format of ETC2 is permitted to use ETC2 encodings on top of + the baseline ETC1 specification */ + /* The ETC2 format has channels "red", "green", "RGB" and "alpha", + which should be cosited samples */ + /* Punch-through alpha can be distinguished from full alpha by + the plane size in bytes required for the texel block */ + KHR_DF_MODEL_ETC2 = 161U, + /* Adaptive Scalable Texture Compression */ + /* ASTC HDR vs LDR is determined by the float flag in the channel */ + /* ASTC block size can be distinguished by texel block size */ + KHR_DF_MODEL_ASTC = 162U, + /* ETC1S is a simplified subset of ETC1 */ + KHR_DF_MODEL_ETC1S = 163U, + /* PowerVR Texture Compression */ + KHR_DF_MODEL_PVRTC = 164U, + KHR_DF_MODEL_PVRTC2 = 165U, + KHR_DF_MODEL_UASTC = 166U, + /* Proprietary formats (ATITC, etc.) should follow */ + KHR_DF_MODEL_MAX = 0xFFU +} khr_df_model_e; + +/* Definition of channel names for each color model */ +typedef enum _khr_df_model_channels_e { + /* Unspecified format with nominal channel numbering */ + KHR_DF_CHANNEL_UNSPECIFIED_0 = 0U, + KHR_DF_CHANNEL_UNSPECIFIED_1 = 1U, + KHR_DF_CHANNEL_UNSPECIFIED_2 = 2U, + KHR_DF_CHANNEL_UNSPECIFIED_3 = 3U, + KHR_DF_CHANNEL_UNSPECIFIED_4 = 4U, + KHR_DF_CHANNEL_UNSPECIFIED_5 = 5U, + KHR_DF_CHANNEL_UNSPECIFIED_6 = 6U, + KHR_DF_CHANNEL_UNSPECIFIED_7 = 7U, + KHR_DF_CHANNEL_UNSPECIFIED_8 = 8U, + KHR_DF_CHANNEL_UNSPECIFIED_9 = 9U, + KHR_DF_CHANNEL_UNSPECIFIED_10 = 10U, + KHR_DF_CHANNEL_UNSPECIFIED_11 = 11U, + KHR_DF_CHANNEL_UNSPECIFIED_12 = 12U, + KHR_DF_CHANNEL_UNSPECIFIED_13 = 13U, + KHR_DF_CHANNEL_UNSPECIFIED_14 = 14U, + KHR_DF_CHANNEL_UNSPECIFIED_15 = 15U, + /* MODEL_RGBSDA - red, green, blue, stencil, depth, alpha */ + KHR_DF_CHANNEL_RGBSDA_RED = 0U, + KHR_DF_CHANNEL_RGBSDA_R = 0U, + KHR_DF_CHANNEL_RGBSDA_GREEN = 1U, + KHR_DF_CHANNEL_RGBSDA_G = 1U, + KHR_DF_CHANNEL_RGBSDA_BLUE = 2U, + KHR_DF_CHANNEL_RGBSDA_B = 2U, + KHR_DF_CHANNEL_RGBSDA_STENCIL = 13U, + KHR_DF_CHANNEL_RGBSDA_S = 13U, + KHR_DF_CHANNEL_RGBSDA_DEPTH = 14U, + KHR_DF_CHANNEL_RGBSDA_D = 14U, + KHR_DF_CHANNEL_RGBSDA_ALPHA = 15U, + KHR_DF_CHANNEL_RGBSDA_A = 15U, + /* MODEL_YUVSDA - luma, Cb, Cr, stencil, depth, alpha */ + KHR_DF_CHANNEL_YUVSDA_Y = 0U, + KHR_DF_CHANNEL_YUVSDA_CB = 1U, + KHR_DF_CHANNEL_YUVSDA_U = 1U, + KHR_DF_CHANNEL_YUVSDA_CR = 2U, + KHR_DF_CHANNEL_YUVSDA_V = 2U, + KHR_DF_CHANNEL_YUVSDA_STENCIL = 13U, + KHR_DF_CHANNEL_YUVSDA_S = 13U, + KHR_DF_CHANNEL_YUVSDA_DEPTH = 14U, + KHR_DF_CHANNEL_YUVSDA_D = 14U, + KHR_DF_CHANNEL_YUVSDA_ALPHA = 15U, + KHR_DF_CHANNEL_YUVSDA_A = 15U, + /* MODEL_YIQSDA - luma, in-phase, quadrature, stencil, depth, alpha */ + KHR_DF_CHANNEL_YIQSDA_Y = 0U, + KHR_DF_CHANNEL_YIQSDA_I = 1U, + KHR_DF_CHANNEL_YIQSDA_Q = 2U, + KHR_DF_CHANNEL_YIQSDA_STENCIL = 13U, + KHR_DF_CHANNEL_YIQSDA_S = 13U, + KHR_DF_CHANNEL_YIQSDA_DEPTH = 14U, + KHR_DF_CHANNEL_YIQSDA_D = 14U, + KHR_DF_CHANNEL_YIQSDA_ALPHA = 15U, + KHR_DF_CHANNEL_YIQSDA_A = 15U, + /* MODEL_LABSDA - CIELAB/L*a*b* luma, red-green, blue-yellow, stencil, depth, alpha */ + KHR_DF_CHANNEL_LABSDA_L = 0U, + KHR_DF_CHANNEL_LABSDA_A = 1U, + KHR_DF_CHANNEL_LABSDA_B = 2U, + KHR_DF_CHANNEL_LABSDA_STENCIL = 13U, + KHR_DF_CHANNEL_LABSDA_S = 13U, + KHR_DF_CHANNEL_LABSDA_DEPTH = 14U, + KHR_DF_CHANNEL_LABSDA_D = 14U, + KHR_DF_CHANNEL_LABSDA_ALPHA = 15U, + /* NOTE: KHR_DF_CHANNEL_LABSDA_A is not a synonym for alpha! */ + /* MODEL_CMYKA - cyan, magenta, yellow, key/blacK, alpha */ + KHR_DF_CHANNEL_CMYKSDA_CYAN = 0U, + KHR_DF_CHANNEL_CMYKSDA_C = 0U, + KHR_DF_CHANNEL_CMYKSDA_MAGENTA = 1U, + KHR_DF_CHANNEL_CMYKSDA_M = 1U, + KHR_DF_CHANNEL_CMYKSDA_YELLOW = 2U, + KHR_DF_CHANNEL_CMYKSDA_Y = 2U, + KHR_DF_CHANNEL_CMYKSDA_KEY = 3U, + KHR_DF_CHANNEL_CMYKSDA_BLACK = 3U, + KHR_DF_CHANNEL_CMYKSDA_K = 3U, + KHR_DF_CHANNEL_CMYKSDA_ALPHA = 15U, + KHR_DF_CHANNEL_CMYKSDA_A = 15U, + /* MODEL_XYZW - coordinates x, y, z, w */ + KHR_DF_CHANNEL_XYZW_X = 0U, + KHR_DF_CHANNEL_XYZW_Y = 1U, + KHR_DF_CHANNEL_XYZW_Z = 2U, + KHR_DF_CHANNEL_XYZW_W = 3U, + /* MODEL_HSVA_ANG - value (luma), saturation, hue, alpha, angular projection, conical space */ + KHR_DF_CHANNEL_HSVA_ANG_VALUE = 0U, + KHR_DF_CHANNEL_HSVA_ANG_V = 0U, + KHR_DF_CHANNEL_HSVA_ANG_SATURATION = 1U, + KHR_DF_CHANNEL_HSVA_ANG_S = 1U, + KHR_DF_CHANNEL_HSVA_ANG_HUE = 2U, + KHR_DF_CHANNEL_HSVA_ANG_H = 2U, + KHR_DF_CHANNEL_HSVA_ANG_ALPHA = 15U, + KHR_DF_CHANNEL_HSVA_ANG_A = 15U, + /* MODEL_HSLA_ANG - lightness (luma), saturation, hue, alpha, angular projection, double conical space */ + KHR_DF_CHANNEL_HSLA_ANG_LIGHTNESS = 0U, + KHR_DF_CHANNEL_HSLA_ANG_L = 0U, + KHR_DF_CHANNEL_HSLA_ANG_SATURATION = 1U, + KHR_DF_CHANNEL_HSLA_ANG_S = 1U, + KHR_DF_CHANNEL_HSLA_ANG_HUE = 2U, + KHR_DF_CHANNEL_HSLA_ANG_H = 2U, + KHR_DF_CHANNEL_HSLA_ANG_ALPHA = 15U, + KHR_DF_CHANNEL_HSLA_ANG_A = 15U, + /* MODEL_HSVA_HEX - value (luma), saturation, hue, alpha, hexagonal projection, conical space */ + KHR_DF_CHANNEL_HSVA_HEX_VALUE = 0U, + KHR_DF_CHANNEL_HSVA_HEX_V = 0U, + KHR_DF_CHANNEL_HSVA_HEX_SATURATION = 1U, + KHR_DF_CHANNEL_HSVA_HEX_S = 1U, + KHR_DF_CHANNEL_HSVA_HEX_HUE = 2U, + KHR_DF_CHANNEL_HSVA_HEX_H = 2U, + KHR_DF_CHANNEL_HSVA_HEX_ALPHA = 15U, + KHR_DF_CHANNEL_HSVA_HEX_A = 15U, + /* MODEL_HSLA_HEX - lightness (luma), saturation, hue, alpha, hexagonal projection, double conical space */ + KHR_DF_CHANNEL_HSLA_HEX_LIGHTNESS = 0U, + KHR_DF_CHANNEL_HSLA_HEX_L = 0U, + KHR_DF_CHANNEL_HSLA_HEX_SATURATION = 1U, + KHR_DF_CHANNEL_HSLA_HEX_S = 1U, + KHR_DF_CHANNEL_HSLA_HEX_HUE = 2U, + KHR_DF_CHANNEL_HSLA_HEX_H = 2U, + KHR_DF_CHANNEL_HSLA_HEX_ALPHA = 15U, + KHR_DF_CHANNEL_HSLA_HEX_A = 15U, + /* MODEL_YCGCOA - luma, green delta, orange delta, alpha */ + KHR_DF_CHANNEL_YCGCOA_Y = 0U, + KHR_DF_CHANNEL_YCGCOA_CG = 1U, + KHR_DF_CHANNEL_YCGCOA_CO = 2U, + KHR_DF_CHANNEL_YCGCOA_ALPHA = 15U, + KHR_DF_CHANNEL_YCGCOA_A = 15U, + /* MODEL_CIEXYZ - CIE 1931 X, Y, Z */ + KHR_DF_CHANNEL_CIEXYZ_X = 0U, + KHR_DF_CHANNEL_CIEXYZ_Y = 1U, + KHR_DF_CHANNEL_CIEXYZ_Z = 2U, + /* MODEL_CIEXYY - CIE 1931 x, y, Y */ + KHR_DF_CHANNEL_CIEXYY_X = 0U, + KHR_DF_CHANNEL_CIEXYY_YCHROMA = 1U, + KHR_DF_CHANNEL_CIEXYY_YLUMA = 2U, + + /* Compressed formats */ + /* MODEL_DXT1A/MODEL_BC1A */ + KHR_DF_CHANNEL_DXT1A_COLOR = 0U, + KHR_DF_CHANNEL_BC1A_COLOR = 0U, + KHR_DF_CHANNEL_DXT1A_ALPHAPRESENT = 1U, + KHR_DF_CHANNEL_DXT1A_ALPHA = 1U, + KHR_DF_CHANNEL_BC1A_ALPHAPRESENT = 1U, + KHR_DF_CHANNEL_BC1A_ALPHA = 1U, + /* MODEL_DXT2/3/MODEL_BC2 */ + KHR_DF_CHANNEL_DXT2_COLOR = 0U, + KHR_DF_CHANNEL_DXT3_COLOR = 0U, + KHR_DF_CHANNEL_BC2_COLOR = 0U, + KHR_DF_CHANNEL_DXT2_ALPHA = 15U, + KHR_DF_CHANNEL_DXT3_ALPHA = 15U, + KHR_DF_CHANNEL_BC2_ALPHA = 15U, + /* MODEL_DXT4/5/MODEL_BC3 */ + KHR_DF_CHANNEL_DXT4_COLOR = 0U, + KHR_DF_CHANNEL_DXT5_COLOR = 0U, + KHR_DF_CHANNEL_BC3_COLOR = 0U, + KHR_DF_CHANNEL_DXT4_ALPHA = 15U, + KHR_DF_CHANNEL_DXT5_ALPHA = 15U, + KHR_DF_CHANNEL_BC3_ALPHA = 15U, + /* MODEL_BC4 */ + KHR_DF_CHANNEL_BC4_DATA = 0U, + /* MODEL_BC5 */ + KHR_DF_CHANNEL_BC5_RED = 0U, + KHR_DF_CHANNEL_BC5_R = 0U, + KHR_DF_CHANNEL_BC5_GREEN = 1U, + KHR_DF_CHANNEL_BC5_G = 1U, + /* MODEL_BC6H */ + KHR_DF_CHANNEL_BC6H_COLOR = 0U, + KHR_DF_CHANNEL_BC6H_DATA = 0U, + /* MODEL_BC7 */ + KHR_DF_CHANNEL_BC7_DATA = 0U, + KHR_DF_CHANNEL_BC7_COLOR = 0U, + /* MODEL_ETC1 */ + KHR_DF_CHANNEL_ETC1_DATA = 0U, + KHR_DF_CHANNEL_ETC1_COLOR = 0U, + /* MODEL_ETC2 */ + KHR_DF_CHANNEL_ETC2_RED = 0U, + KHR_DF_CHANNEL_ETC2_R = 0U, + KHR_DF_CHANNEL_ETC2_GREEN = 1U, + KHR_DF_CHANNEL_ETC2_G = 1U, + KHR_DF_CHANNEL_ETC2_COLOR = 2U, + KHR_DF_CHANNEL_ETC2_ALPHA = 15U, + KHR_DF_CHANNEL_ETC2_A = 15U, + /* MODEL_ASTC */ + KHR_DF_CHANNEL_ASTC_DATA = 0U, + /* MODEL_ETC1S */ + KHR_DF_CHANNEL_ETC1S_RGB = 0U, + KHR_DF_CHANNEL_ETC1S_RRR = 3U, + KHR_DF_CHANNEL_ETC1S_GGG = 4U, + KHR_DF_CHANNEL_ETC1S_AAA = 15U, + /* MODEL_PVRTC */ + KHR_DF_CHANNEL_PVRTC_DATA = 0U, + KHR_DF_CHANNEL_PVRTC_COLOR = 0U, + /* MODEL_PVRTC2 */ + KHR_DF_CHANNEL_PVRTC2_DATA = 0U, + KHR_DF_CHANNEL_PVRTC2_COLOR = 0U, + /* MODEL UASTC */ + KHR_DF_CHANNEL_UASTC_DATA = 0U, + KHR_DF_CHANNEL_UASTC_RGB = 0U, + KHR_DF_CHANNEL_UASTC_RGBA = 3U, + KHR_DF_CHANNEL_UASTC_RRR = 4U, + KHR_DF_CHANNEL_UASTC_RRRG = 5U, + KHR_DF_CHANNEL_UASTC_RG = 6U, + + /* Common channel names shared by multiple formats */ + KHR_DF_CHANNEL_COMMON_LUMA = 0U, + KHR_DF_CHANNEL_COMMON_L = 0U, + KHR_DF_CHANNEL_COMMON_STENCIL = 13U, + KHR_DF_CHANNEL_COMMON_S = 13U, + KHR_DF_CHANNEL_COMMON_DEPTH = 14U, + KHR_DF_CHANNEL_COMMON_D = 14U, + KHR_DF_CHANNEL_COMMON_ALPHA = 15U, + KHR_DF_CHANNEL_COMMON_A = 15U +} khr_df_model_channels_e; + +/* Definition of the primary colors in color coordinates. + This is implicitly responsible for defining the conversion + between RGB an YUV color spaces. + LAB and related absolute color models should use + KHR_DF_PRIMARIES_CIEXYZ. */ +typedef enum _khr_df_primaries_e { + /* No color primaries defined */ + KHR_DF_PRIMARIES_UNSPECIFIED = 0U, + /* Color primaries of ITU-R BT.709 and sRGB */ + KHR_DF_PRIMARIES_BT709 = 1U, + /* Synonym for KHR_DF_PRIMARIES_BT709 */ + KHR_DF_PRIMARIES_SRGB = 1U, + /* Color primaries of ITU-R BT.601 (625-line EBU variant) */ + KHR_DF_PRIMARIES_BT601_EBU = 2U, + /* Color primaries of ITU-R BT.601 (525-line SMPTE C variant) */ + KHR_DF_PRIMARIES_BT601_SMPTE = 3U, + /* Color primaries of ITU-R BT.2020 */ + KHR_DF_PRIMARIES_BT2020 = 4U, + /* CIE theoretical color coordinate space */ + KHR_DF_PRIMARIES_CIEXYZ = 5U, + /* Academy Color Encoding System primaries */ + KHR_DF_PRIMARIES_ACES = 6U, + /* Color primaries of ACEScc */ + KHR_DF_PRIMARIES_ACESCC = 7U, + /* Legacy NTSC 1953 primaries */ + KHR_DF_PRIMARIES_NTSC1953 = 8U, + /* Legacy PAL 525-line primaries */ + KHR_DF_PRIMARIES_PAL525 = 9U, + /* Color primaries of Display P3 */ + KHR_DF_PRIMARIES_DISPLAYP3 = 10U, + /* Color primaries of Adobe RGB (1998) */ + KHR_DF_PRIMARIES_ADOBERGB = 11U, + KHR_DF_PRIMARIES_MAX = 0xFFU +} khr_df_primaries_e; + +/* Definition of the optical to digital transfer function + ("gamma correction"). Most transfer functions are not a pure + power function and also include a linear element. + LAB and related absolute color representations should use + KHR_DF_TRANSFER_UNSPECIFIED. */ +typedef enum _khr_df_transfer_e { + /* No transfer function defined */ + KHR_DF_TRANSFER_UNSPECIFIED = 0U, + /* Linear transfer function (value proportional to intensity) */ + KHR_DF_TRANSFER_LINEAR = 1U, + /* Perceptually-linear transfer function of sRGH (~2.4) */ + KHR_DF_TRANSFER_SRGB = 2U, + /* Perceptually-linear transfer function of ITU BT.601, BT.709 and BT.2020 (~1/.45) */ + KHR_DF_TRANSFER_ITU = 3U, + /* SMTPE170M (digital NTSC) defines an alias for the ITU transfer function (~1/.45) */ + KHR_DF_TRANSFER_SMTPE170M = 3U, + /* Perceptually-linear gamma function of original NTSC (simple 2.2 gamma) */ + KHR_DF_TRANSFER_NTSC = 4U, + /* Sony S-log used by Sony video cameras */ + KHR_DF_TRANSFER_SLOG = 5U, + /* Sony S-log 2 used by Sony video cameras */ + KHR_DF_TRANSFER_SLOG2 = 6U, + /* ITU BT.1886 EOTF */ + KHR_DF_TRANSFER_BT1886 = 7U, + /* ITU BT.2100 HLG OETF */ + KHR_DF_TRANSFER_HLG_OETF = 8U, + /* ITU BT.2100 HLG EOTF */ + KHR_DF_TRANSFER_HLG_EOTF = 9U, + /* ITU BT.2100 PQ EOTF */ + KHR_DF_TRANSFER_PQ_EOTF = 10U, + /* ITU BT.2100 PQ OETF */ + KHR_DF_TRANSFER_PQ_OETF = 11U, + /* DCI P3 transfer function */ + KHR_DF_TRANSFER_DCIP3 = 12U, + /* Legacy PAL OETF */ + KHR_DF_TRANSFER_PAL_OETF = 13U, + /* Legacy PAL 625-line EOTF */ + KHR_DF_TRANSFER_PAL625_EOTF = 14U, + /* Legacy ST240 transfer function */ + KHR_DF_TRANSFER_ST240 = 15U, + /* ACEScc transfer function */ + KHR_DF_TRANSFER_ACESCC = 16U, + /* ACEScct transfer function */ + KHR_DF_TRANSFER_ACESCCT = 17U, + /* Adobe RGB (1998) transfer function */ + KHR_DF_TRANSFER_ADOBERGB = 18U, + KHR_DF_TRANSFER_MAX = 0xFFU +} khr_df_transfer_e; + +typedef enum _khr_df_flags_e { + KHR_DF_FLAG_ALPHA_STRAIGHT = 0U, + KHR_DF_FLAG_ALPHA_PREMULTIPLIED = 1U +} khr_df_flags_e; + +typedef enum _khr_df_sample_datatype_qualifiers_e { + KHR_DF_SAMPLE_DATATYPE_LINEAR = 1U << 4U, + KHR_DF_SAMPLE_DATATYPE_EXPONENT = 1U << 5U, + KHR_DF_SAMPLE_DATATYPE_SIGNED = 1U << 6U, + KHR_DF_SAMPLE_DATATYPE_FLOAT = 1U << 7U +} khr_df_sample_datatype_qualifiers_e; + +#endif diff --git a/thirdparty/libktx/lib/dfdutils/colourspaces.c b/thirdparty/libktx/lib/dfdutils/colourspaces.c new file mode 100644 index 000000000000..0d998a71aa7e --- /dev/null +++ b/thirdparty/libktx/lib/dfdutils/colourspaces.c @@ -0,0 +1,51 @@ +/* Copyright 2019-2020 The Khronos Group Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @~English + * @brief Helper functions for colourspaces. + */ + +#include +#include "dfd.h" + +typedef struct s_PrimaryMapping { + khr_df_primaries_e dfPrimaryEnum; + Primaries primaries; +} sPrimaryMapping; + +sPrimaryMapping primaryMap[] = { + { KHR_DF_PRIMARIES_BT709, { 0.640f,0.330f, 0.300f,0.600f, 0.150f,0.060f, 0.3127f,0.3290f}}, + { KHR_DF_PRIMARIES_BT601_EBU, { 0.640f,0.330f, 0.290f,0.600f, 0.150f,0.060f, 0.3127f,0.3290f}}, + { KHR_DF_PRIMARIES_BT601_SMPTE, { 0.630f,0.340f, 0.310f,0.595f, 0.155f,0.070f, 0.3127f,0.3290f}}, + { KHR_DF_PRIMARIES_BT2020, { 0.708f,0.292f, 0.170f,0.797f, 0.131f,0.046f, 0.3127f,0.3290f}}, + { KHR_DF_PRIMARIES_CIEXYZ, { 1.0f,0.0f, 0.0f,1.0f, 0.0f,0.0f, 0.0f,1.0f}}, + { KHR_DF_PRIMARIES_ACES, { 0.7347f,0.2653f, 0.0f,1.0f, 0.0001f,-0.077f, 0.32168f,0.33767f}}, + { KHR_DF_PRIMARIES_ACESCC, { 0.713f,0.293f, 0.165f,0.830f, 0.128f,0.044f, 0.32168f,0.33767f}}, + { KHR_DF_PRIMARIES_NTSC1953, { 0.67f,0.33f, 0.21f,0.71f, 0.14f,0.08f, 0.310f,0.316f}}, + { KHR_DF_PRIMARIES_PAL525, { 0.630f,0.340f, 0.310f,0.595f, 0.155f,0.070f, 0.3101f,0.3162f}}, + { KHR_DF_PRIMARIES_DISPLAYP3, { 0.6800f,0.3200f, 0.2650f,0.69f, 0.1500f,0.0600f, 0.3127f,0.3290f}}, + { KHR_DF_PRIMARIES_ADOBERGB, { 0.6400f,0.3300f, 0.2100f,0.71f, 0.1500f,0.0600f, 0.3127f,0.3290f}}}; + +/** + * @brief Map a set of primaries to a KDFS primaries enum. + * + * @param[in] p pointer to a Primaries struct filled in with the primary values. + * @param[in] latitude tolerance to use while matching. A suitable value might be 0.002 + * but it depends on the application. + */ +khr_df_primaries_e findMapping(Primaries *p, float latitude) { + unsigned int i; + for (i = 0; i < sizeof(primaryMap)/sizeof(sPrimaryMapping); ++i) { + if (primaryMap[i].primaries.Rx - p->Rx <= latitude && p->Rx - primaryMap[i].primaries.Rx <= latitude && + primaryMap[i].primaries.Gx - p->Gx <= latitude && p->Gx - primaryMap[i].primaries.Gx <= latitude && + primaryMap[i].primaries.Bx - p->Bx <= latitude && p->Bx - primaryMap[i].primaries.Bx <= latitude && + primaryMap[i].primaries.Wx - p->Wx <= latitude && p->Wx - primaryMap[i].primaries.Wx <= latitude) { + return primaryMap[i].dfPrimaryEnum; + } + } + /* No match */ + return KHR_DF_PRIMARIES_UNSPECIFIED; +} diff --git a/thirdparty/libktx/lib/dfdutils/createdfd.c b/thirdparty/libktx/lib/dfdutils/createdfd.c new file mode 100644 index 000000000000..ea00d8d74580 --- /dev/null +++ b/thirdparty/libktx/lib/dfdutils/createdfd.c @@ -0,0 +1,659 @@ +/* -*- tab-width: 4; -*- */ +/* vi: set sw=2 ts=4 expandtab: */ + +/* Copyright 2019-2020 The Khronos Group Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @~English + * @brief Utilities for creating data format descriptors. + */ + +/* + * Author: Andrew Garrard + */ + +#include +#include + +#include "dfd.h" + +typedef enum { i_COLOR, i_NON_COLOR } channels_infotype; + +static uint32_t *writeHeader(int numSamples, int bytes, int suffix, + channels_infotype infotype) +{ + uint32_t *DFD = (uint32_t *) malloc(sizeof(uint32_t) * + (1 + KHR_DF_WORD_SAMPLESTART + + numSamples * KHR_DF_WORD_SAMPLEWORDS)); + uint32_t* BDFD = DFD+1; + DFD[0] = sizeof(uint32_t) * + (1 + KHR_DF_WORD_SAMPLESTART + + numSamples * KHR_DF_WORD_SAMPLEWORDS); + BDFD[KHR_DF_WORD_VENDORID] = + (KHR_DF_VENDORID_KHRONOS << KHR_DF_SHIFT_VENDORID) | + (KHR_DF_KHR_DESCRIPTORTYPE_BASICFORMAT << KHR_DF_SHIFT_DESCRIPTORTYPE); + BDFD[KHR_DF_WORD_VERSIONNUMBER] = + (KHR_DF_VERSIONNUMBER_LATEST << KHR_DF_SHIFT_VERSIONNUMBER) | + (((uint32_t)sizeof(uint32_t) * + (KHR_DF_WORD_SAMPLESTART + + numSamples * KHR_DF_WORD_SAMPLEWORDS) + << KHR_DF_SHIFT_DESCRIPTORBLOCKSIZE)); + BDFD[KHR_DF_WORD_MODEL] = + ((KHR_DF_MODEL_RGBSDA << KHR_DF_SHIFT_MODEL) | /* Only supported model */ + (KHR_DF_FLAG_ALPHA_STRAIGHT << KHR_DF_SHIFT_FLAGS)); + if (infotype == i_COLOR) { + BDFD[KHR_DF_WORD_PRIMARIES] |= KHR_DF_PRIMARIES_BT709 << KHR_DF_SHIFT_PRIMARIES; /* Assumed */ + } else { + BDFD[KHR_DF_WORD_PRIMARIES] |= KHR_DF_PRIMARIES_UNSPECIFIED << KHR_DF_SHIFT_PRIMARIES; + } + if (suffix == s_SRGB) { + BDFD[KHR_DF_WORD_TRANSFER] |= KHR_DF_TRANSFER_SRGB << KHR_DF_SHIFT_TRANSFER; + } else { + BDFD[KHR_DF_WORD_TRANSFER] |= KHR_DF_TRANSFER_LINEAR << KHR_DF_SHIFT_TRANSFER; + } + BDFD[KHR_DF_WORD_TEXELBLOCKDIMENSION0] = 0; /* Only 1x1x1x1 texel blocks supported */ + BDFD[KHR_DF_WORD_BYTESPLANE0] = bytes; /* bytesPlane0 = bytes, bytesPlane3..1 = 0 */ + BDFD[KHR_DF_WORD_BYTESPLANE4] = 0; /* bytesPlane7..5 = 0 */ + return DFD; +} + +static uint32_t setChannelFlags(uint32_t channel, enum VkSuffix suffix) +{ + switch (suffix) { + case s_UNORM: break; + case s_SNORM: + channel |= + KHR_DF_SAMPLE_DATATYPE_SIGNED; + break; + case s_USCALED: break; + case s_SSCALED: + channel |= + KHR_DF_SAMPLE_DATATYPE_SIGNED; + break; + case s_UINT: break; + case s_SINT: + channel |= + KHR_DF_SAMPLE_DATATYPE_SIGNED; + break; + case s_SFLOAT: + channel |= + KHR_DF_SAMPLE_DATATYPE_FLOAT | + KHR_DF_SAMPLE_DATATYPE_SIGNED; + break; + case s_UFLOAT: + channel |= + KHR_DF_SAMPLE_DATATYPE_FLOAT; + break; + case s_SRGB: + if (channel == KHR_DF_CHANNEL_RGBSDA_ALPHA) { + channel |= KHR_DF_SAMPLE_DATATYPE_LINEAR; + } + break; + } + return channel; +} + +static void writeSample(uint32_t *DFD, int sampleNo, int channel, + int bits, int offset, + int topSample, int bottomSample, enum VkSuffix suffix) +{ + // Use this to avoid type-punning complaints from the gcc optimizer + // with -Wall. + union { + uint32_t i; + float f; + } lower, upper; + uint32_t *sample = DFD + 1 + KHR_DF_WORD_SAMPLESTART + sampleNo * KHR_DF_WORD_SAMPLEWORDS; + if (channel == 3) channel = KHR_DF_CHANNEL_RGBSDA_ALPHA; + + if (channel == 3) channel = KHR_DF_CHANNEL_RGBSDA_ALPHA; + channel = setChannelFlags(channel, suffix); + + sample[KHR_DF_SAMPLEWORD_BITOFFSET] = + (offset << KHR_DF_SAMPLESHIFT_BITOFFSET) | + ((bits - 1) << KHR_DF_SAMPLESHIFT_BITLENGTH) | + (channel << KHR_DF_SAMPLESHIFT_CHANNELID); + + sample[KHR_DF_SAMPLEWORD_SAMPLEPOSITION_ALL] = 0; + + switch (suffix) { + case s_UNORM: + case s_SRGB: + default: + if (bits > 32) { + upper.i = 0xFFFFFFFFU; + } else { + upper.i = (uint32_t)((1U << bits) - 1U); + } + lower.i = 0U; + break; + case s_SNORM: + if (bits > 32) { + upper.i = 0x7FFFFFFF; + } else { + upper.i = topSample ? (1U << (bits - 1)) - 1 : (1U << bits) - 1; + } + lower.i = ~upper.i; + if (bottomSample) lower.i += 1; + break; + case s_USCALED: + case s_UINT: + upper.i = bottomSample ? 1U : 0U; + lower.i = 0U; + break; + case s_SSCALED: + case s_SINT: + upper.i = bottomSample ? 1U : 0U; + lower.i = ~0U; + break; + case s_SFLOAT: + upper.f = 1.0f; + lower.f = -1.0f; + break; + case s_UFLOAT: + upper.f = 1.0f; + lower.f = 0.0f; + break; + } + sample[KHR_DF_SAMPLEWORD_SAMPLELOWER] = lower.i; + sample[KHR_DF_SAMPLEWORD_SAMPLEUPPER] = upper.i; +} + +/** + * @~English + * @brief Create a Data Format Descriptor for an unpacked format. + * + * @param bigEndian Set to 1 for big-endian byte ordering and + 0 for little-endian byte ordering. + * @param numChannels The number of color channels. + * @param bytes The number of bytes per channel. + * @param redBlueSwap Normally channels appear in consecutive R, G, B, A order + * in memory; redBlueSwap inverts red and blue, allowing + * B, G, R, A. + * @param suffix Indicates the format suffix for the type. + * + * @return A data format descriptor in malloc'd data. The caller is responsible + * for freeing the descriptor. + **/ +uint32_t *createDFDUnpacked(int bigEndian, int numChannels, int bytes, + int redBlueSwap, enum VkSuffix suffix) +{ + uint32_t *DFD; + if (bigEndian) { + int channelCounter, channelByte; + /* Number of samples = number of channels * bytes per channel */ + DFD = writeHeader(numChannels * bytes, numChannels * bytes, suffix, i_COLOR); + /* First loop over the channels */ + for (channelCounter = 0; channelCounter < numChannels; ++channelCounter) { + int channel = channelCounter; + if (redBlueSwap && (channel == 0 || channel == 2)) { + channel ^= 2; + } + /* Loop over the bytes that constitute a channel */ + for (channelByte = 0; channelByte < bytes; ++channelByte) { + writeSample(DFD, channelCounter * bytes + channelByte, channel, + 8, 8 * (channelCounter * bytes + bytes - channelByte - 1), + channelByte == bytes-1, channelByte == 0, suffix); + } + } + + } else { /* Little-endian */ + + int sampleCounter; + /* One sample per channel */ + DFD = writeHeader(numChannels, numChannels * bytes, suffix, i_COLOR); + for (sampleCounter = 0; sampleCounter < numChannels; ++sampleCounter) { + int channel = sampleCounter; + if (redBlueSwap && (channel == 0 || channel == 2)) { + channel ^= 2; + } + writeSample(DFD, sampleCounter, channel, + 8 * bytes, 8 * sampleCounter * bytes, + 1, 1, suffix); + } + } + return DFD; +} + +/** + * @~English + * @brief Create a Data Format Descriptor for a packed format. + * + * @param bigEndian Big-endian flag: Set to 1 for big-endian byte ordering and + * 0 for little-endian byte ordering. + * @param numChannels The number of color channels. + * @param bits[] An array of length numChannels. + * Each entry is the number of bits composing the channel, in + * order starting at bit 0 of the packed type. + * @param channels[] An array of length numChannels. + * Each entry enumerates the channel type: 0 = red, 1 = green, + * 2 = blue, 15 = alpha, in order starting at bit 0 of the + * packed type. These values match channel IDs for RGBSDA in + * the Khronos Data Format header. To simplify iteration + * through channels, channel id 3 is a synonym for alpha. + * @param suffix Indicates the format suffix for the type. + * + * @return A data format descriptor in malloc'd data. The caller is responsible + * for freeing the descriptor. + **/ +uint32_t *createDFDPacked(int bigEndian, int numChannels, + int bits[], int channels[], + enum VkSuffix suffix) +{ + uint32_t *DFD = 0; + if (numChannels == 6) { + /* Special case E5B9G9R9 */ + DFD = writeHeader(numChannels, 4, s_UFLOAT, i_COLOR); + writeSample(DFD, 0, 0, + 9, 0, + 1, 1, s_UNORM); + KHR_DFDSETSVAL((DFD+1), 0, SAMPLEUPPER, 8448); + writeSample(DFD, 1, 0 | KHR_DF_SAMPLE_DATATYPE_EXPONENT, + 5, 27, + 1, 1, s_UNORM); + KHR_DFDSETSVAL((DFD+1), 1, SAMPLELOWER, 15); + KHR_DFDSETSVAL((DFD+1), 1, SAMPLEUPPER, 31); + writeSample(DFD, 2, 1, + 9, 9, + 1, 1, s_UNORM); + KHR_DFDSETSVAL((DFD+1), 2, SAMPLEUPPER, 8448); + writeSample(DFD, 3, 1 | KHR_DF_SAMPLE_DATATYPE_EXPONENT, + 5, 27, + 1, 1, s_UNORM); + KHR_DFDSETSVAL((DFD+1), 3, SAMPLELOWER, 15); + KHR_DFDSETSVAL((DFD+1), 3, SAMPLEUPPER, 31); + writeSample(DFD, 4, 2, + 9, 18, + 1, 1, s_UNORM); + KHR_DFDSETSVAL((DFD+1), 4, SAMPLEUPPER, 8448); + writeSample(DFD, 5, 2 | KHR_DF_SAMPLE_DATATYPE_EXPONENT, + 5, 27, + 1, 1, s_UNORM); + KHR_DFDSETSVAL((DFD+1), 5, SAMPLELOWER, 15); + KHR_DFDSETSVAL((DFD+1), 5, SAMPLEUPPER, 31); + } else if (bigEndian) { + /* No packed format is larger than 32 bits. */ + /* No packed channel crosses more than two bytes. */ + int totalBits = 0; + int bitChannel[32]; + int beChannelStart[4]; + int channelCounter; + int bitOffset = 0; + int BEMask; + int numSamples = numChannels; + int sampleCounter; + for (channelCounter = 0; channelCounter < numChannels; ++channelCounter) { + beChannelStart[channelCounter] = totalBits; + totalBits += bits[channelCounter]; + } + BEMask = (totalBits - 1) & 0x18; + for (channelCounter = 0; channelCounter < numChannels; ++channelCounter) { + bitChannel[bitOffset ^ BEMask] = channelCounter; + if (((bitOffset + bits[channelCounter] - 1) & ~7) != (bitOffset & ~7)) { + /* Continuation sample */ + bitChannel[((bitOffset + bits[channelCounter] - 1) & ~7) ^ BEMask] = channelCounter; + numSamples++; + } + bitOffset += bits[channelCounter]; + } + DFD = writeHeader(numSamples, totalBits >> 3, suffix, i_COLOR); + + sampleCounter = 0; + for (bitOffset = 0; bitOffset < totalBits;) { + if (bitChannel[bitOffset] == -1) { + /* Done this bit, so this is the lower half of something. */ + /* We must therefore jump to the end of the byte and continue. */ + bitOffset = (bitOffset + 8) & ~7; + } else { + /* Start of a channel? */ + int thisChannel = bitChannel[bitOffset]; + if ((beChannelStart[thisChannel] ^ BEMask) == bitOffset) { + /* Must be just one sample if we hit it first. */ + writeSample(DFD, sampleCounter++, channels[thisChannel], + bits[thisChannel], bitOffset, + 1, 1, suffix); + bitOffset += bits[thisChannel]; + } else { + /* Two samples. Move to the end of the first one we hit when we're done. */ + int firstSampleBits = 8 - (beChannelStart[thisChannel] & 0x7); /* Rest of the byte */ + int secondSampleBits = bits[thisChannel] - firstSampleBits; /* Rest of the bits */ + writeSample(DFD, sampleCounter++, channels[thisChannel], + firstSampleBits, beChannelStart[thisChannel] ^ BEMask, + 0, 1, suffix); + /* Mark that we've already handled this sample */ + bitChannel[beChannelStart[thisChannel] ^ BEMask] = -1; + writeSample(DFD, sampleCounter++, channels[thisChannel], + secondSampleBits, bitOffset, + 1, 0, suffix); + bitOffset += secondSampleBits; + } + } + } + + } else { /* Little-endian */ + + int sampleCounter; + int totalBits = 0; + int bitOffset = 0; + for (sampleCounter = 0; sampleCounter < numChannels; ++sampleCounter) { + totalBits += bits[sampleCounter]; + } + + /* One sample per channel */ + DFD = writeHeader(numChannels, totalBits >> 3, suffix, i_COLOR); + for (sampleCounter = 0; sampleCounter < numChannels; ++sampleCounter) { + writeSample(DFD, sampleCounter, channels[sampleCounter], + bits[sampleCounter], bitOffset, + 1, 1, suffix); + bitOffset += bits[sampleCounter]; + } + } + return DFD; +} + +static khr_df_model_e compModelMapping[] = { + KHR_DF_MODEL_BC1A, /*!< BC1, aka DXT1, no alpha. */ + KHR_DF_MODEL_BC1A, /*!< BC1, aka DXT1, punch-through alpha. */ + KHR_DF_MODEL_BC2, /*!< BC2, aka DXT2 and DXT3. */ + KHR_DF_MODEL_BC3, /*!< BC3, aka DXT4 and DXT5. */ + KHR_DF_MODEL_BC4, /*!< BC4. */ + KHR_DF_MODEL_BC5, /*!< BC5. */ + KHR_DF_MODEL_BC6H, /*!< BC6h HDR format. */ + KHR_DF_MODEL_BC7, /*!< BC7. */ + KHR_DF_MODEL_ETC2, /*!< ETC2 no alpha. */ + KHR_DF_MODEL_ETC2, /*!< ETC2 punch-through alpha. */ + KHR_DF_MODEL_ETC2, /*!< ETC2 independent alpha. */ + KHR_DF_MODEL_ETC2, /*!< R11 ETC2 single-channel. */ + KHR_DF_MODEL_ETC2, /*!< R11G11 ETC2 dual-channel. */ + KHR_DF_MODEL_ASTC, /*!< ASTC. */ + KHR_DF_MODEL_ETC1S, /*!< ETC1S. */ + KHR_DF_MODEL_PVRTC, /*!< PVRTC(1). */ + KHR_DF_MODEL_PVRTC2 /*!< PVRTC2. */ +}; + +static uint32_t compSampleCount[] = { + 1U, /*!< BC1, aka DXT1, no alpha. */ + 1U, /*!< BC1, aka DXT1, punch-through alpha. */ + 2U, /*!< BC2, aka DXT2 and DXT3. */ + 2U, /*!< BC3, aka DXT4 and DXT5. */ + 1U, /*!< BC4. */ + 2U, /*!< BC5. */ + 1U, /*!< BC6h HDR format. */ + 1U, /*!< BC7. */ + 1U, /*!< ETC2 no alpha. */ + 2U, /*!< ETC2 punch-through alpha. */ + 2U, /*!< ETC2 independent alpha. */ + 1U, /*!< R11 ETC2 single-channel. */ + 2U, /*!< R11G11 ETC2 dual-channel. */ + 1U, /*!< ASTC. */ + 1U, /*!< ETC1S. */ + 1U, /*!< PVRTC. */ + 1U /*!< PVRTC2. */ +}; + +static khr_df_model_channels_e compFirstChannel[] = { + KHR_DF_CHANNEL_BC1A_COLOR, /*!< BC1, aka DXT1, no alpha. */ + KHR_DF_CHANNEL_BC1A_ALPHAPRESENT, /*!< BC1, aka DXT1, punch-through alpha. */ + KHR_DF_CHANNEL_BC2_ALPHA, /*!< BC2, aka DXT2 and DXT3. */ + KHR_DF_CHANNEL_BC3_ALPHA, /*!< BC3, aka DXT4 and DXT5. */ + KHR_DF_CHANNEL_BC4_DATA, /*!< BC4. */ + KHR_DF_CHANNEL_BC5_RED, /*!< BC5. */ + KHR_DF_CHANNEL_BC6H_COLOR, /*!< BC6h HDR format. */ + KHR_DF_CHANNEL_BC7_COLOR, /*!< BC7. */ + KHR_DF_CHANNEL_ETC2_COLOR, /*!< ETC2 no alpha. */ + KHR_DF_CHANNEL_ETC2_COLOR, /*!< ETC2 punch-through alpha. */ + KHR_DF_CHANNEL_ETC2_ALPHA, /*!< ETC2 independent alpha. */ + KHR_DF_CHANNEL_ETC2_RED, /*!< R11 ETC2 single-channel. */ + KHR_DF_CHANNEL_ETC2_RED, /*!< R11G11 ETC2 dual-channel. */ + KHR_DF_CHANNEL_ASTC_DATA, /*!< ASTC. */ + KHR_DF_CHANNEL_ETC1S_RGB, /*!< ETC1S. */ + KHR_DF_CHANNEL_PVRTC_COLOR, /*!< PVRTC. */ + KHR_DF_CHANNEL_PVRTC2_COLOR /*!< PVRTC2. */ +}; + +static khr_df_model_channels_e compSecondChannel[] = { + KHR_DF_CHANNEL_BC1A_COLOR, /*!< BC1, aka DXT1, no alpha. */ + KHR_DF_CHANNEL_BC1A_ALPHAPRESENT, /*!< BC1, aka DXT1, punch-through alpha. */ + KHR_DF_CHANNEL_BC2_COLOR, /*!< BC2, aka DXT2 and DXT3. */ + KHR_DF_CHANNEL_BC3_COLOR, /*!< BC3, aka DXT4 and DXT5. */ + KHR_DF_CHANNEL_BC4_DATA, /*!< BC4. */ + KHR_DF_CHANNEL_BC5_GREEN, /*!< BC5. */ + KHR_DF_CHANNEL_BC6H_COLOR, /*!< BC6h HDR format. */ + KHR_DF_CHANNEL_BC7_COLOR, /*!< BC7. */ + KHR_DF_CHANNEL_ETC2_COLOR, /*!< ETC2 no alpha. */ + KHR_DF_CHANNEL_ETC2_ALPHA, /*!< ETC2 punch-through alpha. */ + KHR_DF_CHANNEL_ETC2_COLOR, /*!< ETC2 independent alpha. */ + KHR_DF_CHANNEL_ETC2_RED, /*!< R11 ETC2 single-channel. */ + KHR_DF_CHANNEL_ETC2_GREEN, /*!< R11G11 ETC2 dual-channel. */ + KHR_DF_CHANNEL_ASTC_DATA, /*!< ASTC. */ + KHR_DF_CHANNEL_ETC1S_RGB, /*!< ETC1S. */ + KHR_DF_CHANNEL_PVRTC_COLOR, /*!< PVRTC. */ + KHR_DF_CHANNEL_PVRTC2_COLOR /*!< PVRTC2. */ +}; + +static uint32_t compSecondChannelOffset[] = { + 0U, /*!< BC1, aka DXT1, no alpha. */ + 0U, /*!< BC1, aka DXT1, punch-through alpha. */ + 64U, /*!< BC2, aka DXT2 and DXT3. */ + 64U, /*!< BC3, aka DXT4 and DXT5. */ + 0U, /*!< BC4. */ + 64U, /*!< BC5. */ + 0U, /*!< BC6h HDR format. */ + 0U, /*!< BC7. */ + 0U, /*!< ETC2 no alpha. */ + 0U, /*!< ETC2 punch-through alpha. */ + 64U, /*!< ETC2 independent alpha. */ + 0U, /*!< R11 ETC2 single-channel. */ + 64U, /*!< R11G11 ETC2 dual-channel. */ + 0U, /*!< ASTC. */ + 0U, /*!< ETC1S. */ + 0U, /*!< PVRTC. */ + 0U /*!< PVRTC2. */ +}; + +static uint32_t compChannelBits[] = { + 64U, /*!< BC1, aka DXT1, no alpha. */ + 64U, /*!< BC1, aka DXT1, punch-through alpha. */ + 64U, /*!< BC2, aka DXT2 and DXT3. */ + 64U, /*!< BC3, aka DXT4 and DXT5. */ + 64U, /*!< BC4. */ + 64U, /*!< BC5. */ + 128U, /*!< BC6h HDR format. */ + 128U, /*!< BC7. */ + 64U, /*!< ETC2 no alpha. */ + 64U, /*!< ETC2 punch-through alpha. */ + 64U, /*!< ETC2 independent alpha. */ + 64U, /*!< R11 ETC2 single-channel. */ + 64U, /*!< R11G11 ETC2 dual-channel. */ + 128U, /*!< ASTC. */ + 64U, /*!< ETC1S. */ + 64U, /*!< PVRTC. */ + 64U /*!< PVRTC2. */ +}; + +static uint32_t compBytes[] = { + 8U, /*!< BC1, aka DXT1, no alpha. */ + 8U, /*!< BC1, aka DXT1, punch-through alpha. */ + 16U, /*!< BC2, aka DXT2 and DXT3. */ + 16U, /*!< BC3, aka DXT4 and DXT5. */ + 8U, /*!< BC4. */ + 16U, /*!< BC5. */ + 16U, /*!< BC6h HDR format. */ + 16U, /*!< BC7. */ + 8U, /*!< ETC2 no alpha. */ + 8U, /*!< ETC2 punch-through alpha. */ + 16U, /*!< ETC2 independent alpha. */ + 8U, /*!< R11 ETC2 single-channel. */ + 16U, /*!< R11G11 ETC2 dual-channel. */ + 16U, /*!< ASTC. */ + 8U, /*!< ETC1S. */ + 8U, /*!< PVRTC. */ + 8U /*!< PVRTC2. */ +}; + +/** + * @~English + * @brief Create a Data Format Descriptor for a compressed format. + * + * @param compScheme Vulkan-style compression scheme enumeration. + * @param bwidth Block width in texel coordinates. + * @param bheight Block height in texel coordinates. + * @param bdepth Block depth in texel coordinates. + * @author Mark Callow, Edgewise Consulting. + * @param suffix Indicates the format suffix for the type. + * + * @return A data format descriptor in malloc'd data. The caller is responsible + * for freeing the descriptor. + **/ +uint32_t *createDFDCompressed(enum VkCompScheme compScheme, int bwidth, int bheight, int bdepth, + enum VkSuffix suffix) +{ + uint32_t *DFD = 0; + uint32_t numSamples = compSampleCount[compScheme]; + uint32_t* BDFD; + uint32_t *sample; + uint32_t channel; + // Use union to avoid type-punning complaints from gcc optimizer + // with -Wall. + union { + uint32_t i; + float f; + } lower, upper; + + DFD = (uint32_t *) malloc(sizeof(uint32_t) * + (1 + KHR_DF_WORD_SAMPLESTART + + numSamples * KHR_DF_WORD_SAMPLEWORDS)); + BDFD = DFD+1; + DFD[0] = sizeof(uint32_t) * + (1 + KHR_DF_WORD_SAMPLESTART + + numSamples * KHR_DF_WORD_SAMPLEWORDS); + BDFD[KHR_DF_WORD_VENDORID] = + (KHR_DF_VENDORID_KHRONOS << KHR_DF_SHIFT_VENDORID) | + (KHR_DF_KHR_DESCRIPTORTYPE_BASICFORMAT << KHR_DF_SHIFT_DESCRIPTORTYPE); + BDFD[KHR_DF_WORD_VERSIONNUMBER] = + (KHR_DF_VERSIONNUMBER_LATEST << KHR_DF_SHIFT_VERSIONNUMBER) | + (((uint32_t)sizeof(uint32_t) * + (KHR_DF_WORD_SAMPLESTART + + numSamples * KHR_DF_WORD_SAMPLEWORDS) + << KHR_DF_SHIFT_DESCRIPTORBLOCKSIZE)); + BDFD[KHR_DF_WORD_MODEL] = + ((compModelMapping[compScheme] << KHR_DF_SHIFT_MODEL) | + (KHR_DF_PRIMARIES_BT709 << KHR_DF_SHIFT_PRIMARIES) | /* Assumed */ + (KHR_DF_FLAG_ALPHA_STRAIGHT << KHR_DF_SHIFT_FLAGS)); + + if (suffix == s_SRGB) { + BDFD[KHR_DF_WORD_TRANSFER] |= KHR_DF_TRANSFER_SRGB << KHR_DF_SHIFT_TRANSFER; + } else { + BDFD[KHR_DF_WORD_TRANSFER] |= KHR_DF_TRANSFER_LINEAR << KHR_DF_SHIFT_TRANSFER; + } + BDFD[KHR_DF_WORD_TEXELBLOCKDIMENSION0] = + (bwidth - 1) | ((bheight - 1) << KHR_DF_SHIFT_TEXELBLOCKDIMENSION1) | ((bdepth - 1) << KHR_DF_SHIFT_TEXELBLOCKDIMENSION2); + /* bytesPlane0 = bytes, bytesPlane3..1 = 0 */ + BDFD[KHR_DF_WORD_BYTESPLANE0] = compBytes[compScheme]; + BDFD[KHR_DF_WORD_BYTESPLANE4] = 0; /* bytesPlane7..5 = 0 */ + + sample = BDFD + KHR_DF_WORD_SAMPLESTART; + channel = compFirstChannel[compScheme]; + channel = setChannelFlags(channel, suffix); + + sample[KHR_DF_SAMPLEWORD_BITOFFSET] = + (0 << KHR_DF_SAMPLESHIFT_BITOFFSET) | + ((compChannelBits[compScheme] - 1) << KHR_DF_SAMPLESHIFT_BITLENGTH) | + (channel << KHR_DF_SAMPLESHIFT_CHANNELID); + + sample[KHR_DF_SAMPLEWORD_SAMPLEPOSITION_ALL] = 0; + switch (suffix) { + case s_UNORM: + case s_SRGB: + default: + upper.i = 0xFFFFFFFFU; + lower.i = 0U; + break; + case s_SNORM: + upper.i = 0x7FFFFFFF; + lower.i = ~upper.i; + break; + case s_USCALED: + case s_UINT: + upper.i = 1U; + lower.i = 0U; + break; + case s_SSCALED: + case s_SINT: + upper.i = 1U; + lower.i = ~0U; + break; + case s_SFLOAT: + upper.f = 1.0f; + lower.f = -1.0f; + break; + case s_UFLOAT: + upper.f = 1.0f; + lower.f = 0.0f; + break; + } + sample[KHR_DF_SAMPLEWORD_SAMPLELOWER] = lower.i; + sample[KHR_DF_SAMPLEWORD_SAMPLEUPPER] = upper.i; + + if (compSampleCount[compScheme] > 1) { + sample += KHR_DF_WORD_SAMPLEWORDS; + channel = compSecondChannel[compScheme]; + channel = setChannelFlags(channel, suffix); + + sample[KHR_DF_SAMPLEWORD_BITOFFSET] = + (compSecondChannelOffset[compScheme] << KHR_DF_SAMPLESHIFT_BITOFFSET) | + ((compChannelBits[compScheme] - 1) << KHR_DF_SAMPLESHIFT_BITLENGTH) | + (channel << KHR_DF_SAMPLESHIFT_CHANNELID); + + sample[KHR_DF_SAMPLEWORD_SAMPLEPOSITION_ALL] = 0; + + sample[KHR_DF_SAMPLEWORD_SAMPLELOWER] = lower.i; + sample[KHR_DF_SAMPLEWORD_SAMPLEUPPER] = upper.i; + } + return DFD; +} + +/** + * @~English + * @brief Create a Data Format Descriptor for a depth-stencil format. + * + * @param depthBits The numeber of bits in the depth channel. + * @param stencilBits The numeber of bits in the stencil channel. + * @param sizeBytes The total byte size of the texel. + * + * @return A data format descriptor in malloc'd data. The caller is responsible + * for freeing the descriptor. + **/ +uint32_t *createDFDDepthStencil(int depthBits, + int stencilBits, + int sizeBytes) +{ + /* N.B. Little-endian is assumed. */ + uint32_t *DFD = 0; + DFD = writeHeader((depthBits > 0) + (stencilBits > 0), + sizeBytes, s_UNORM, i_NON_COLOR); + if (depthBits == 32) { + writeSample(DFD, 0, KHR_DF_CHANNEL_RGBSDA_DEPTH, + 32, 0, + 1, 1, s_SFLOAT); + } else if (depthBits > 0) { + writeSample(DFD, 0, KHR_DF_CHANNEL_RGBSDA_DEPTH, + depthBits, 0, + 1, 1, s_UNORM); + } + if (stencilBits > 0) { + if (depthBits > 0) { + writeSample(DFD, 1, KHR_DF_CHANNEL_RGBSDA_STENCIL, + stencilBits, depthBits, + 1, 1, s_UINT); + } else { + writeSample(DFD, 0, KHR_DF_CHANNEL_RGBSDA_STENCIL, + stencilBits, 0, + 1, 1, s_UINT); + } + } + return DFD; +} diff --git a/thirdparty/libktx/lib/dfdutils/dfd.h b/thirdparty/libktx/lib/dfdutils/dfd.h new file mode 100644 index 000000000000..3ba0249dbb2d --- /dev/null +++ b/thirdparty/libktx/lib/dfdutils/dfd.h @@ -0,0 +1,170 @@ +/* -*- tab-width: 4; -*- */ +/* vi: set sw=2 ts=4 expandtab: */ + +/* Copyright 2019-2020 The Khronos Group Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @~English + * @brief Header file defining the data format descriptor utilities API. + */ + +/* + * Author: Andrew Garrard + */ + +#ifndef _DFD_H_ +#define _DFD_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** Qualifier suffix to the format, in Vulkan terms. */ +enum VkSuffix { + s_UNORM, /*!< Unsigned normalized format. */ + s_SNORM, /*!< Signed normalized format. */ + s_USCALED, /*!< Unsigned scaled format. */ + s_SSCALED, /*!< Signed scaled format. */ + s_UINT, /*!< Unsigned integer format. */ + s_SINT, /*!< Signed integer format. */ + s_SFLOAT, /*!< Signed float format. */ + s_UFLOAT, /*!< Unsigned float format. */ + s_SRGB /*!< sRGB normalized format. */ +}; + +/** Compression scheme, in Vulkan terms. */ +enum VkCompScheme { + c_BC1_RGB, /*!< BC1, aka DXT1, no alpha. */ + c_BC1_RGBA, /*!< BC1, aka DXT1, punch-through alpha. */ + c_BC2, /*!< BC2, aka DXT2 and DXT3. */ + c_BC3, /*!< BC3, aka DXT4 and DXT5. */ + c_BC4, /*!< BC4. */ + c_BC5, /*!< BC5. */ + c_BC6H, /*!< BC6h HDR format. */ + c_BC7, /*!< BC7. */ + c_ETC2_R8G8B8, /*!< ETC2 no alpha. */ + c_ETC2_R8G8B8A1, /*!< ETC2 punch-through alpha. */ + c_ETC2_R8G8B8A8, /*!< ETC2 independent alpha. */ + c_EAC_R11, /*!< R11 ETC2 single-channel. */ + c_EAC_R11G11, /*!< R11G11 ETC2 dual-channel. */ + c_ASTC, /*!< ASTC. */ + c_ETC1S, /*!< ETC1S. */ + c_PVRTC, /*!< PVRTC(1). */ + c_PVRTC2 /*!< PVRTC2. */ +}; + +typedef unsigned int uint32_t; + +#if !defined(LIBKTX) +#include +#else +#include "../vkformat_enum.h" +#endif + +uint32_t* vk2dfd(enum VkFormat format); + +/* Create a Data Format Descriptor for an unpacked format. */ +uint32_t *createDFDUnpacked(int bigEndian, int numChannels, int bytes, + int redBlueSwap, enum VkSuffix suffix); + +/* Create a Data Format Descriptor for a packed format. */ +uint32_t *createDFDPacked(int bigEndian, int numChannels, + int bits[], int channels[], + enum VkSuffix suffix); + +/* Create a Data Format Descriptor for a compressed format. */ +uint32_t *createDFDCompressed(enum VkCompScheme compScheme, + int bwidth, int bheight, int bdepth, + enum VkSuffix suffix); + +/* Create a Data Format Descriptor for a depth/stencil format. */ +uint32_t *createDFDDepthStencil(int depthBits, + int stencilBits, + int sizeBytes); + +/** @brief Result of interpreting the data format descriptor. */ +enum InterpretDFDResult { + i_LITTLE_ENDIAN_FORMAT_BIT = 0, /*!< Confirmed little-endian (default for 8bpc). */ + i_BIG_ENDIAN_FORMAT_BIT = 1, /*!< Confirmed big-endian. */ + i_PACKED_FORMAT_BIT = 2, /*!< Packed format. */ + i_SRGB_FORMAT_BIT = 4, /*!< sRGB transfer function. */ + i_NORMALIZED_FORMAT_BIT = 8, /*!< Normalized (UNORM or SNORM). */ + i_SIGNED_FORMAT_BIT = 16, /*!< Format is signed. */ + i_FLOAT_FORMAT_BIT = 32, /*!< Format is floating point. */ + i_UNSUPPORTED_ERROR_BIT = 64, /*!< Format not successfully interpreted. */ + /** "NONTRIVIAL_ENDIANNESS" means not big-endian, not little-endian + * (a channel has bits that are not consecutive in either order). **/ + i_UNSUPPORTED_NONTRIVIAL_ENDIANNESS = i_UNSUPPORTED_ERROR_BIT, + /** "MULTIPLE_SAMPLE_LOCATIONS" is an error because only single-sample + * texel blocks (with coordinates 0,0,0,0 for all samples) are supported. **/ + i_UNSUPPORTED_MULTIPLE_SAMPLE_LOCATIONS = i_UNSUPPORTED_ERROR_BIT + 1, + /** "MULTIPLE_PLANES" is an error because only contiguous data is supported. */ + i_UNSUPPORTED_MULTIPLE_PLANES = i_UNSUPPORTED_ERROR_BIT + 2, + /** Only channels R, G, B and A are supported. */ + i_UNSUPPORTED_CHANNEL_TYPES = i_UNSUPPORTED_ERROR_BIT + 3, + /** Only channels with the same flags are supported + * (e.g. we don't support float red with integer green). */ + i_UNSUPPORTED_MIXED_CHANNELS = i_UNSUPPORTED_ERROR_BIT + 4 +}; + +/** @brief Interpretation of a channel from the data format descriptor. */ +typedef struct _InterpretedDFDChannel { + uint32_t offset; /*!< Offset in bits for packed, bytes for unpacked. */ + uint32_t size; /*!< Size in bits for packed, bytes for unpacked. */ +} InterpretedDFDChannel; + +/* Interpret a Data Format Descriptor. */ +enum InterpretDFDResult interpretDFD(const uint32_t *DFD, + InterpretedDFDChannel *R, + InterpretedDFDChannel *G, + InterpretedDFDChannel *B, + InterpretedDFDChannel *A, + uint32_t *wordBytes); + +/* Print a human-readable interpretation of a data format descriptor. */ +void printDFD(uint32_t *DFD); + +/* Get the number of components & component size from a DFD for an + * unpacked format. + */ +void +getDFDComponentInfoUnpacked(const uint32_t* DFD, uint32_t* numComponents, + uint32_t* componentByteLength); + +/* Return the number of components described by a DFD. */ +uint32_t getDFDNumComponents(const uint32_t* DFD); + +/* Recreate and return the value of bytesPlane0 as it should be for the data + * post-inflation from variable-rate compression. + */ +void +recreateBytesPlane0FromSampleInfo(const uint32_t* DFD, uint32_t* bytesPlane0); + +/** @brief Colourspace primaries information. + * + * Structure to store the 1931 CIE x,y chromaticities of the red, green, and blue + * display primaries and the reference white point of a colourspace. + */ +typedef struct _Primaries { + float Rx; /*!< Red x. */ + float Ry; /*!< Red y. */ + float Gx; /*!< Green x. */ + float Gy; /*!< Green y. */ + float Bx; /*!< Blue x. */ + float By; /*!< Blue y. */ + float Wx; /*!< White x. */ + float Wy; /*!< White y. */ +} Primaries; + +khr_df_primaries_e findMapping(Primaries *p, float latitude); + +#ifdef __cplusplus +} +#endif + +#endif /* _DFD_H_ */ diff --git a/thirdparty/libktx/lib/dfdutils/dfd2vk.inl b/thirdparty/libktx/lib/dfdutils/dfd2vk.inl new file mode 100644 index 000000000000..cfed9140e9f2 --- /dev/null +++ b/thirdparty/libktx/lib/dfdutils/dfd2vk.inl @@ -0,0 +1,599 @@ +/* Copyright 2019-2020 The Khronos Group Inc. */ +/* SPDX-License-Identifier: Apache-2.0 */ + +/***************************** Do not edit. ***************************** + Automatically generated by makedfd2vk.pl. + *************************************************************************/ +if (KHR_DFDVAL(dfd + 1, MODEL) == KHR_DF_MODEL_RGBSDA) { + enum InterpretDFDResult r; + InterpretedDFDChannel R = {0,0}; + InterpretedDFDChannel G = {0,0}; + InterpretedDFDChannel B = {0,0}; + InterpretedDFDChannel A = {0,0}; + uint32_t wordBytes; + + /* Special case exponent format */ + if (KHR_DFDSAMPLECOUNT(dfd + 1) == 6 && + ((KHR_DFDSVAL((dfd + 1), 1, QUALIFIERS) & KHR_DF_SAMPLE_DATATYPE_EXPONENT) > 0)) { + /* The only format we expect to be encoded like this. */ + return VK_FORMAT_E5B9G9R9_UFLOAT_PACK32; + } + + /* Special case depth formats (assumed little-endian) */ + if (KHR_DFDSVAL((dfd + 1), 0, CHANNELID) == KHR_DF_CHANNEL_RGBSDA_DEPTH) { + if (KHR_DFDSAMPLECOUNT((dfd + 1)) == 1) { + if (KHR_DFDSVAL((dfd + 1), 0, BITLENGTH) == 16-1) return VK_FORMAT_D16_UNORM; + if (KHR_DFDSVAL((dfd + 1), 0, BITLENGTH) == 24-1) return VK_FORMAT_X8_D24_UNORM_PACK32; + return VK_FORMAT_D32_SFLOAT; + } else { + if (KHR_DFDSVAL((dfd + 1), 0, BITLENGTH) == 16-1) return VK_FORMAT_D16_UNORM_S8_UINT; + if (KHR_DFDSVAL((dfd + 1), 0, BITLENGTH) == 24-1) return VK_FORMAT_D24_UNORM_S8_UINT; + return VK_FORMAT_D32_SFLOAT_S8_UINT; + } + } + if (KHR_DFDSVAL((dfd + 1), 0, CHANNELID) == KHR_DF_CHANNEL_RGBSDA_STENCIL) { + return VK_FORMAT_S8_UINT; + } + + r = interpretDFD(dfd, &R, &G, &B, &A, &wordBytes); + + if (r & i_UNSUPPORTED_ERROR_BIT) return VK_FORMAT_UNDEFINED; + + if (r & i_PACKED_FORMAT_BIT) { + if (wordBytes == 1) return VK_FORMAT_R4G4_UNORM_PACK8; + else if (wordBytes == 2) { /* PACK16 */ + if (A.size == 4) { + if (R.offset == 12) return VK_FORMAT_R4G4B4A4_UNORM_PACK16; + else return VK_FORMAT_B4G4R4A4_UNORM_PACK16; + } else if (A.size == 0) { /* Three channels */ + if (B.offset == 0) return VK_FORMAT_R5G6B5_UNORM_PACK16; + else return VK_FORMAT_B5G6R5_UNORM_PACK16; + } else { /* Four channels, one-bit alpha */ + if (B.offset == 0) return VK_FORMAT_A1R5G5B5_UNORM_PACK16; + if (B.offset == 1) return VK_FORMAT_R5G5B5A1_UNORM_PACK16; + return VK_FORMAT_B5G5R5A1_UNORM_PACK16; + } + } else if (wordBytes == 4) { /* PACK32 */ + if (A.size == 8) { + if ((r & i_SRGB_FORMAT_BIT)) return VK_FORMAT_A8B8G8R8_SRGB_PACK32; + if ((r & i_NORMALIZED_FORMAT_BIT) && !(r & i_SIGNED_FORMAT_BIT)) return VK_FORMAT_A8B8G8R8_UNORM_PACK32; + if ((r & i_NORMALIZED_FORMAT_BIT) && (r & i_SIGNED_FORMAT_BIT)) return VK_FORMAT_A8B8G8R8_SNORM_PACK32; + if (!(r & i_NORMALIZED_FORMAT_BIT) && !(r & i_SIGNED_FORMAT_BIT)) return VK_FORMAT_A8B8G8R8_UINT_PACK32; + if (!(r & i_NORMALIZED_FORMAT_BIT) && (r & i_SIGNED_FORMAT_BIT)) return VK_FORMAT_A8B8G8R8_SINT_PACK32; + } else if (A.size == 2 && B.offset == 0) { + if ((r & i_NORMALIZED_FORMAT_BIT) && !(r & i_SIGNED_FORMAT_BIT)) return VK_FORMAT_A2R10G10B10_UNORM_PACK32; + if ((r & i_NORMALIZED_FORMAT_BIT) && (r & i_SIGNED_FORMAT_BIT)) return VK_FORMAT_A2R10G10B10_SNORM_PACK32; + if (!(r & i_NORMALIZED_FORMAT_BIT) && !(r & i_SIGNED_FORMAT_BIT)) return VK_FORMAT_A2R10G10B10_UINT_PACK32; + if (!(r & i_NORMALIZED_FORMAT_BIT) && (r & i_SIGNED_FORMAT_BIT)) return VK_FORMAT_A2R10G10B10_SINT_PACK32; + } else if (A.size == 2 && R.offset == 0) { + if ((r & i_NORMALIZED_FORMAT_BIT) && !(r & i_SIGNED_FORMAT_BIT)) return VK_FORMAT_A2B10G10R10_UNORM_PACK32; + if ((r & i_NORMALIZED_FORMAT_BIT) && (r & i_SIGNED_FORMAT_BIT)) return VK_FORMAT_A2B10G10R10_SNORM_PACK32; + if (!(r & i_NORMALIZED_FORMAT_BIT) && !(r & i_SIGNED_FORMAT_BIT)) return VK_FORMAT_A2B10G10R10_UINT_PACK32; + if (!(r & i_NORMALIZED_FORMAT_BIT) && (r & i_SIGNED_FORMAT_BIT)) return VK_FORMAT_A2B10G10R10_SINT_PACK32; + } else if (R.size == 11) return VK_FORMAT_B10G11R11_UFLOAT_PACK32; + } + } else { /* Not a packed format */ + if (wordBytes == 1) { + if (A.size > 0) { /* 4 channels */ + if (R.offset == 0) { /* RGBA */ + if ((r & i_SRGB_FORMAT_BIT)) return VK_FORMAT_R8G8B8A8_SRGB; + if ((r & i_NORMALIZED_FORMAT_BIT) && !(r & i_SIGNED_FORMAT_BIT)) return VK_FORMAT_R8G8B8A8_UNORM; + if ((r & i_NORMALIZED_FORMAT_BIT) && (r & i_SIGNED_FORMAT_BIT)) return VK_FORMAT_R8G8B8A8_SNORM; + if (!(r & i_NORMALIZED_FORMAT_BIT) && !(r & i_SIGNED_FORMAT_BIT)) return VK_FORMAT_R8G8B8A8_UINT; + if (!(r & i_NORMALIZED_FORMAT_BIT) && (r & i_SIGNED_FORMAT_BIT)) return VK_FORMAT_R8G8B8A8_SINT; + } else { /* BGRA */ + if ((r & i_SRGB_FORMAT_BIT)) return VK_FORMAT_B8G8R8A8_SRGB; + if ((r & i_NORMALIZED_FORMAT_BIT) && !(r & i_SIGNED_FORMAT_BIT)) return VK_FORMAT_B8G8R8A8_UNORM; + if ((r & i_NORMALIZED_FORMAT_BIT) && (r & i_SIGNED_FORMAT_BIT)) return VK_FORMAT_B8G8R8A8_SNORM; + if (!(r & i_NORMALIZED_FORMAT_BIT) && !(r & i_SIGNED_FORMAT_BIT)) return VK_FORMAT_B8G8R8A8_UINT; + if (!(r & i_NORMALIZED_FORMAT_BIT) && (r & i_SIGNED_FORMAT_BIT)) return VK_FORMAT_B8G8R8A8_SINT; + } + } else if (B.size > 0) { /* 3 channels */ + if (R.offset == 0) { /* RGB */ + if ((r & i_SRGB_FORMAT_BIT)) return VK_FORMAT_R8G8B8_SRGB; + if ((r & i_NORMALIZED_FORMAT_BIT) && !(r & i_SIGNED_FORMAT_BIT)) return VK_FORMAT_R8G8B8_UNORM; + if ((r & i_NORMALIZED_FORMAT_BIT) && (r & i_SIGNED_FORMAT_BIT)) return VK_FORMAT_R8G8B8_SNORM; + if (!(r & i_NORMALIZED_FORMAT_BIT) && !(r & i_SIGNED_FORMAT_BIT)) return VK_FORMAT_R8G8B8_UINT; + if (!(r & i_NORMALIZED_FORMAT_BIT) && (r & i_SIGNED_FORMAT_BIT)) return VK_FORMAT_R8G8B8_SINT; + } else { /* BGR */ + if ((r & i_SRGB_FORMAT_BIT)) return VK_FORMAT_B8G8R8_SRGB; + if ((r & i_NORMALIZED_FORMAT_BIT) && !(r & i_SIGNED_FORMAT_BIT)) return VK_FORMAT_B8G8R8_UNORM; + if ((r & i_NORMALIZED_FORMAT_BIT) && (r & i_SIGNED_FORMAT_BIT)) return VK_FORMAT_B8G8R8_SNORM; + if (!(r & i_NORMALIZED_FORMAT_BIT) && !(r & i_SIGNED_FORMAT_BIT)) return VK_FORMAT_B8G8R8_UINT; + if (!(r & i_NORMALIZED_FORMAT_BIT) && (r & i_SIGNED_FORMAT_BIT)) return VK_FORMAT_B8G8R8_SINT; + } + } else if (G.size > 0) { /* 2 channels */ + if ((r & i_SRGB_FORMAT_BIT)) return VK_FORMAT_R8G8_SRGB; + if ((r & i_NORMALIZED_FORMAT_BIT) && !(r & i_SIGNED_FORMAT_BIT)) return VK_FORMAT_R8G8_UNORM; + if ((r & i_NORMALIZED_FORMAT_BIT) && (r & i_SIGNED_FORMAT_BIT)) return VK_FORMAT_R8G8_SNORM; + if (!(r & i_NORMALIZED_FORMAT_BIT) && !(r & i_SIGNED_FORMAT_BIT)) return VK_FORMAT_R8G8_UINT; + if (!(r & i_NORMALIZED_FORMAT_BIT) && (r & i_SIGNED_FORMAT_BIT)) return VK_FORMAT_R8G8_SINT; + } else { /* 1 channel */ + if ((r & i_SRGB_FORMAT_BIT)) return VK_FORMAT_R8_SRGB; + if ((r & i_NORMALIZED_FORMAT_BIT) && !(r & i_SIGNED_FORMAT_BIT)) return VK_FORMAT_R8_UNORM; + if ((r & i_NORMALIZED_FORMAT_BIT) && (r & i_SIGNED_FORMAT_BIT)) return VK_FORMAT_R8_SNORM; + if (!(r & i_NORMALIZED_FORMAT_BIT) && !(r & i_SIGNED_FORMAT_BIT)) return VK_FORMAT_R8_UINT; + if (!(r & i_NORMALIZED_FORMAT_BIT) && (r & i_SIGNED_FORMAT_BIT)) return VK_FORMAT_R8_SINT; + } + } else if (wordBytes == 2) { + if (A.size > 0) { /* 4 channels */ + if (R.offset == 0) { /* RGBA */ + if ((r & i_FLOAT_FORMAT_BIT)) return VK_FORMAT_R16G16B16A16_SFLOAT; + if ((r & i_NORMALIZED_FORMAT_BIT) && !(r & i_SIGNED_FORMAT_BIT)) return VK_FORMAT_R16G16B16A16_UNORM; + if ((r & i_NORMALIZED_FORMAT_BIT) && (r & i_SIGNED_FORMAT_BIT)) return VK_FORMAT_R16G16B16A16_SNORM; + if (!(r & i_NORMALIZED_FORMAT_BIT) && !(r & i_SIGNED_FORMAT_BIT)) return VK_FORMAT_R16G16B16A16_UINT; + if (!(r & i_NORMALIZED_FORMAT_BIT) && (r & i_SIGNED_FORMAT_BIT)) return VK_FORMAT_R16G16B16A16_SINT; + } else { /* BGRA */ + } + } else if (B.size > 0) { /* 3 channels */ + if (R.offset == 0) { /* RGB */ + if ((r & i_FLOAT_FORMAT_BIT)) return VK_FORMAT_R16G16B16_SFLOAT; + if ((r & i_NORMALIZED_FORMAT_BIT) && !(r & i_SIGNED_FORMAT_BIT)) return VK_FORMAT_R16G16B16_UNORM; + if ((r & i_NORMALIZED_FORMAT_BIT) && (r & i_SIGNED_FORMAT_BIT)) return VK_FORMAT_R16G16B16_SNORM; + if (!(r & i_NORMALIZED_FORMAT_BIT) && !(r & i_SIGNED_FORMAT_BIT)) return VK_FORMAT_R16G16B16_UINT; + if (!(r & i_NORMALIZED_FORMAT_BIT) && (r & i_SIGNED_FORMAT_BIT)) return VK_FORMAT_R16G16B16_SINT; + } else { /* BGR */ + } + } else if (G.size > 0) { /* 2 channels */ + if ((r & i_FLOAT_FORMAT_BIT)) return VK_FORMAT_R16G16_SFLOAT; + if ((r & i_NORMALIZED_FORMAT_BIT) && !(r & i_SIGNED_FORMAT_BIT)) return VK_FORMAT_R16G16_UNORM; + if ((r & i_NORMALIZED_FORMAT_BIT) && (r & i_SIGNED_FORMAT_BIT)) return VK_FORMAT_R16G16_SNORM; + if (!(r & i_NORMALIZED_FORMAT_BIT) && !(r & i_SIGNED_FORMAT_BIT)) return VK_FORMAT_R16G16_UINT; + if (!(r & i_NORMALIZED_FORMAT_BIT) && (r & i_SIGNED_FORMAT_BIT)) return VK_FORMAT_R16G16_SINT; + } else { /* 1 channel */ + if ((r & i_FLOAT_FORMAT_BIT)) return VK_FORMAT_R16_SFLOAT; + if ((r & i_NORMALIZED_FORMAT_BIT) && !(r & i_SIGNED_FORMAT_BIT)) return VK_FORMAT_R16_UNORM; + if ((r & i_NORMALIZED_FORMAT_BIT) && (r & i_SIGNED_FORMAT_BIT)) return VK_FORMAT_R16_SNORM; + if (!(r & i_NORMALIZED_FORMAT_BIT) && !(r & i_SIGNED_FORMAT_BIT)) return VK_FORMAT_R16_UINT; + if (!(r & i_NORMALIZED_FORMAT_BIT) && (r & i_SIGNED_FORMAT_BIT)) return VK_FORMAT_R16_SINT; + } + } else if (wordBytes == 4) { + if (A.size > 0) { /* 4 channels */ + if (R.offset == 0) { /* RGBA */ + if ((r & i_FLOAT_FORMAT_BIT)) return VK_FORMAT_R32G32B32A32_SFLOAT; + if (!(r & i_NORMALIZED_FORMAT_BIT) && !(r & i_SIGNED_FORMAT_BIT)) return VK_FORMAT_R32G32B32A32_UINT; + if (!(r & i_NORMALIZED_FORMAT_BIT) && (r & i_SIGNED_FORMAT_BIT)) return VK_FORMAT_R32G32B32A32_SINT; + } else { /* BGRA */ + } + } else if (B.size > 0) { /* 3 channels */ + if (R.offset == 0) { /* RGB */ + if ((r & i_FLOAT_FORMAT_BIT)) return VK_FORMAT_R32G32B32_SFLOAT; + if (!(r & i_NORMALIZED_FORMAT_BIT) && !(r & i_SIGNED_FORMAT_BIT)) return VK_FORMAT_R32G32B32_UINT; + if (!(r & i_NORMALIZED_FORMAT_BIT) && (r & i_SIGNED_FORMAT_BIT)) return VK_FORMAT_R32G32B32_SINT; + } else { /* BGR */ + } + } else if (G.size > 0) { /* 2 channels */ + if ((r & i_FLOAT_FORMAT_BIT)) return VK_FORMAT_R32G32_SFLOAT; + if (!(r & i_NORMALIZED_FORMAT_BIT) && !(r & i_SIGNED_FORMAT_BIT)) return VK_FORMAT_R32G32_UINT; + if (!(r & i_NORMALIZED_FORMAT_BIT) && (r & i_SIGNED_FORMAT_BIT)) return VK_FORMAT_R32G32_SINT; + } else { /* 1 channel */ + if ((r & i_FLOAT_FORMAT_BIT)) return VK_FORMAT_R32_SFLOAT; + if (!(r & i_NORMALIZED_FORMAT_BIT) && !(r & i_SIGNED_FORMAT_BIT)) return VK_FORMAT_R32_UINT; + if (!(r & i_NORMALIZED_FORMAT_BIT) && (r & i_SIGNED_FORMAT_BIT)) return VK_FORMAT_R32_SINT; + } + } else if (wordBytes == 8) { + if (A.size > 0) { /* 4 channels */ + if (R.offset == 0) { /* RGBA */ + if ((r & i_FLOAT_FORMAT_BIT)) return VK_FORMAT_R64G64B64A64_SFLOAT; + if (!(r & i_NORMALIZED_FORMAT_BIT) && !(r & i_SIGNED_FORMAT_BIT)) return VK_FORMAT_R64G64B64A64_UINT; + if (!(r & i_NORMALIZED_FORMAT_BIT) && (r & i_SIGNED_FORMAT_BIT)) return VK_FORMAT_R64G64B64A64_SINT; + } else { /* BGRA */ + } + } else if (B.size > 0) { /* 3 channels */ + if (R.offset == 0) { /* RGB */ + if ((r & i_FLOAT_FORMAT_BIT)) return VK_FORMAT_R64G64B64_SFLOAT; + if (!(r & i_NORMALIZED_FORMAT_BIT) && !(r & i_SIGNED_FORMAT_BIT)) return VK_FORMAT_R64G64B64_UINT; + if (!(r & i_NORMALIZED_FORMAT_BIT) && (r & i_SIGNED_FORMAT_BIT)) return VK_FORMAT_R64G64B64_SINT; + } else { /* BGR */ + } + } else if (G.size > 0) { /* 2 channels */ + if ((r & i_FLOAT_FORMAT_BIT)) return VK_FORMAT_R64G64_SFLOAT; + if (!(r & i_NORMALIZED_FORMAT_BIT) && !(r & i_SIGNED_FORMAT_BIT)) return VK_FORMAT_R64G64_UINT; + if (!(r & i_NORMALIZED_FORMAT_BIT) && (r & i_SIGNED_FORMAT_BIT)) return VK_FORMAT_R64G64_SINT; + } else { /* 1 channel */ + if ((r & i_FLOAT_FORMAT_BIT)) return VK_FORMAT_R64_SFLOAT; + if (!(r & i_NORMALIZED_FORMAT_BIT) && !(r & i_SIGNED_FORMAT_BIT)) return VK_FORMAT_R64_UINT; + if (!(r & i_NORMALIZED_FORMAT_BIT) && (r & i_SIGNED_FORMAT_BIT)) return VK_FORMAT_R64_SINT; + } + } + } +} else if (KHR_DFDVAL((dfd + 1), MODEL) >= 128) { + const uint32_t *bdb = dfd + 1; + switch (KHR_DFDVAL(bdb, MODEL)) { + case KHR_DF_MODEL_BC1A: + if (KHR_DFDSVAL(bdb, 0, CHANNELID) == KHR_DF_CHANNEL_BC1A_COLOR) { + if (KHR_DFDVAL(bdb, TRANSFER) != KHR_DF_TRANSFER_SRGB) { + return VK_FORMAT_BC1_RGB_UNORM_BLOCK; + } else { + return VK_FORMAT_BC1_RGB_SRGB_BLOCK; + } + } else { + if (KHR_DFDVAL(bdb, TRANSFER) != KHR_DF_TRANSFER_SRGB) { + return VK_FORMAT_BC1_RGBA_UNORM_BLOCK; + } else { + return VK_FORMAT_BC1_RGBA_SRGB_BLOCK; + } + } + case KHR_DF_MODEL_BC2: + if (KHR_DFDVAL(bdb, TRANSFER) != KHR_DF_TRANSFER_SRGB) { + return VK_FORMAT_BC2_UNORM_BLOCK; + } else { + return VK_FORMAT_BC2_SRGB_BLOCK; + } + case KHR_DF_MODEL_BC3: + if (KHR_DFDVAL(bdb, TRANSFER) != KHR_DF_TRANSFER_SRGB) { + return VK_FORMAT_BC3_UNORM_BLOCK; + } else { + return VK_FORMAT_BC3_SRGB_BLOCK; + } + case KHR_DF_MODEL_BC4: + if (!(KHR_DFDSVAL(bdb, 0, QUALIFIERS) & KHR_DF_SAMPLE_DATATYPE_SIGNED)) { + return VK_FORMAT_BC4_UNORM_BLOCK; + } else { + return VK_FORMAT_BC4_SNORM_BLOCK; + } + case KHR_DF_MODEL_BC5: + if (!(KHR_DFDSVAL(bdb, 0, QUALIFIERS) & KHR_DF_SAMPLE_DATATYPE_SIGNED)) { + return VK_FORMAT_BC5_UNORM_BLOCK; + } else { + return VK_FORMAT_BC5_SNORM_BLOCK; + } + case KHR_DF_MODEL_BC6H: + if (!(KHR_DFDSVAL(bdb, 0, QUALIFIERS) & KHR_DF_SAMPLE_DATATYPE_SIGNED)) { + return VK_FORMAT_BC6H_UFLOAT_BLOCK; + } else { + return VK_FORMAT_BC6H_SFLOAT_BLOCK; + } + case KHR_DF_MODEL_BC7: + if (KHR_DFDVAL(bdb, TRANSFER) != KHR_DF_TRANSFER_SRGB) { + return VK_FORMAT_BC7_UNORM_BLOCK; + } else { + return VK_FORMAT_BC7_SRGB_BLOCK; + } + case KHR_DF_MODEL_ETC2: + if (KHR_DFDSVAL(bdb, 0, CHANNELID) == KHR_DF_CHANNEL_ETC2_COLOR) { + if (KHR_DFDVAL(bdb, DESCRIPTORBLOCKSIZE) == 40) { + if (KHR_DFDVAL(bdb, TRANSFER) != KHR_DF_TRANSFER_SRGB) { + return VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK; + } else { + return VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK; + } + } else { + if (KHR_DFDVAL(bdb, TRANSFER) != KHR_DF_TRANSFER_SRGB) { + return VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK; + } else { + return VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK; + } + } + } else if (KHR_DFDSVAL(bdb, 0, CHANNELID) == KHR_DF_CHANNEL_ETC2_ALPHA) { + if (KHR_DFDVAL(bdb, TRANSFER) != KHR_DF_TRANSFER_SRGB) { + return VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK; + } else { + return VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK; + } + } else if (KHR_DFDVAL(bdb, DESCRIPTORBLOCKSIZE) == 40) { + if (!(KHR_DFDSVAL(bdb, 0, QUALIFIERS) & KHR_DF_SAMPLE_DATATYPE_SIGNED)) { + return VK_FORMAT_EAC_R11_UNORM_BLOCK; + } else { + return VK_FORMAT_EAC_R11_SNORM_BLOCK; + } + } else { + if (!(KHR_DFDSVAL(bdb, 0, QUALIFIERS) & KHR_DF_SAMPLE_DATATYPE_SIGNED)) { + return VK_FORMAT_EAC_R11G11_UNORM_BLOCK; + } else { + return VK_FORMAT_EAC_R11G11_SNORM_BLOCK; + } + } + case KHR_DF_MODEL_ASTC: + if (!(KHR_DFDSVAL(bdb, 0, QUALIFIERS) & KHR_DF_SAMPLE_DATATYPE_FLOAT)) { + if (KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION2) == 0) { + if ((KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION0) == 3) && + (KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION1) == 3)) { + if (KHR_DFDVAL(bdb, TRANSFER) != KHR_DF_TRANSFER_SRGB) { + return VK_FORMAT_ASTC_4x4_UNORM_BLOCK; + } else { + return VK_FORMAT_ASTC_4x4_SRGB_BLOCK; + } + } else if ((KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION0) == 4) && + (KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION1) == 3)) { + if (KHR_DFDVAL(bdb, TRANSFER) != KHR_DF_TRANSFER_SRGB) { + return VK_FORMAT_ASTC_5x4_UNORM_BLOCK; + } else { + return VK_FORMAT_ASTC_5x4_SRGB_BLOCK; + } + } else if ((KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION0) == 4) && + (KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION1) == 4)) { + if (KHR_DFDVAL(bdb, TRANSFER) != KHR_DF_TRANSFER_SRGB) { + return VK_FORMAT_ASTC_5x5_UNORM_BLOCK; + } else { + return VK_FORMAT_ASTC_5x5_SRGB_BLOCK; + } + } else if ((KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION0) == 5) && + (KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION1) == 4)) { + if (KHR_DFDVAL(bdb, TRANSFER) != KHR_DF_TRANSFER_SRGB) { + return VK_FORMAT_ASTC_6x5_UNORM_BLOCK; + } else { + return VK_FORMAT_ASTC_6x5_SRGB_BLOCK; + } + } else if ((KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION0) == 5) && + (KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION1) == 5)) { + if (KHR_DFDVAL(bdb, TRANSFER) != KHR_DF_TRANSFER_SRGB) { + return VK_FORMAT_ASTC_6x6_UNORM_BLOCK; + } else { + return VK_FORMAT_ASTC_6x6_SRGB_BLOCK; + } + } else if ((KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION0) == 7) && + (KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION1) == 4)) { + if (KHR_DFDVAL(bdb, TRANSFER) != KHR_DF_TRANSFER_SRGB) { + return VK_FORMAT_ASTC_8x5_UNORM_BLOCK; + } else { + return VK_FORMAT_ASTC_8x5_SRGB_BLOCK; + } + } else if ((KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION0) == 7) && + (KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION1) == 5)) { + if (KHR_DFDVAL(bdb, TRANSFER) != KHR_DF_TRANSFER_SRGB) { + return VK_FORMAT_ASTC_8x6_UNORM_BLOCK; + } else { + return VK_FORMAT_ASTC_8x6_SRGB_BLOCK; + } + } else if ((KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION0) == 7) && + (KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION1) == 7)) { + if (KHR_DFDVAL(bdb, TRANSFER) != KHR_DF_TRANSFER_SRGB) { + return VK_FORMAT_ASTC_8x8_UNORM_BLOCK; + } else { + return VK_FORMAT_ASTC_8x8_SRGB_BLOCK; + } + } else if ((KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION0) == 9) && + (KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION1) == 4)) { + if (KHR_DFDVAL(bdb, TRANSFER) != KHR_DF_TRANSFER_SRGB) { + return VK_FORMAT_ASTC_10x5_UNORM_BLOCK; + } else { + return VK_FORMAT_ASTC_10x5_SRGB_BLOCK; + } + } else if ((KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION0) == 9) && + (KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION1) == 5)) { + if (KHR_DFDVAL(bdb, TRANSFER) != KHR_DF_TRANSFER_SRGB) { + return VK_FORMAT_ASTC_10x6_UNORM_BLOCK; + } else { + return VK_FORMAT_ASTC_10x6_SRGB_BLOCK; + } + } else if ((KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION0) == 9) && + (KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION1) == 7)) { + if (KHR_DFDVAL(bdb, TRANSFER) != KHR_DF_TRANSFER_SRGB) { + return VK_FORMAT_ASTC_10x8_UNORM_BLOCK; + } else { + return VK_FORMAT_ASTC_10x8_SRGB_BLOCK; + } + } else if ((KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION0) == 9) && + (KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION1) == 9)) { + if (KHR_DFDVAL(bdb, TRANSFER) != KHR_DF_TRANSFER_SRGB) { + return VK_FORMAT_ASTC_10x10_UNORM_BLOCK; + } else { + return VK_FORMAT_ASTC_10x10_SRGB_BLOCK; + } + } else if ((KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION0) == 11) && + (KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION1) == 9)) { + if (KHR_DFDVAL(bdb, TRANSFER) != KHR_DF_TRANSFER_SRGB) { + return VK_FORMAT_ASTC_12x10_UNORM_BLOCK; + } else { + return VK_FORMAT_ASTC_12x10_SRGB_BLOCK; + } + } else if ((KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION0) == 11) && + (KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION1) == 11)) { + if (KHR_DFDVAL(bdb, TRANSFER) != KHR_DF_TRANSFER_SRGB) { + return VK_FORMAT_ASTC_12x12_UNORM_BLOCK; + } else { + return VK_FORMAT_ASTC_12x12_SRGB_BLOCK; + } + } + } else { + if ((KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION0) == 2) && + (KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION1) == 2) && + (KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION2) == 2)) { + if (KHR_DFDVAL(bdb, TRANSFER) != KHR_DF_TRANSFER_SRGB) { + return VK_FORMAT_ASTC_3x3x3_UNORM_BLOCK_EXT; + } else { + return VK_FORMAT_ASTC_3x3x3_SRGB_BLOCK_EXT; + } + } else if ((KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION0) == 3) && + (KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION1) == 2) && + (KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION2) == 2)) { + if (KHR_DFDVAL(bdb, TRANSFER) != KHR_DF_TRANSFER_SRGB) { + return VK_FORMAT_ASTC_4x3x3_UNORM_BLOCK_EXT; + } else { + return VK_FORMAT_ASTC_4x3x3_SRGB_BLOCK_EXT; + } + } else if ((KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION0) == 3) && + (KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION1) == 3) && + (KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION2) == 2)) { + if (KHR_DFDVAL(bdb, TRANSFER) != KHR_DF_TRANSFER_SRGB) { + return VK_FORMAT_ASTC_4x4x3_UNORM_BLOCK_EXT; + } else { + return VK_FORMAT_ASTC_4x4x3_SRGB_BLOCK_EXT; + } + } else if ((KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION0) == 3) && + (KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION1) == 3) && + (KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION2) == 3)) { + if (KHR_DFDVAL(bdb, TRANSFER) != KHR_DF_TRANSFER_SRGB) { + return VK_FORMAT_ASTC_4x4x4_UNORM_BLOCK_EXT; + } else { + return VK_FORMAT_ASTC_4x4x4_SRGB_BLOCK_EXT; + } + } + if ((KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION0) == 4) && + (KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION1) == 3) && + (KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION2) == 3)) { + if (KHR_DFDVAL(bdb, TRANSFER) != KHR_DF_TRANSFER_SRGB) { + return VK_FORMAT_ASTC_5x4x4_UNORM_BLOCK_EXT; + } else { + return VK_FORMAT_ASTC_5x4x4_SRGB_BLOCK_EXT; + } + } else if ((KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION0) == 4) && + (KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION1) == 4) && + (KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION2) == 3)) { + if (KHR_DFDVAL(bdb, TRANSFER) != KHR_DF_TRANSFER_SRGB) { + return VK_FORMAT_ASTC_5x5x4_UNORM_BLOCK_EXT; + } else { + return VK_FORMAT_ASTC_5x5x4_SRGB_BLOCK_EXT; + } + } else if ((KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION0) == 4) && + (KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION1) == 4) && + (KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION2) == 4)) { + if (KHR_DFDVAL(bdb, TRANSFER) != KHR_DF_TRANSFER_SRGB) { + return VK_FORMAT_ASTC_5x5x5_UNORM_BLOCK_EXT; + } else { + return VK_FORMAT_ASTC_5x5x5_SRGB_BLOCK_EXT; + } + } else if ((KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION0) == 5) && + (KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION1) == 4) && + (KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION2) == 4)) { + if (KHR_DFDVAL(bdb, TRANSFER) != KHR_DF_TRANSFER_SRGB) { + return VK_FORMAT_ASTC_6x5x5_UNORM_BLOCK_EXT; + } else { + return VK_FORMAT_ASTC_6x5x5_SRGB_BLOCK_EXT; + } + } else if ((KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION0) == 5) && + (KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION1) == 5) && + (KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION2) == 4)) { + if (KHR_DFDVAL(bdb, TRANSFER) != KHR_DF_TRANSFER_SRGB) { + return VK_FORMAT_ASTC_6x6x5_UNORM_BLOCK_EXT; + } else { + return VK_FORMAT_ASTC_6x6x5_SRGB_BLOCK_EXT; + } + } else if ((KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION0) == 5) && + (KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION1) == 5) && + (KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION2) == 5)) { + if (KHR_DFDVAL(bdb, TRANSFER) != KHR_DF_TRANSFER_SRGB) { + return VK_FORMAT_ASTC_6x6x6_UNORM_BLOCK_EXT; + } else { + return VK_FORMAT_ASTC_6x6x6_SRGB_BLOCK_EXT; + } + } + } + } else { + if (KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION2) == 0) { + if ((KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION0) == 3) && + (KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION1) == 3)) { + return VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK_EXT; + } else if ((KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION0) == 4) && + (KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION1) == 3)) { + return VK_FORMAT_ASTC_5x4_SFLOAT_BLOCK_EXT; + } else if ((KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION0) == 4) && + (KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION1) == 4)) { + return VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK_EXT; + } else if ((KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION0) == 5) && + (KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION1) == 4)) { + return VK_FORMAT_ASTC_6x5_SFLOAT_BLOCK_EXT; + } else if ((KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION0) == 5) && + (KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION1) == 5)) { + return VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK_EXT; + } else if ((KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION0) == 7) && + (KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION1) == 4)) { + return VK_FORMAT_ASTC_8x5_SFLOAT_BLOCK_EXT; + } else if ((KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION0) == 7) && + (KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION1) == 5)) { + return VK_FORMAT_ASTC_8x6_SFLOAT_BLOCK_EXT; + } else if ((KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION0) == 7) && + (KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION1) == 7)) { + return VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK_EXT; + } else if ((KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION0) == 9) && + (KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION1) == 4)) { + return VK_FORMAT_ASTC_10x5_SFLOAT_BLOCK_EXT; + } else if ((KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION0) == 9) && + (KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION1) == 5)) { + return VK_FORMAT_ASTC_10x6_SFLOAT_BLOCK_EXT; + } else if ((KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION0) == 9) && + (KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION1) == 7)) { + return VK_FORMAT_ASTC_10x8_SFLOAT_BLOCK_EXT; + } else if ((KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION0) == 9) && + (KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION1) == 9)) { + return VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK_EXT; + } else if ((KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION0) == 11) && + (KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION1) == 9)) { + return VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK_EXT; + } else if ((KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION0) == 11) && + (KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION1) == 11)) { + return VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK_EXT; + } + } else { + if ((KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION0) == 2) && + (KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION1) == 2) && + (KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION2) == 2)) { + return VK_FORMAT_ASTC_3x3x3_SFLOAT_BLOCK_EXT; + } else if ((KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION0) == 3) && + (KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION1) == 2) && + (KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION2) == 2)) { + return VK_FORMAT_ASTC_4x3x3_SFLOAT_BLOCK_EXT; + } else if ((KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION0) == 3) && + (KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION1) == 2) && + (KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION2) == 2)) { + return VK_FORMAT_ASTC_4x3x3_SFLOAT_BLOCK_EXT; + } else if ((KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION0) == 3) && + (KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION1) == 3) && + (KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION2) == 2)) { + return VK_FORMAT_ASTC_4x4x3_SFLOAT_BLOCK_EXT; + } else if ((KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION0) == 3) && + (KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION1) == 3) && + (KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION2) == 3)) { + return VK_FORMAT_ASTC_4x4x4_SFLOAT_BLOCK_EXT; + } else if ((KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION0) == 4) && + (KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION1) == 3) && + (KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION2) == 3)) { + return VK_FORMAT_ASTC_5x4x4_SFLOAT_BLOCK_EXT; + } else if ((KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION0) == 4) && + (KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION1) == 4) && + (KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION2) == 3)) { + return VK_FORMAT_ASTC_5x5x4_SFLOAT_BLOCK_EXT; + } else if ((KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION0) == 4) && + (KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION1) == 4) && + (KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION2) == 4)) { + return VK_FORMAT_ASTC_5x5x5_SFLOAT_BLOCK_EXT; + } else if ((KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION0) == 5) && + (KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION1) == 4) && + (KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION2) == 4)) { + return VK_FORMAT_ASTC_6x5x5_SFLOAT_BLOCK_EXT; + } else if ((KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION0) == 5) && + (KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION1) == 5) && + (KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION2) == 4)) { + return VK_FORMAT_ASTC_6x6x5_SFLOAT_BLOCK_EXT; + } else if ((KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION0) == 5) && + (KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION1) == 5) && + (KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION2) == 5)) { + return VK_FORMAT_ASTC_6x6x6_SFLOAT_BLOCK_EXT; + } + } + } + break; + case KHR_DF_MODEL_PVRTC: + if (KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION0) == 3) { + if (KHR_DFDVAL(bdb, TRANSFER) == KHR_DF_TRANSFER_SRGB) { + return VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG; + } else { + return VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG; + } + } else { + if (KHR_DFDVAL(bdb, TRANSFER) == KHR_DF_TRANSFER_SRGB) { + return VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG; + } else { + return VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG; + } + } + case KHR_DF_MODEL_PVRTC2: + if (KHR_DFDVAL(bdb, TEXELBLOCKDIMENSION0) == 3) { + if (KHR_DFDVAL(bdb, TRANSFER) == KHR_DF_TRANSFER_SRGB) { + return VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG; + } else { + return VK_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG; + } + } else { + if (KHR_DFDVAL(bdb, TRANSFER) == KHR_DF_TRANSFER_SRGB) { + return VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG; + } else { + return VK_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG; + } + } + default: + ; + } +} +return VK_FORMAT_UNDEFINED; /* Drop-through for unmatched formats. */ diff --git a/thirdparty/libktx/lib/dfdutils/interpretdfd.c b/thirdparty/libktx/lib/dfdutils/interpretdfd.c new file mode 100644 index 000000000000..273410a18ccd --- /dev/null +++ b/thirdparty/libktx/lib/dfdutils/interpretdfd.c @@ -0,0 +1,345 @@ +/* -*- tab-width: 4; -*- */ +/* vi: set sw=2 ts=4 expandtab: */ + +/* Copyright 2019-2020 The Khronos Group Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @~English + * @brief Utility for interpreting a data format descriptor. + * @author Andrew Garrard + */ + +#include +#include +#include +#include "dfd.h" + +/** + * @~English + * @brief Interpret a Data Format Descriptor for a simple format. + * + * @param DFD Pointer to a Data Format Descriptor to interpret, + described as 32-bit words in native endianness. + Note that this is the whole descriptor, not just + the basic descriptor block. + * @param R Information about the decoded red channel, if any. + * @param G Information about the decoded green channel, if any. + * @param B Information about the decoded blue channel, if any. + * @param A Information about the decoded alpha channel, if any. + * @param wordBytes Byte size of the channels (unpacked) or total size (packed). + * + * @return An enumerant describing the decoded value, + * or an error code in case of failure. + **/ +enum InterpretDFDResult interpretDFD(const uint32_t *DFD, + InterpretedDFDChannel *R, + InterpretedDFDChannel *G, + InterpretedDFDChannel *B, + InterpretedDFDChannel *A, + uint32_t *wordBytes) +{ + /* We specifically handle "simple" cases that can be translated */ + /* to things a GPU can access. For simplicity, we also ignore */ + /* the compressed formats, which are generally a single sample */ + /* (and I believe are all defined to be little-endian in their */ + /* in-memory layout, even if some documentation confuses this). */ + /* We also just worry about layout and ignore sRGB, since that's */ + /* trivial to extract anyway. */ + + /* DFD points to the whole descriptor, not the basic descriptor block. */ + /* Make everything else relative to the basic descriptor block. */ + const uint32_t *BDFDB = DFD+1; + + uint32_t numSamples = KHR_DFDSAMPLECOUNT(BDFDB); + + uint32_t sampleCounter; + int determinedEndianness = 0; + int determinedNormalizedness = 0; + int determinedSignedness = 0; + int determinedFloatness = 0; + enum InterpretDFDResult result = 0; /* Build this up incrementally. */ + + /* Clear these so following code doesn't get confused. */ + R->offset = R->size = 0; + G->offset = G->size = 0; + B->offset = B->size = 0; + A->offset = A->size = 0; + + /* First rule out the multiple planes case (trivially) */ + /* - that is, we check that only bytesPlane0 is non-zero. */ + /* This means we don't handle YUV even if the API could. */ + /* (We rely on KHR_DF_WORD_BYTESPLANE0..3 being the same and */ + /* KHR_DF_WORD_BYTESPLANE4..7 being the same as a short cut.) */ + if ((BDFDB[KHR_DF_WORD_BYTESPLANE0] & ~KHR_DF_MASK_BYTESPLANE0) + || BDFDB[KHR_DF_WORD_BYTESPLANE4]) return i_UNSUPPORTED_MULTIPLE_PLANES; + + /* Only support the RGB color model. */ + /* We could expand this to allow "UNSPECIFIED" as well. */ + if (KHR_DFDVAL(BDFDB, MODEL) != KHR_DF_MODEL_RGBSDA) return i_UNSUPPORTED_CHANNEL_TYPES; + + /* We only pay attention to sRGB. */ + if (KHR_DFDVAL(BDFDB, TRANSFER) == KHR_DF_TRANSFER_SRGB) result |= i_SRGB_FORMAT_BIT; + + /* We only support samples at coordinate 0,0,0,0. */ + /* (We could confirm this from texel_block_dimensions in 1.2, but */ + /* the interpretation might change in later versions.) */ + for (sampleCounter = 0; sampleCounter < numSamples; ++sampleCounter) { + if (KHR_DFDSVAL(BDFDB, sampleCounter, SAMPLEPOSITION_ALL)) + return i_UNSUPPORTED_MULTIPLE_SAMPLE_LOCATIONS; + } + + /* Set flags and check for consistency. */ + for (sampleCounter = 0; sampleCounter < numSamples; ++sampleCounter) { + /* Note: We're ignoring 9995, which is weird and worth special-casing */ + /* rather than trying to generalise to all float formats. */ + if (!determinedFloatness) { + if (KHR_DFDSVAL(BDFDB, sampleCounter, QUALIFIERS) + & KHR_DF_SAMPLE_DATATYPE_FLOAT) { + result |= i_FLOAT_FORMAT_BIT; + determinedFloatness = 1; + } + } else { + /* Check whether we disagree with our predetermined floatness. */ + /* Note that this could justifiably happen with (say) D24S8. */ + if (KHR_DFDSVAL(BDFDB, sampleCounter, QUALIFIERS) + & KHR_DF_SAMPLE_DATATYPE_FLOAT) { + if (!(result & i_FLOAT_FORMAT_BIT)) return i_UNSUPPORTED_MIXED_CHANNELS; + } else { + if ((result & i_FLOAT_FORMAT_BIT)) return i_UNSUPPORTED_MIXED_CHANNELS; + } + } + if (!determinedSignedness) { + if (KHR_DFDSVAL(BDFDB, sampleCounter, QUALIFIERS) + & KHR_DF_SAMPLE_DATATYPE_SIGNED) { + result |= i_SIGNED_FORMAT_BIT; + determinedSignedness = 1; + } + } else { + /* Check whether we disagree with our predetermined signedness. */ + if (KHR_DFDSVAL(BDFDB, sampleCounter, QUALIFIERS) + & KHR_DF_SAMPLE_DATATYPE_SIGNED) { + if (!(result & i_SIGNED_FORMAT_BIT)) return i_UNSUPPORTED_MIXED_CHANNELS; + } else { + if ((result & i_SIGNED_FORMAT_BIT)) return i_UNSUPPORTED_MIXED_CHANNELS; + } + } + /* We define "unnormalized" as "sample_upper = 1". */ + /* We don't check whether any non-1 normalization value is correct */ + /* (i.e. set to the maximum bit value, and check min value) on */ + /* the assumption that we're looking at a format which *came* from */ + /* an API we can support. */ + if (!determinedNormalizedness) { + /* The ambiguity here is if the bottom bit is a single-bit value, */ + /* as in RGBA 5:5:5:1, so we defer the decision if the channel only has one bit. */ + if (KHR_DFDSVAL(BDFDB, sampleCounter, BITLENGTH) > 0) { + if ((result & i_FLOAT_FORMAT_BIT)) { + if (*(float *)(void *)&BDFDB[KHR_DF_WORD_SAMPLESTART + + KHR_DF_WORD_SAMPLEWORDS * sampleCounter + + KHR_DF_SAMPLEWORD_SAMPLEUPPER] != 1.0f) { + result |= i_NORMALIZED_FORMAT_BIT; + } + } else { + if (KHR_DFDSVAL(BDFDB, sampleCounter, SAMPLEUPPER) != 1U) { + result |= i_NORMALIZED_FORMAT_BIT; + } + } + determinedNormalizedness = 1; + } + } + /* Note: We don't check for inconsistent normalization, because */ + /* channels composed of multiple samples will have 0 in the */ + /* lower/upper range. */ + /* This heuristic should handle 64-bit integers, too. */ + } + + /* If this is a packed format, we work out our offsets differently. */ + /* We assume a packed format has channels that aren't byte-aligned. */ + /* If we have a format in which every channel is byte-aligned *and* packed, */ + /* we have the RGBA/ABGR ambiguity; we *probably* don't want the packed */ + /* version in this case, and if hardware has to pack it and swizzle, */ + /* that's up to the hardware to special-case. */ + for (sampleCounter = 0; sampleCounter < numSamples; ++sampleCounter) { + if (KHR_DFDSVAL(BDFDB, sampleCounter, BITOFFSET) & 0x7U) { + result |= i_PACKED_FORMAT_BIT; + /* Once we're packed, we're packed, no need to keep checking. */ + break; + } + } + + /* Remember: the canonical ordering of samples is to start with */ + /* the lowest bit of the channel/location which touches bit 0 of */ + /* the data, when the latter is concatenated in little-endian order, */ + /* and then progress until all the bits of that channel/location */ + /* have been processed. Multiple channels sharing the same source */ + /* bits are processed in channel ID order. (I should clarify this */ + /* for partially-shared data, but it doesn't really matter so long */ + /* as everything is consecutive, except to make things canonical.) */ + /* Note: For standard formats we could determine big/little-endianness */ + /* simply from whether the first sample starts in bit 0; technically */ + /* it's possible to have a format with unaligned channels wherein the */ + /* first channel starts at bit 0 and is one byte, yet other channels */ + /* take more bytes or aren't aligned (e.g. D24S8), but this should be */ + /* irrelevant for the formats that we support. */ + if ((result & i_PACKED_FORMAT_BIT)) { + /* A packed format. */ + uint32_t currentChannel = ~0U; /* Don't start matched. */ + uint32_t currentBitOffset = 0; + uint32_t currentByteOffset = 0; + uint32_t currentBitLength = 0; + *wordBytes = (BDFDB[KHR_DF_WORD_BYTESPLANE0] & 0xFFU); + for (sampleCounter = 0; sampleCounter < numSamples; ++sampleCounter) { + uint32_t sampleBitOffset = KHR_DFDSVAL(BDFDB, sampleCounter, BITOFFSET); + uint32_t sampleByteOffset = sampleBitOffset >> 3U; + /* The sample bitLength field stores the bit length - 1. */ + uint32_t sampleBitLength = KHR_DFDSVAL(BDFDB, sampleCounter, BITLENGTH) + 1; + uint32_t sampleChannel = KHR_DFDSVAL(BDFDB, sampleCounter, CHANNELID); + InterpretedDFDChannel *sampleChannelPtr; + switch (sampleChannel) { + case KHR_DF_CHANNEL_RGBSDA_RED: + sampleChannelPtr = R; + break; + case KHR_DF_CHANNEL_RGBSDA_GREEN: + sampleChannelPtr = G; + break; + case KHR_DF_CHANNEL_RGBSDA_BLUE: + sampleChannelPtr = B; + break; + case KHR_DF_CHANNEL_RGBSDA_ALPHA: + sampleChannelPtr = A; + break; + default: + return i_UNSUPPORTED_CHANNEL_TYPES; + } + if (sampleChannel == currentChannel) { + /* Continuation of the same channel. */ + /* Since a big (>32-bit) channel isn't "packed", */ + /* this should only happen in big-endian, or if */ + /* we have a wacky format that we won't support. */ + if (sampleByteOffset == currentByteOffset - 1U && /* One byte earlier */ + ((currentBitOffset + currentBitLength) & 7U) == 0 && /* Already at the end of a byte */ + (sampleBitOffset & 7U) == 0) { /* Start at the beginning of the byte */ + /* All is good, continue big-endian. */ + /* N.B. We shouldn't be here if we decided we were little-endian, */ + /* so we don't bother to check that disagreement. */ + result |= i_BIG_ENDIAN_FORMAT_BIT; + determinedEndianness = 1; + } else { + /* Oh dear. */ + /* We could be little-endian, but not with any standard format. */ + /* More likely we've got something weird that we can't support. */ + return i_UNSUPPORTED_NONTRIVIAL_ENDIANNESS; + } + /* Remember where we are. */ + currentBitOffset = sampleBitOffset; + currentByteOffset = sampleByteOffset; + currentBitLength = sampleBitLength; + /* Accumulate the bit length. */ + sampleChannelPtr->size += sampleBitLength; + } else { + /* Everything is new. Hopefully. */ + currentChannel = sampleChannel; + currentBitOffset = sampleBitOffset; + currentByteOffset = sampleByteOffset; + currentBitLength = sampleBitLength; + if (sampleChannelPtr->size) { + /* Uh-oh, we've seen this channel before. */ + return i_UNSUPPORTED_NONTRIVIAL_ENDIANNESS; + } + /* For now, record the bit offset in little-endian terms, */ + /* because we may not know to reverse it yet. */ + sampleChannelPtr->offset = sampleBitOffset; + sampleChannelPtr->size = sampleBitLength; + } + } + if ((result & i_BIG_ENDIAN_FORMAT_BIT)) { + /* Our bit offsets to bit 0 of each channel are in little-endian terms. */ + /* We need to do a byte swap to work out where they should be. */ + /* We assume, for sanity, that byte sizes are a power of two for this. */ + uint32_t offsetMask = (*wordBytes - 1U) << 3U; + R->offset ^= offsetMask; + G->offset ^= offsetMask; + B->offset ^= offsetMask; + A->offset ^= offsetMask; + } + } else { + /* Not a packed format. */ + /* Everything is byte-aligned. */ + /* Question is whether there multiple samples per channel. */ + uint32_t currentChannel = ~0U; /* Don't start matched. */ + uint32_t currentByteOffset = 0; + uint32_t currentByteLength = 0; + for (sampleCounter = 0; sampleCounter < numSamples; ++sampleCounter) { + uint32_t sampleByteOffset = KHR_DFDSVAL(BDFDB, sampleCounter, BITOFFSET) >> 3U; + uint32_t sampleByteLength = (KHR_DFDSVAL(BDFDB, sampleCounter, BITLENGTH) + 1) >> 3U; + uint32_t sampleChannel = KHR_DFDSVAL(BDFDB, sampleCounter, CHANNELID); + InterpretedDFDChannel *sampleChannelPtr; + switch (sampleChannel) { + case KHR_DF_CHANNEL_RGBSDA_RED: + sampleChannelPtr = R; + break; + case KHR_DF_CHANNEL_RGBSDA_GREEN: + sampleChannelPtr = G; + break; + case KHR_DF_CHANNEL_RGBSDA_BLUE: + sampleChannelPtr = B; + break; + case KHR_DF_CHANNEL_RGBSDA_ALPHA: + sampleChannelPtr = A; + break; + default: + return i_UNSUPPORTED_CHANNEL_TYPES; + } + if (sampleChannel == currentChannel) { + /* Continuation of the same channel. */ + /* Either big-endian, or little-endian with a very large channel. */ + if (sampleByteOffset == currentByteOffset - 1) { /* One byte earlier */ + if (determinedEndianness && !(result & i_BIG_ENDIAN_FORMAT_BIT)) { + return i_UNSUPPORTED_NONTRIVIAL_ENDIANNESS; + } + /* All is good, continue big-endian. */ + result |= i_BIG_ENDIAN_FORMAT_BIT; + determinedEndianness = 1; + /* Update the start */ + sampleChannelPtr->offset = sampleByteOffset; + } else if (sampleByteOffset == currentByteOffset + currentByteLength) { + if (determinedEndianness && (result & i_BIG_ENDIAN_FORMAT_BIT)) { + return i_UNSUPPORTED_NONTRIVIAL_ENDIANNESS; + } + /* All is good, continue little-endian. */ + determinedEndianness = 1; + } else { + /* Oh dear. */ + /* We could be little-endian, but not with any standard format. */ + /* More likely we've got something weird that we can't support. */ + return i_UNSUPPORTED_NONTRIVIAL_ENDIANNESS; + } + /* Remember where we are. */ + currentByteOffset = sampleByteOffset; + currentByteLength = sampleByteLength; + /* Accumulate the byte length. */ + sampleChannelPtr->size += sampleByteLength; + /* Assume these are all the same. */ + *wordBytes = sampleChannelPtr->size; + } else { + /* Everything is new. Hopefully. */ + currentChannel = sampleChannel; + currentByteOffset = sampleByteOffset; + currentByteLength = sampleByteLength; + if (sampleChannelPtr->size) { + /* Uh-oh, we've seen this channel before. */ + return i_UNSUPPORTED_NONTRIVIAL_ENDIANNESS; + } + /* For now, record the byte offset in little-endian terms, */ + /* because we may not know to reverse it yet. */ + sampleChannelPtr->offset = sampleByteOffset; + sampleChannelPtr->size = sampleByteLength; + /* Assume these are all the same. */ + *wordBytes = sampleByteLength; + } + } + } + return result; +} diff --git a/thirdparty/libktx/lib/dfdutils/printdfd.c b/thirdparty/libktx/lib/dfdutils/printdfd.c new file mode 100644 index 000000000000..36d3d2c50d47 --- /dev/null +++ b/thirdparty/libktx/lib/dfdutils/printdfd.c @@ -0,0 +1,97 @@ +/* -*- tab-width: 4; -*- */ +/* vi: set sw=2 ts=4 expandtab: */ + +/* Copyright 2019-2020 The Khronos Group Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @~English + * @brief Utilities for printing data format descriptors. + */ + +/* + * Author: Andrew Garrard + */ + +#include +#include +#include "dfd.h" + +/** + * @~English + * @brief Print a human-readable interpretation of a data format descriptor. + * + * @param DFD Pointer to a data format descriptor. + **/ +void printDFD(uint32_t *DFD) +{ + uint32_t *BDB = DFD+1; + int samples = (KHR_DFDVAL(BDB, DESCRIPTORBLOCKSIZE) - 4 * KHR_DF_WORD_SAMPLESTART) / (4 * KHR_DF_WORD_SAMPLEWORDS); + int sample; + int model = KHR_DFDVAL(BDB, MODEL); + printf("DFD total bytes: %d\n", DFD[0]); + printf("BDB descriptor type 0x%04x vendor id = 0x%05x\n", + KHR_DFDVAL(BDB, DESCRIPTORTYPE), + KHR_DFDVAL(BDB, VENDORID)); + printf("Descriptor block size %d (%d samples) versionNumber = 0x%04x\n", + KHR_DFDVAL(BDB, DESCRIPTORBLOCKSIZE), + samples, + KHR_DFDVAL(BDB, VERSIONNUMBER)); + printf("Flags 0x%02x Xfer %02d Primaries %02d Model %03d\n", + KHR_DFDVAL(BDB, FLAGS), + KHR_DFDVAL(BDB, TRANSFER), + KHR_DFDVAL(BDB, PRIMARIES), + model); + printf("Dimensions: %d,%d,%d,%d\n", + KHR_DFDVAL(BDB, TEXELBLOCKDIMENSION0) + 1, + KHR_DFDVAL(BDB, TEXELBLOCKDIMENSION1) + 1, + KHR_DFDVAL(BDB, TEXELBLOCKDIMENSION2) + 1, + KHR_DFDVAL(BDB, TEXELBLOCKDIMENSION3) + 1); + printf("Plane bytes: %d,%d,%d,%d,%d,%d,%d,%d\n", + KHR_DFDVAL(BDB, BYTESPLANE0), + KHR_DFDVAL(BDB, BYTESPLANE1), + KHR_DFDVAL(BDB, BYTESPLANE2), + KHR_DFDVAL(BDB, BYTESPLANE3), + KHR_DFDVAL(BDB, BYTESPLANE4), + KHR_DFDVAL(BDB, BYTESPLANE5), + KHR_DFDVAL(BDB, BYTESPLANE6), + KHR_DFDVAL(BDB, BYTESPLANE7)); + for (sample = 0; sample < samples; ++sample) { + int channelId = KHR_DFDSVAL(BDB, sample, CHANNELID); + printf(" Sample %d\n", sample); + printf("Qualifiers %x", KHR_DFDSVAL(BDB, sample, QUALIFIERS) >> 4); + printf(" Channel 0x%x", channelId); + if (model == KHR_DF_MODEL_UASTC) { + printf(" (%s)", + channelId == KHR_DF_CHANNEL_UASTC_RRRG ? "RRRG" + : channelId == KHR_DF_CHANNEL_UASTC_RGBA ? "RGBA" + : channelId == KHR_DF_CHANNEL_UASTC_RRR ? "RRR" + : channelId == KHR_DF_CHANNEL_UASTC_RGB ? "RGB" + : channelId == KHR_DF_CHANNEL_UASTC_RG ? "RG" + : "unknown"); + } else if (model == KHR_DF_MODEL_ETC1S) { + printf(" (%s)", + channelId == KHR_DF_CHANNEL_ETC1S_AAA ? "AAA" + : channelId == KHR_DF_CHANNEL_ETC1S_GGG ? "GGG" + : channelId == KHR_DF_CHANNEL_ETC1S_RRR ? "RRR" + : channelId == KHR_DF_CHANNEL_ETC1S_RGB ? "RGB" + : "unknown"); + } else { + printf(" (%c)", + "RGB3456789abcdeA"[channelId]); + } + printf(" Length %d bits Offset %d\n", + KHR_DFDSVAL(BDB, sample, BITLENGTH) + 1, + KHR_DFDSVAL(BDB, sample, BITOFFSET)); + printf("Position: %d,%d,%d,%d\n", + KHR_DFDSVAL(BDB, sample, SAMPLEPOSITION0), + KHR_DFDSVAL(BDB, sample, SAMPLEPOSITION1), + KHR_DFDSVAL(BDB, sample, SAMPLEPOSITION2), + KHR_DFDSVAL(BDB, sample, SAMPLEPOSITION3)); + printf("Lower 0x%08x\nUpper 0x%08x\n", + KHR_DFDSVAL(BDB, sample, SAMPLELOWER), + KHR_DFDSVAL(BDB, sample, SAMPLEUPPER)); + } +} diff --git a/thirdparty/libktx/lib/dfdutils/queries.c b/thirdparty/libktx/lib/dfdutils/queries.c new file mode 100644 index 000000000000..19488f9e33de --- /dev/null +++ b/thirdparty/libktx/lib/dfdutils/queries.c @@ -0,0 +1,146 @@ +/* -*- tab-width: 4; -*- */ +/* vi: set sw=2 ts=4 expandtab: */ + +/* Copyright 2019-2020 The Khronos Group Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @~English + * @brief Utilities for querying info from a data format descriptor. + * @author Mark Callow + */ + +#include +#include +#include +#include +#include +#include "dfd.h" + +/** + * @~English + * @brief Get the number and size of the image components from a DFD. + * + * This simplified function is for use only with the DFDs for unpacked + * formats which means all components have the same size. + * + * @param DFD Pointer to a Data Format Descriptor to interpret, + described as 32-bit words in native endianness. + Note that this is the whole descriptor, not just + the basic descriptor block. + * @param numComponents pointer to a 32-bit word in which the number of + components will be written. + * @param componentByteLength pointer to a 32-bit word in which the size of + a component in bytes will be written. + */ +void +getDFDComponentInfoUnpacked(const uint32_t* DFD, uint32_t* numComponents, + uint32_t* componentByteLength) +{ + const uint32_t *BDFDB = DFD+1; + uint32_t numSamples = KHR_DFDSAMPLECOUNT(BDFDB); + uint32_t sampleCounter; + uint32_t currentChannel = ~0U; /* Don't start matched. */ + + /* This is specifically for unpacked formats which means the size of */ + /* each component is the same. */ + *numComponents = 0; + for (sampleCounter = 0; sampleCounter < numSamples; ++sampleCounter) { + uint32_t sampleByteLength = (KHR_DFDSVAL(BDFDB, sampleCounter, BITLENGTH) + 1) >> 3U; + uint32_t sampleChannel = KHR_DFDSVAL(BDFDB, sampleCounter, CHANNELID); + + if (sampleChannel == currentChannel) { + /* Continuation of the same channel. */ + /* Accumulate the byte length. */ + *componentByteLength += sampleByteLength; + } else { + /* Everything is new. Hopefully. */ + currentChannel = sampleChannel; + (*numComponents)++; + *componentByteLength = sampleByteLength; + } + } +} + +/** + * @~English + * @brief Return the number of "components" in the data. + * + * Calculates the number of uniques samples in the DFD by combining + * multiple samples for the same channel. For uncompressed colorModels + * this is the same as the number of components in the image data. For + * block-compressed color models this is the number of samples in + * the color model, typically 1 and in a few cases 2. + * + * @param DFD Pointer to a Data Format Descriptor for which, + * described as 32-bit words in native endianness. + * Note that this is the whole descriptor, not just + * the basic descriptor block. + */ +uint32_t getDFDNumComponents(const uint32_t* DFD) +{ + const uint32_t *BDFDB = DFD+1; + uint32_t currentChannel = ~0U; /* Don't start matched. */ + uint32_t numComponents = 0; + uint32_t numSamples = KHR_DFDSAMPLECOUNT(BDFDB); + uint32_t sampleCounter; + + for (sampleCounter = 0; sampleCounter < numSamples; ++sampleCounter) { + uint32_t sampleChannel = KHR_DFDSVAL(BDFDB, sampleCounter, CHANNELID); + if (sampleChannel != currentChannel) { + numComponents++; + currentChannel = sampleChannel; + } + } + return numComponents; +} + +/** + * @~English + * @brief Recreate the value of bytesPlane0 from sample info. + * + * This can be use to recreate the value of bytesPlane0 for data that + * has been variable-rate compressed so has bytesPlane0 = 0. For DFDs + * that are valid for KTX files. Little-endian data only and no multi-plane + * formats. + * + * @param DFD Pointer to a Data Format Descriptor for which, + * described as 32-bit words in native endianness. + * Note that this is the whole descriptor, not just + * the basic descriptor block. + * @param bytesPlane0 pointer to a 32-bit word in which the recreated + * value of bytesPlane0 will be written. + */ +void +recreateBytesPlane0FromSampleInfo(const uint32_t* DFD, uint32_t* bytesPlane0) +{ + const uint32_t *BDFDB = DFD+1; + uint32_t numSamples = KHR_DFDSAMPLECOUNT(BDFDB); + uint32_t sampleCounter; + + uint32_t bitsPlane0 = 0; + uint32_t* bitOffsets = malloc(sizeof(uint32_t) * numSamples); + memset(bitOffsets, -1, sizeof(uint32_t) * numSamples); + for (sampleCounter = 0; sampleCounter < numSamples; ++sampleCounter) { + uint32_t sampleBitOffset = KHR_DFDSVAL(BDFDB, sampleCounter, BITOFFSET); + /* The sample bitLength field stores the bit length - 1. */ + uint32_t sampleBitLength = KHR_DFDSVAL(BDFDB, sampleCounter, BITLENGTH) + 1; + uint32_t i; + for (i = 0; i < numSamples; i++) { + if (sampleBitOffset == bitOffsets[i]) { + // This sample is being repeated as in e.g. RGB9E5. + break; + } + } + if (i == numSamples) { + // Previously unseen bitOffset. Bump size. + bitsPlane0 += sampleBitLength; + bitOffsets[sampleCounter] = sampleBitOffset; + } + } + free(bitOffsets); + *bytesPlane0 = bitsPlane0 >> 3U; +} + diff --git a/thirdparty/libktx/lib/dfdutils/vk2dfd.c b/thirdparty/libktx/lib/dfdutils/vk2dfd.c new file mode 100644 index 000000000000..d476ced1be5e --- /dev/null +++ b/thirdparty/libktx/lib/dfdutils/vk2dfd.c @@ -0,0 +1,34 @@ +/* -*- tab-width: 4; -*- */ +/* vi: set sw=2 ts=4 expandtab: */ + +/* Copyright 2019-2020 Mark Callow + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @~English + * @brief Create a DFD for a VkFormat. + */ + +#include "dfd.h" + +/** + * @~English + * @brief Create a DFD matching a VkFormat. + * + * @param[in] format VkFormat for which to create a DFD. + * + * @return pointer to the created DFD or 0 if format not supported or + * unrecognized. Caller is responsible for freeing the created + * DFD. + */ +uint32_t* +vk2dfd(enum VkFormat format) + { + switch (format) { +#include "vk2dfd.inl" + default: return 0; + } + } + diff --git a/thirdparty/libktx/lib/dfdutils/vk2dfd.inl b/thirdparty/libktx/lib/dfdutils/vk2dfd.inl new file mode 100644 index 000000000000..4ae1e6d5e1db --- /dev/null +++ b/thirdparty/libktx/lib/dfdutils/vk2dfd.inl @@ -0,0 +1,340 @@ +/* Copyright 2019-2020 The Khronos Group Inc. */ +/* SPDX-License-Identifier: Apache-2.0 */ + +/***************************** Do not edit. ***************************** + Automatically generated by makevk2dfd.pl. + *************************************************************************/ + +/* Vulkan combined depth & stencil formats are not included here + * because they do not exist outside a Vulkan device. + */ +case VK_FORMAT_R4G4_UNORM_PACK8: { + int channels[] = {1,0}; int bits[] = {4,4}; + return createDFDPacked(0, 2, bits, channels, s_UNORM); +} +case VK_FORMAT_R4G4B4A4_UNORM_PACK16: { + int channels[] = {3,2,1,0}; int bits[] = {4,4,4,4}; + return createDFDPacked(0, 4, bits, channels, s_UNORM); +} +case VK_FORMAT_B4G4R4A4_UNORM_PACK16: { + int channels[] = {3,0,1,2}; int bits[] = {4,4,4,4}; + return createDFDPacked(0, 4, bits, channels, s_UNORM); +} +case VK_FORMAT_R5G6B5_UNORM_PACK16: { + int channels[] = {2,1,0}; int bits[] = {5,6,5}; + return createDFDPacked(0, 3, bits, channels, s_UNORM); +} +case VK_FORMAT_B5G6R5_UNORM_PACK16: { + int channels[] = {0,1,2}; int bits[] = {5,6,5}; + return createDFDPacked(0, 3, bits, channels, s_UNORM); +} +case VK_FORMAT_R5G5B5A1_UNORM_PACK16: { + int channels[] = {3,2,1,0}; int bits[] = {1,5,5,5}; + return createDFDPacked(0, 4, bits, channels, s_UNORM); +} +case VK_FORMAT_B5G5R5A1_UNORM_PACK16: { + int channels[] = {3,0,1,2}; int bits[] = {1,5,5,5}; + return createDFDPacked(0, 4, bits, channels, s_UNORM); +} +case VK_FORMAT_A1R5G5B5_UNORM_PACK16: { + int channels[] = {2,1,0,3}; int bits[] = {5,5,5,1}; + return createDFDPacked(0, 4, bits, channels, s_UNORM); +} +case VK_FORMAT_R8_UNORM: return createDFDUnpacked(0, 1, 1, 0, s_UNORM); +case VK_FORMAT_R8_SNORM: return createDFDUnpacked(0, 1, 1, 0, s_SNORM); +case VK_FORMAT_R8_USCALED: return createDFDUnpacked(0, 1, 1, 0, s_USCALED); +case VK_FORMAT_R8_SSCALED: return createDFDUnpacked(0, 1, 1, 0, s_SSCALED); +case VK_FORMAT_R8_UINT: return createDFDUnpacked(0, 1, 1, 0, s_UINT); +case VK_FORMAT_R8_SINT: return createDFDUnpacked(0, 1, 1, 0, s_SINT); +case VK_FORMAT_R8_SRGB: return createDFDUnpacked(0, 1, 1, 0, s_SRGB); +case VK_FORMAT_R8G8_UNORM: return createDFDUnpacked(0, 2, 1, 0, s_UNORM); +case VK_FORMAT_R8G8_SNORM: return createDFDUnpacked(0, 2, 1, 0, s_SNORM); +case VK_FORMAT_R8G8_USCALED: return createDFDUnpacked(0, 2, 1, 0, s_USCALED); +case VK_FORMAT_R8G8_SSCALED: return createDFDUnpacked(0, 2, 1, 0, s_SSCALED); +case VK_FORMAT_R8G8_UINT: return createDFDUnpacked(0, 2, 1, 0, s_UINT); +case VK_FORMAT_R8G8_SINT: return createDFDUnpacked(0, 2, 1, 0, s_SINT); +case VK_FORMAT_R8G8_SRGB: return createDFDUnpacked(0, 2, 1, 0, s_SRGB); +case VK_FORMAT_R8G8B8_UNORM: return createDFDUnpacked(0, 3, 1, 0, s_UNORM); +case VK_FORMAT_R8G8B8_SNORM: return createDFDUnpacked(0, 3, 1, 0, s_SNORM); +case VK_FORMAT_R8G8B8_USCALED: return createDFDUnpacked(0, 3, 1, 0, s_USCALED); +case VK_FORMAT_R8G8B8_SSCALED: return createDFDUnpacked(0, 3, 1, 0, s_SSCALED); +case VK_FORMAT_R8G8B8_UINT: return createDFDUnpacked(0, 3, 1, 0, s_UINT); +case VK_FORMAT_R8G8B8_SINT: return createDFDUnpacked(0, 3, 1, 0, s_SINT); +case VK_FORMAT_R8G8B8_SRGB: return createDFDUnpacked(0, 3, 1, 0, s_SRGB); +case VK_FORMAT_B8G8R8_UNORM: return createDFDUnpacked(0, 3, 1, 1, s_UNORM); +case VK_FORMAT_B8G8R8_SNORM: return createDFDUnpacked(0, 3, 1, 1, s_SNORM); +case VK_FORMAT_B8G8R8_USCALED: return createDFDUnpacked(0, 3, 1, 1, s_USCALED); +case VK_FORMAT_B8G8R8_SSCALED: return createDFDUnpacked(0, 3, 1, 1, s_SSCALED); +case VK_FORMAT_B8G8R8_UINT: return createDFDUnpacked(0, 3, 1, 1, s_UINT); +case VK_FORMAT_B8G8R8_SINT: return createDFDUnpacked(0, 3, 1, 1, s_SINT); +case VK_FORMAT_B8G8R8_SRGB: return createDFDUnpacked(0, 3, 1, 1, s_SRGB); +case VK_FORMAT_R8G8B8A8_UNORM: return createDFDUnpacked(0, 4, 1, 0, s_UNORM); +case VK_FORMAT_R8G8B8A8_SNORM: return createDFDUnpacked(0, 4, 1, 0, s_SNORM); +case VK_FORMAT_R8G8B8A8_USCALED: return createDFDUnpacked(0, 4, 1, 0, s_USCALED); +case VK_FORMAT_R8G8B8A8_SSCALED: return createDFDUnpacked(0, 4, 1, 0, s_SSCALED); +case VK_FORMAT_R8G8B8A8_UINT: return createDFDUnpacked(0, 4, 1, 0, s_UINT); +case VK_FORMAT_R8G8B8A8_SINT: return createDFDUnpacked(0, 4, 1, 0, s_SINT); +case VK_FORMAT_R8G8B8A8_SRGB: return createDFDUnpacked(0, 4, 1, 0, s_SRGB); +case VK_FORMAT_B8G8R8A8_UNORM: return createDFDUnpacked(0, 4, 1, 1, s_UNORM); +case VK_FORMAT_B8G8R8A8_SNORM: return createDFDUnpacked(0, 4, 1, 1, s_SNORM); +case VK_FORMAT_B8G8R8A8_USCALED: return createDFDUnpacked(0, 4, 1, 1, s_USCALED); +case VK_FORMAT_B8G8R8A8_SSCALED: return createDFDUnpacked(0, 4, 1, 1, s_SSCALED); +case VK_FORMAT_B8G8R8A8_UINT: return createDFDUnpacked(0, 4, 1, 1, s_UINT); +case VK_FORMAT_B8G8R8A8_SINT: return createDFDUnpacked(0, 4, 1, 1, s_SINT); +case VK_FORMAT_B8G8R8A8_SRGB: return createDFDUnpacked(0, 4, 1, 1, s_SRGB); +case VK_FORMAT_A8B8G8R8_UNORM_PACK32: { + int channels[] = {0,1,2,3}; int bits[] = {8,8,8,8}; + return createDFDPacked(0, 4, bits, channels, s_UNORM); +} +case VK_FORMAT_A8B8G8R8_SNORM_PACK32: { + int channels[] = {0,1,2,3}; int bits[] = {8,8,8,8}; + return createDFDPacked(0, 4, bits, channels, s_SNORM); +} +case VK_FORMAT_A8B8G8R8_USCALED_PACK32: { + int channels[] = {0,1,2,3}; int bits[] = {8,8,8,8}; + return createDFDPacked(0, 4, bits, channels, s_USCALED); +} +case VK_FORMAT_A8B8G8R8_SSCALED_PACK32: { + int channels[] = {0,1,2,3}; int bits[] = {8,8,8,8}; + return createDFDPacked(0, 4, bits, channels, s_SSCALED); +} +case VK_FORMAT_A8B8G8R8_UINT_PACK32: { + int channels[] = {0,1,2,3}; int bits[] = {8,8,8,8}; + return createDFDPacked(0, 4, bits, channels, s_UINT); +} +case VK_FORMAT_A8B8G8R8_SINT_PACK32: { + int channels[] = {0,1,2,3}; int bits[] = {8,8,8,8}; + return createDFDPacked(0, 4, bits, channels, s_SINT); +} +case VK_FORMAT_A8B8G8R8_SRGB_PACK32: { + int channels[] = {0,1,2,3}; int bits[] = {8,8,8,8}; + return createDFDPacked(0, 4, bits, channels, s_SRGB); +} +case VK_FORMAT_A2R10G10B10_UNORM_PACK32: { + int channels[] = {2,1,0,3}; int bits[] = {10,10,10,2}; + return createDFDPacked(0, 4, bits, channels, s_UNORM); +} +case VK_FORMAT_A2R10G10B10_SNORM_PACK32: { + int channels[] = {2,1,0,3}; int bits[] = {10,10,10,2}; + return createDFDPacked(0, 4, bits, channels, s_SNORM); +} +case VK_FORMAT_A2R10G10B10_USCALED_PACK32: { + int channels[] = {2,1,0,3}; int bits[] = {10,10,10,2}; + return createDFDPacked(0, 4, bits, channels, s_USCALED); +} +case VK_FORMAT_A2R10G10B10_SSCALED_PACK32: { + int channels[] = {2,1,0,3}; int bits[] = {10,10,10,2}; + return createDFDPacked(0, 4, bits, channels, s_SSCALED); +} +case VK_FORMAT_A2R10G10B10_UINT_PACK32: { + int channels[] = {2,1,0,3}; int bits[] = {10,10,10,2}; + return createDFDPacked(0, 4, bits, channels, s_UINT); +} +case VK_FORMAT_A2R10G10B10_SINT_PACK32: { + int channels[] = {2,1,0,3}; int bits[] = {10,10,10,2}; + return createDFDPacked(0, 4, bits, channels, s_SINT); +} +case VK_FORMAT_A2B10G10R10_UNORM_PACK32: { + int channels[] = {0,1,2,3}; int bits[] = {10,10,10,2}; + return createDFDPacked(0, 4, bits, channels, s_UNORM); +} +case VK_FORMAT_A2B10G10R10_SNORM_PACK32: { + int channels[] = {0,1,2,3}; int bits[] = {10,10,10,2}; + return createDFDPacked(0, 4, bits, channels, s_SNORM); +} +case VK_FORMAT_A2B10G10R10_USCALED_PACK32: { + int channels[] = {0,1,2,3}; int bits[] = {10,10,10,2}; + return createDFDPacked(0, 4, bits, channels, s_USCALED); +} +case VK_FORMAT_A2B10G10R10_SSCALED_PACK32: { + int channels[] = {0,1,2,3}; int bits[] = {10,10,10,2}; + return createDFDPacked(0, 4, bits, channels, s_SSCALED); +} +case VK_FORMAT_A2B10G10R10_UINT_PACK32: { + int channels[] = {0,1,2,3}; int bits[] = {10,10,10,2}; + return createDFDPacked(0, 4, bits, channels, s_UINT); +} +case VK_FORMAT_A2B10G10R10_SINT_PACK32: { + int channels[] = {0,1,2,3}; int bits[] = {10,10,10,2}; + return createDFDPacked(0, 4, bits, channels, s_SINT); +} +case VK_FORMAT_R16_UNORM: return createDFDUnpacked(0, 1, 2, 0, s_UNORM); +case VK_FORMAT_R16_SNORM: return createDFDUnpacked(0, 1, 2, 0, s_SNORM); +case VK_FORMAT_R16_USCALED: return createDFDUnpacked(0, 1, 2, 0, s_USCALED); +case VK_FORMAT_R16_SSCALED: return createDFDUnpacked(0, 1, 2, 0, s_SSCALED); +case VK_FORMAT_R16_UINT: return createDFDUnpacked(0, 1, 2, 0, s_UINT); +case VK_FORMAT_R16_SINT: return createDFDUnpacked(0, 1, 2, 0, s_SINT); +case VK_FORMAT_R16_SFLOAT: return createDFDUnpacked(0, 1, 2, 0, s_SFLOAT); +case VK_FORMAT_R16G16_UNORM: return createDFDUnpacked(0, 2, 2, 0, s_UNORM); +case VK_FORMAT_R16G16_SNORM: return createDFDUnpacked(0, 2, 2, 0, s_SNORM); +case VK_FORMAT_R16G16_USCALED: return createDFDUnpacked(0, 2, 2, 0, s_USCALED); +case VK_FORMAT_R16G16_SSCALED: return createDFDUnpacked(0, 2, 2, 0, s_SSCALED); +case VK_FORMAT_R16G16_UINT: return createDFDUnpacked(0, 2, 2, 0, s_UINT); +case VK_FORMAT_R16G16_SINT: return createDFDUnpacked(0, 2, 2, 0, s_SINT); +case VK_FORMAT_R16G16_SFLOAT: return createDFDUnpacked(0, 2, 2, 0, s_SFLOAT); +case VK_FORMAT_R16G16B16_UNORM: return createDFDUnpacked(0, 3, 2, 0, s_UNORM); +case VK_FORMAT_R16G16B16_SNORM: return createDFDUnpacked(0, 3, 2, 0, s_SNORM); +case VK_FORMAT_R16G16B16_USCALED: return createDFDUnpacked(0, 3, 2, 0, s_USCALED); +case VK_FORMAT_R16G16B16_SSCALED: return createDFDUnpacked(0, 3, 2, 0, s_SSCALED); +case VK_FORMAT_R16G16B16_UINT: return createDFDUnpacked(0, 3, 2, 0, s_UINT); +case VK_FORMAT_R16G16B16_SINT: return createDFDUnpacked(0, 3, 2, 0, s_SINT); +case VK_FORMAT_R16G16B16_SFLOAT: return createDFDUnpacked(0, 3, 2, 0, s_SFLOAT); +case VK_FORMAT_R16G16B16A16_UNORM: return createDFDUnpacked(0, 4, 2, 0, s_UNORM); +case VK_FORMAT_R16G16B16A16_SNORM: return createDFDUnpacked(0, 4, 2, 0, s_SNORM); +case VK_FORMAT_R16G16B16A16_USCALED: return createDFDUnpacked(0, 4, 2, 0, s_USCALED); +case VK_FORMAT_R16G16B16A16_SSCALED: return createDFDUnpacked(0, 4, 2, 0, s_SSCALED); +case VK_FORMAT_R16G16B16A16_UINT: return createDFDUnpacked(0, 4, 2, 0, s_UINT); +case VK_FORMAT_R16G16B16A16_SINT: return createDFDUnpacked(0, 4, 2, 0, s_SINT); +case VK_FORMAT_R16G16B16A16_SFLOAT: return createDFDUnpacked(0, 4, 2, 0, s_SFLOAT); +case VK_FORMAT_R32_UINT: return createDFDUnpacked(0, 1, 4, 0, s_UINT); +case VK_FORMAT_R32_SINT: return createDFDUnpacked(0, 1, 4, 0, s_SINT); +case VK_FORMAT_R32_SFLOAT: return createDFDUnpacked(0, 1, 4, 0, s_SFLOAT); +case VK_FORMAT_R32G32_UINT: return createDFDUnpacked(0, 2, 4, 0, s_UINT); +case VK_FORMAT_R32G32_SINT: return createDFDUnpacked(0, 2, 4, 0, s_SINT); +case VK_FORMAT_R32G32_SFLOAT: return createDFDUnpacked(0, 2, 4, 0, s_SFLOAT); +case VK_FORMAT_R32G32B32_UINT: return createDFDUnpacked(0, 3, 4, 0, s_UINT); +case VK_FORMAT_R32G32B32_SINT: return createDFDUnpacked(0, 3, 4, 0, s_SINT); +case VK_FORMAT_R32G32B32_SFLOAT: return createDFDUnpacked(0, 3, 4, 0, s_SFLOAT); +case VK_FORMAT_R32G32B32A32_UINT: return createDFDUnpacked(0, 4, 4, 0, s_UINT); +case VK_FORMAT_R32G32B32A32_SINT: return createDFDUnpacked(0, 4, 4, 0, s_SINT); +case VK_FORMAT_R32G32B32A32_SFLOAT: return createDFDUnpacked(0, 4, 4, 0, s_SFLOAT); +case VK_FORMAT_R64_UINT: return createDFDUnpacked(0, 1, 8, 0, s_UINT); +case VK_FORMAT_R64_SINT: return createDFDUnpacked(0, 1, 8, 0, s_SINT); +case VK_FORMAT_R64_SFLOAT: return createDFDUnpacked(0, 1, 8, 0, s_SFLOAT); +case VK_FORMAT_R64G64_UINT: return createDFDUnpacked(0, 2, 8, 0, s_UINT); +case VK_FORMAT_R64G64_SINT: return createDFDUnpacked(0, 2, 8, 0, s_SINT); +case VK_FORMAT_R64G64_SFLOAT: return createDFDUnpacked(0, 2, 8, 0, s_SFLOAT); +case VK_FORMAT_R64G64B64_UINT: return createDFDUnpacked(0, 3, 8, 0, s_UINT); +case VK_FORMAT_R64G64B64_SINT: return createDFDUnpacked(0, 3, 8, 0, s_SINT); +case VK_FORMAT_R64G64B64_SFLOAT: return createDFDUnpacked(0, 3, 8, 0, s_SFLOAT); +case VK_FORMAT_R64G64B64A64_UINT: return createDFDUnpacked(0, 4, 8, 0, s_UINT); +case VK_FORMAT_R64G64B64A64_SINT: return createDFDUnpacked(0, 4, 8, 0, s_SINT); +case VK_FORMAT_R64G64B64A64_SFLOAT: return createDFDUnpacked(0, 4, 8, 0, s_SFLOAT); +case VK_FORMAT_B10G11R11_UFLOAT_PACK32: { + int channels[] = {0,1,2}; int bits[] = {11,11,10}; + return createDFDPacked(0, 3, bits, channels, s_UFLOAT); +} +case VK_FORMAT_E5B9G9R9_UFLOAT_PACK32: { + int bits[] = {0}; int channels[] = {0}; + return createDFDPacked(0, 6, bits, channels, s_UFLOAT); +} +case VK_FORMAT_D16_UNORM: return createDFDDepthStencil(16,0,2); +case VK_FORMAT_X8_D24_UNORM_PACK32: return createDFDDepthStencil(24,0,4); +case VK_FORMAT_D32_SFLOAT: return createDFDDepthStencil(32,0,4); +case VK_FORMAT_S8_UINT: return createDFDDepthStencil(0,8,1); +case VK_FORMAT_BC1_RGB_UNORM_BLOCK: return createDFDCompressed(c_BC1_RGB, 4, 4, 1, s_UNORM); +case VK_FORMAT_BC1_RGB_SRGB_BLOCK: return createDFDCompressed(c_BC1_RGB, 4, 4, 1, s_SRGB); +case VK_FORMAT_BC1_RGBA_UNORM_BLOCK: return createDFDCompressed(c_BC1_RGBA, 4, 4, 1, s_UNORM); +case VK_FORMAT_BC1_RGBA_SRGB_BLOCK: return createDFDCompressed(c_BC1_RGBA, 4, 4, 1, s_SRGB); +case VK_FORMAT_BC2_UNORM_BLOCK: return createDFDCompressed(c_BC2, 4, 4, 1, s_UNORM); +case VK_FORMAT_BC2_SRGB_BLOCK: return createDFDCompressed(c_BC2, 4, 4, 1, s_SRGB); +case VK_FORMAT_BC3_UNORM_BLOCK: return createDFDCompressed(c_BC3, 4, 4, 1, s_UNORM); +case VK_FORMAT_BC3_SRGB_BLOCK: return createDFDCompressed(c_BC3, 4, 4, 1, s_SRGB); +case VK_FORMAT_BC4_UNORM_BLOCK: return createDFDCompressed(c_BC4, 4, 4, 1, s_UNORM); +case VK_FORMAT_BC4_SNORM_BLOCK: return createDFDCompressed(c_BC4, 4, 4, 1, s_SNORM); +case VK_FORMAT_BC5_UNORM_BLOCK: return createDFDCompressed(c_BC5, 4, 4, 1, s_UNORM); +case VK_FORMAT_BC5_SNORM_BLOCK: return createDFDCompressed(c_BC5, 4, 4, 1, s_SNORM); +case VK_FORMAT_BC6H_UFLOAT_BLOCK: return createDFDCompressed(c_BC6H, 4, 4, 1, s_UFLOAT); +case VK_FORMAT_BC6H_SFLOAT_BLOCK: return createDFDCompressed(c_BC6H, 4, 4, 1, s_SFLOAT); +case VK_FORMAT_BC7_UNORM_BLOCK: return createDFDCompressed(c_BC7, 4, 4, 1, s_UNORM); +case VK_FORMAT_BC7_SRGB_BLOCK: return createDFDCompressed(c_BC7, 4, 4, 1, s_SRGB); +case VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK: return createDFDCompressed(c_ETC2_R8G8B8, 4, 4, 1, s_UNORM); +case VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK: return createDFDCompressed(c_ETC2_R8G8B8, 4, 4, 1, s_SRGB); +case VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK: return createDFDCompressed(c_ETC2_R8G8B8A1, 4, 4, 1, s_UNORM); +case VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK: return createDFDCompressed(c_ETC2_R8G8B8A1, 4, 4, 1, s_SRGB); +case VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK: return createDFDCompressed(c_ETC2_R8G8B8A8, 4, 4, 1, s_UNORM); +case VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK: return createDFDCompressed(c_ETC2_R8G8B8A8, 4, 4, 1, s_SRGB); +case VK_FORMAT_EAC_R11_UNORM_BLOCK: return createDFDCompressed(c_EAC_R11, 4, 4, 1, s_UNORM); +case VK_FORMAT_EAC_R11_SNORM_BLOCK: return createDFDCompressed(c_EAC_R11, 4, 4, 1, s_SNORM); +case VK_FORMAT_EAC_R11G11_UNORM_BLOCK: return createDFDCompressed(c_EAC_R11G11, 4, 4, 1, s_UNORM); +case VK_FORMAT_EAC_R11G11_SNORM_BLOCK: return createDFDCompressed(c_EAC_R11G11, 4, 4, 1, s_SNORM); +case VK_FORMAT_ASTC_4x4_UNORM_BLOCK: return createDFDCompressed(c_ASTC, 4, 4, 1, s_UNORM); +case VK_FORMAT_ASTC_4x4_SRGB_BLOCK: return createDFDCompressed(c_ASTC, 4, 4, 1, s_SRGB); +case VK_FORMAT_ASTC_5x4_UNORM_BLOCK: return createDFDCompressed(c_ASTC, 5, 4, 1, s_UNORM); +case VK_FORMAT_ASTC_5x4_SRGB_BLOCK: return createDFDCompressed(c_ASTC, 5, 4, 1, s_SRGB); +case VK_FORMAT_ASTC_5x5_UNORM_BLOCK: return createDFDCompressed(c_ASTC, 5, 5, 1, s_UNORM); +case VK_FORMAT_ASTC_5x5_SRGB_BLOCK: return createDFDCompressed(c_ASTC, 5, 5, 1, s_SRGB); +case VK_FORMAT_ASTC_6x5_UNORM_BLOCK: return createDFDCompressed(c_ASTC, 6, 5, 1, s_UNORM); +case VK_FORMAT_ASTC_6x5_SRGB_BLOCK: return createDFDCompressed(c_ASTC, 6, 5, 1, s_SRGB); +case VK_FORMAT_ASTC_6x6_UNORM_BLOCK: return createDFDCompressed(c_ASTC, 6, 6, 1, s_UNORM); +case VK_FORMAT_ASTC_6x6_SRGB_BLOCK: return createDFDCompressed(c_ASTC, 6, 6, 1, s_SRGB); +case VK_FORMAT_ASTC_8x5_UNORM_BLOCK: return createDFDCompressed(c_ASTC, 8, 5, 1, s_UNORM); +case VK_FORMAT_ASTC_8x5_SRGB_BLOCK: return createDFDCompressed(c_ASTC, 8, 5, 1, s_SRGB); +case VK_FORMAT_ASTC_8x6_UNORM_BLOCK: return createDFDCompressed(c_ASTC, 8, 6, 1, s_UNORM); +case VK_FORMAT_ASTC_8x6_SRGB_BLOCK: return createDFDCompressed(c_ASTC, 8, 6, 1, s_SRGB); +case VK_FORMAT_ASTC_8x8_UNORM_BLOCK: return createDFDCompressed(c_ASTC, 8, 8, 1, s_UNORM); +case VK_FORMAT_ASTC_8x8_SRGB_BLOCK: return createDFDCompressed(c_ASTC, 8, 8, 1, s_SRGB); +case VK_FORMAT_ASTC_10x5_UNORM_BLOCK: return createDFDCompressed(c_ASTC, 10, 5, 1, s_UNORM); +case VK_FORMAT_ASTC_10x5_SRGB_BLOCK: return createDFDCompressed(c_ASTC, 10, 5, 1, s_SRGB); +case VK_FORMAT_ASTC_10x6_UNORM_BLOCK: return createDFDCompressed(c_ASTC, 10, 6, 1, s_UNORM); +case VK_FORMAT_ASTC_10x6_SRGB_BLOCK: return createDFDCompressed(c_ASTC, 10, 6, 1, s_SRGB); +case VK_FORMAT_ASTC_10x8_UNORM_BLOCK: return createDFDCompressed(c_ASTC, 10, 8, 1, s_UNORM); +case VK_FORMAT_ASTC_10x8_SRGB_BLOCK: return createDFDCompressed(c_ASTC, 10, 8, 1, s_SRGB); +case VK_FORMAT_ASTC_10x10_UNORM_BLOCK: return createDFDCompressed(c_ASTC, 10, 10, 1, s_UNORM); +case VK_FORMAT_ASTC_10x10_SRGB_BLOCK: return createDFDCompressed(c_ASTC, 10, 10, 1, s_SRGB); +case VK_FORMAT_ASTC_12x10_UNORM_BLOCK: return createDFDCompressed(c_ASTC, 12, 10, 1, s_UNORM); +case VK_FORMAT_ASTC_12x10_SRGB_BLOCK: return createDFDCompressed(c_ASTC, 12, 10, 1, s_SRGB); +case VK_FORMAT_ASTC_12x12_UNORM_BLOCK: return createDFDCompressed(c_ASTC, 12, 12, 1, s_UNORM); +case VK_FORMAT_ASTC_12x12_SRGB_BLOCK: return createDFDCompressed(c_ASTC, 12, 12, 1, s_SRGB); +case VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG: return createDFDCompressed(c_PVRTC, 8, 4, 1, s_UNORM); +case VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG: return createDFDCompressed(c_PVRTC, 4, 4, 1, s_UNORM); +case VK_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG: return createDFDCompressed(c_PVRTC2, 8, 4, 1, s_UNORM); +case VK_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG: return createDFDCompressed(c_PVRTC2, 4, 4, 1, s_UNORM); +case VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG: return createDFDCompressed(c_PVRTC, 8, 4, 1, s_SRGB); +case VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG: return createDFDCompressed(c_PVRTC, 4, 4, 1, s_SRGB); +case VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG: return createDFDCompressed(c_PVRTC2, 8, 4, 1, s_SRGB); +case VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG: return createDFDCompressed(c_PVRTC2, 4, 4, 1, s_SRGB); +case VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK_EXT: return createDFDCompressed(c_ASTC, 4, 4, 1, s_SFLOAT); +case VK_FORMAT_ASTC_5x4_SFLOAT_BLOCK_EXT: return createDFDCompressed(c_ASTC, 5, 4, 1, s_SFLOAT); +case VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK_EXT: return createDFDCompressed(c_ASTC, 5, 5, 1, s_SFLOAT); +case VK_FORMAT_ASTC_6x5_SFLOAT_BLOCK_EXT: return createDFDCompressed(c_ASTC, 6, 5, 1, s_SFLOAT); +case VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK_EXT: return createDFDCompressed(c_ASTC, 6, 6, 1, s_SFLOAT); +case VK_FORMAT_ASTC_8x5_SFLOAT_BLOCK_EXT: return createDFDCompressed(c_ASTC, 8, 5, 1, s_SFLOAT); +case VK_FORMAT_ASTC_8x6_SFLOAT_BLOCK_EXT: return createDFDCompressed(c_ASTC, 8, 6, 1, s_SFLOAT); +case VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK_EXT: return createDFDCompressed(c_ASTC, 8, 8, 1, s_SFLOAT); +case VK_FORMAT_ASTC_10x5_SFLOAT_BLOCK_EXT: return createDFDCompressed(c_ASTC, 10, 5, 1, s_SFLOAT); +case VK_FORMAT_ASTC_10x6_SFLOAT_BLOCK_EXT: return createDFDCompressed(c_ASTC, 10, 6, 1, s_SFLOAT); +case VK_FORMAT_ASTC_10x8_SFLOAT_BLOCK_EXT: return createDFDCompressed(c_ASTC, 10, 8, 1, s_SFLOAT); +case VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK_EXT: return createDFDCompressed(c_ASTC, 10, 10, 1, s_SFLOAT); +case VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK_EXT: return createDFDCompressed(c_ASTC, 12, 10, 1, s_SFLOAT); +case VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK_EXT: return createDFDCompressed(c_ASTC, 12, 12, 1, s_SFLOAT); +#if 0 +case VK_FORMAT_ASTC_3x3x3_UNORM_BLOCK_EXT: return createDFDCompressed(c_ASTC, 3, 3, 3, s_UNORM); +case VK_FORMAT_ASTC_3x3x3_SRGB_BLOCK_EXT: return createDFDCompressed(c_ASTC, 3, 3, 3, s_SRGB); +case VK_FORMAT_ASTC_3x3x3_SFLOAT_BLOCK_EXT: return createDFDCompressed(c_ASTC, 3, 3, 3, s_SFLOAT); +case VK_FORMAT_ASTC_4x3x3_UNORM_BLOCK_EXT: return createDFDCompressed(c_ASTC, 4, 3, 3, s_UNORM); +case VK_FORMAT_ASTC_4x3x3_SRGB_BLOCK_EXT: return createDFDCompressed(c_ASTC, 4, 3, 3, s_SRGB); +case VK_FORMAT_ASTC_4x3x3_SFLOAT_BLOCK_EXT: return createDFDCompressed(c_ASTC, 4, 3, 3, s_SFLOAT); +case VK_FORMAT_ASTC_4x4x3_UNORM_BLOCK_EXT: return createDFDCompressed(c_ASTC, 4, 4, 3, s_UNORM); +case VK_FORMAT_ASTC_4x4x3_SRGB_BLOCK_EXT: return createDFDCompressed(c_ASTC, 4, 4, 3, s_SRGB); +case VK_FORMAT_ASTC_4x4x3_SFLOAT_BLOCK_EXT: return createDFDCompressed(c_ASTC, 4, 4, 3, s_SFLOAT); +case VK_FORMAT_ASTC_4x4x4_UNORM_BLOCK_EXT: return createDFDCompressed(c_ASTC, 4, 4, 4, s_UNORM); +case VK_FORMAT_ASTC_4x4x4_SRGB_BLOCK_EXT: return createDFDCompressed(c_ASTC, 4, 4, 4, s_SRGB); +case VK_FORMAT_ASTC_4x4x4_SFLOAT_BLOCK_EXT: return createDFDCompressed(c_ASTC, 4, 4, 4, s_SFLOAT); +case VK_FORMAT_ASTC_5x4x4_UNORM_BLOCK_EXT: return createDFDCompressed(c_ASTC, 5, 4, 4, s_UNORM); +case VK_FORMAT_ASTC_5x4x4_SRGB_BLOCK_EXT: return createDFDCompressed(c_ASTC, 5, 4, 4, s_SRGB); +case VK_FORMAT_ASTC_5x4x4_SFLOAT_BLOCK_EXT: return createDFDCompressed(c_ASTC, 5, 4, 4, s_SFLOAT); +case VK_FORMAT_ASTC_5x5x4_UNORM_BLOCK_EXT: return createDFDCompressed(c_ASTC, 5, 5, 4, s_UNORM); +case VK_FORMAT_ASTC_5x5x4_SRGB_BLOCK_EXT: return createDFDCompressed(c_ASTC, 5, 5, 4, s_SRGB); +case VK_FORMAT_ASTC_5x5x4_SFLOAT_BLOCK_EXT: return createDFDCompressed(c_ASTC, 5, 5, 4, s_SFLOAT); +case VK_FORMAT_ASTC_5x5x5_UNORM_BLOCK_EXT: return createDFDCompressed(c_ASTC, 5, 5, 5, s_UNORM); +case VK_FORMAT_ASTC_5x5x5_SRGB_BLOCK_EXT: return createDFDCompressed(c_ASTC, 5, 5, 5, s_SRGB); +case VK_FORMAT_ASTC_5x5x5_SFLOAT_BLOCK_EXT: return createDFDCompressed(c_ASTC, 5, 5, 5, s_SFLOAT); +case VK_FORMAT_ASTC_6x5x5_UNORM_BLOCK_EXT: return createDFDCompressed(c_ASTC, 6, 5, 5, s_UNORM); +case VK_FORMAT_ASTC_6x5x5_SRGB_BLOCK_EXT: return createDFDCompressed(c_ASTC, 6, 5, 5, s_SRGB); +case VK_FORMAT_ASTC_6x5x5_SFLOAT_BLOCK_EXT: return createDFDCompressed(c_ASTC, 6, 5, 5, s_SFLOAT); +case VK_FORMAT_ASTC_6x6x5_UNORM_BLOCK_EXT: return createDFDCompressed(c_ASTC, 6, 6, 5, s_UNORM); +case VK_FORMAT_ASTC_6x6x5_SRGB_BLOCK_EXT: return createDFDCompressed(c_ASTC, 6, 6, 5, s_SRGB); +case VK_FORMAT_ASTC_6x6x5_SFLOAT_BLOCK_EXT: return createDFDCompressed(c_ASTC, 6, 6, 5, s_SFLOAT); +case VK_FORMAT_ASTC_6x6x6_UNORM_BLOCK_EXT: return createDFDCompressed(c_ASTC, 6, 6, 6, s_UNORM); +case VK_FORMAT_ASTC_6x6x6_SRGB_BLOCK_EXT: return createDFDCompressed(c_ASTC, 6, 6, 6, s_SRGB); +case VK_FORMAT_ASTC_6x6x6_SFLOAT_BLOCK_EXT: return createDFDCompressed(c_ASTC, 6, 6, 6, s_SFLOAT); +#endif +case VK_FORMAT_A4R4G4B4_UNORM_PACK16_EXT: { + int channels[] = {2,1,0,3}; int bits[] = {4,4,4,4}; + return createDFDPacked(0, 4, bits, channels, s_UNORM); +} +case VK_FORMAT_A4B4G4R4_UNORM_PACK16_EXT: { + int channels[] = {0,1,2,3}; int bits[] = {4,4,4,4}; + return createDFDPacked(0, 4, bits, channels, s_UNORM); +} diff --git a/thirdparty/libktx/lib/filestream.c b/thirdparty/libktx/lib/filestream.c new file mode 100644 index 000000000000..b1e0eba7c6ff --- /dev/null +++ b/thirdparty/libktx/lib/filestream.c @@ -0,0 +1,393 @@ +/* -*- tab-width: 4; -*- */ +/* vi: set sw=2 ts=4 expandtab: */ + +/* + * Copyright 2010-2020 The Khronos Group Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @~English + * + * @brief Implementation of ktxStream for FILE. + * + * @author Maksim Kolesin, Under Development + * @author Georg Kolling, Imagination Technology + * @author Mark Callow, HI Corporation + */ + +#include +#include +#include +#include +/* I need these on Linux. Why? */ +#define __USE_LARGEFILE 1 // For declaration of ftello, etc. +#define __USE_POSIX 1 // For declaration of fileno. +#define _POSIX_SOURCE 1 // For both the above in Emscripten. +#include +#include +#include // For stat.h on Windows +#define __USE_MISC 1 // For declaration of S_IF... +#include + +#include "ktx.h" +#include "ktxint.h" +#include "filestream.h" + +// Gotta love Windows :-( +#if defined(_MSC_VER) + #if defined(_WIN64) + #define ftello _ftelli64 + #define fseeko _fseeki64 + #else + #define ftello ftell + #define fseeko fseek + #endif + #define fileno _fileno + #define fstat _fstat + #define stat _stat + #define S_IFIFO _S_IFIFO + #define S_IFSOCK 0xC000 + typedef unsigned short mode_t; +#endif + +#if defined(__MINGW32__) + #define S_IFSOCK 0xC000 +#endif + +#define KTX_FILE_STREAM_MAX (1 << (sizeof(ktx_off_t) - 1) - 1) + +/** + * @~English + * @brief Read bytes from a ktxFileStream. + * + * @param [in] str pointer to the ktxStream from which to read. + * @param [out] dst pointer to a block of memory with a size + * of at least @p size bytes, converted to a void*. + * @param [in,out] count pointer to total count of bytes to be read. + * On completion set to number of bytes read. + * + * @return KTX_SUCCESS on success, other KTX_* enum values on error. + * + * @exception KTX_INVALID_VALUE @p dst is @c NULL or @p src is @c NULL. + * @exception KTX_FILE_READ_ERROR an error occurred while reading the file. + * @exception KTX_FILE_UNEXPECTED_EOF not enough data to satisfy the request. + */ +static +KTX_error_code ktxFileStream_read(ktxStream* str, void* dst, const ktx_size_t count) +{ + ktx_size_t nread; + + if (!str || !dst) + return KTX_INVALID_VALUE; + + assert(str->type == eStreamTypeFile); + + if ((nread = fread(dst, 1, count, str->data.file)) != count) { + if (feof(str->data.file)) { + return KTX_FILE_UNEXPECTED_EOF; + } else { + return KTX_FILE_READ_ERROR; + } + } + str->readpos += count; + + return KTX_SUCCESS; +} + +/** + * @~English + * @brief Skip bytes in a ktxFileStream. + * + * @param [in] str pointer to a ktxStream object. + * @param [in] count number of bytes to be skipped. + * + * In order to support applications reading from stdin, read characters + * rather than using seek functions. + * + * @return KTX_SUCCESS on success, other KTX_* enum values on error. + * + * @exception KTX_INVALID_VALUE @p str is @c NULL or @p count is less than zero. + * @exception KTX_INVALID_OPERATION skipping @p count bytes would go beyond EOF. + * @exception KTX_FILE_READ_ERROR an error occurred while reading the file. + * @exception KTX_FILE_UNEXPECTED_EOF not enough data to satisfy the request. + * @p count is set to the number of bytes + * skipped. + */ +static +KTX_error_code ktxFileStream_skip(ktxStream* str, const ktx_size_t count) +{ + if (!str) + return KTX_INVALID_VALUE; + + assert(str->type == eStreamTypeFile); + + for (ktx_uint32_t i = 0; i < count; i++) { + int ret = getc(str->data.file); + if (ret == EOF) { + if (feof(str->data.file)) { + return KTX_FILE_UNEXPECTED_EOF; + } else { + return KTX_FILE_READ_ERROR; + } + } + } + str->readpos += count; + + return KTX_SUCCESS; +} + +/** + * @~English + * @brief Write bytes to a ktxFileStream. + * + * @param [in] str pointer to the ktxStream that is the destination of the + * write. + * @param [in] src pointer to the array of elements to be written, + * converted to a const void*. + * @param [in] size size in bytes of each element to be written. + * @param [in] count number of elements, each one with a @p size of size + * bytes. + * + * @return KTX_SUCCESS on success, other KTX_* enum values on error. + * + * @exception KTX_INVALID_VALUE @p str is @c NULL or @p src is @c NULL. + * @exception KTX_FILE_OVERFLOW the requested write would caused the file to + * exceed the maximum supported file size. + * @exception KTX_FILE_WRITE_ERROR a system error occurred while writing the + * file. + */ +static +KTX_error_code ktxFileStream_write(ktxStream* str, const void *src, + const ktx_size_t size, + const ktx_size_t count) +{ + if (!str || !src) + return KTX_INVALID_VALUE; + + assert(str->type == eStreamTypeFile); + + if (fwrite(src, size, count, str->data.file) != count) { + if (errno == EFBIG || errno == EOVERFLOW) + return KTX_FILE_OVERFLOW; + else + return KTX_FILE_WRITE_ERROR; + } + + return KTX_SUCCESS; +} + +/** + * @~English + * @brief Get the current read/write position in a ktxFileStream. + * + * @param [in] str pointer to the ktxStream to query. + * @param [in,out] off pointer to variable to receive the offset value. + * + * @return KTX_SUCCESS on success, other KTX_* enum values on error. + * + * @exception KTX_FILE_ISPIPE file descriptor underlying stream is associated + * with a pipe or FIFO so does not have a + * file-position indicator. + * @exception KTX_INVALID_VALUE @p str or @p pos is @c NULL. + */ +static +KTX_error_code ktxFileStream_getpos(ktxStream* str, ktx_off_t* pos) +{ + ktx_off_t ftellval; + + if (!str || !pos) + return KTX_INVALID_VALUE; + + assert(str->type == eStreamTypeFile); + + if (str->data.file == stdin) { + *pos = str->readpos; + } else { + /* The cast quiets an Xcode warning when building for "Generic iOS Device". + * I'm not sure why. + */ + ftellval = (ktx_off_t)ftello(str->data.file); + if (ftellval < 0) { + switch (errno) { + case ESPIPE: return KTX_FILE_ISPIPE; + case EOVERFLOW: return KTX_FILE_OVERFLOW; + } + } + + *pos = ftellval; + } + + return KTX_SUCCESS; +} + +/** + * @~English + * @brief Set the current read/write position in a ktxFileStream. + * + * Offset of 0 is the start of the file. This function operates + * like Linux > 3.1's @c lseek() when it is passed a @c whence + * of @c SEEK_DATA as it returns an error if the seek would + * go beyond the end of the file. + * + * @param [in] str pointer to the ktxStream whose r/w position is to be set. + * @param [in] off pointer to the offset value to set. + * + * @return KTX_SUCCESS on success, other KTX_* enum values on error. + * + * Throws the same exceptions as ktxFileStream_getsize() for the reasons given + * there plus the following: + * + * @exception KTX_INVALID_VALUE @p str is @c NULL. + * @exception KTX_INVALID_OPERATION @p pos is > the size of the file or an + * fseek error occurred. + */ +static +KTX_error_code ktxFileStream_setpos(ktxStream* str, ktx_off_t pos) +{ + ktx_size_t fileSize; + KTX_error_code result; + + if (!str) + return KTX_INVALID_VALUE; + + assert(str->type == eStreamTypeFile); + + if (str->data.file == stdin) { + if (pos > str->readpos) + return str->skip(str, pos - str->readpos); + else + return KTX_FILE_ISPIPE; + } + + result = str->getsize(str, &fileSize); + + if (result != KTX_SUCCESS) { + // Device is likely not seekable. + return result; + } + + if (pos > (ktx_off_t)fileSize) + return KTX_INVALID_OPERATION; + + if (fseeko(str->data.file, pos, SEEK_SET) < 0) + return KTX_FILE_SEEK_ERROR; + else + return KTX_SUCCESS; +} + +/** + * @~English + * @brief Get the size of a ktxFileStream in bytes. + * + * @param [in] str pointer to the ktxStream whose size is to be queried. + * @param [in,out] size pointer to a variable in which size will be written. + * + * @return KTX_SUCCESS on success, other KTX_* enum values on error. + * + * @exception KTX_FILE_OVERFLOW size is too large to be returned in a + * @c ktx_size_t. + * @exception KTX_FILE_ISPIPE file descriptor underlying stream is associated + * with a pipe or FIFO so does not have a + * file-position indicator. + * @exception KTX_FILE_READ_ERROR a system error occurred while getting the + * size. + * @exception KTX_INVALID_VALUE @p str or @p size is @c NULL. + * @exception KTX_INVALID_OPERATION stream is a tty. + */ +static +KTX_error_code ktxFileStream_getsize(ktxStream* str, ktx_size_t* size) +{ + struct stat statbuf; + int statret; + + if (!str || !size) + return KTX_INVALID_VALUE; + + assert(str->type == eStreamTypeFile); + + // Need to flush so that fstat will return the current size. + // Can ignore return value. The only error that can happen is to tell you + // it was a NOP because the file is read only. +#if (defined(_MSC_VER) && _MSC_VER < 1900) || defined(__MINGW64__) && !defined(_UCRT) + // Bug in VS2013 msvcrt. fflush on FILE open for READ changes file offset + // to 4096. + if (str->data.file->_flag & _IOWRT) +#endif + (void)fflush(str->data.file); + statret = fstat(fileno(str->data.file), &statbuf); + if (statret < 0) { + switch (errno) { + case EOVERFLOW: return KTX_FILE_OVERFLOW; + case EIO: + default: + return KTX_FILE_READ_ERROR; + } + } + + mode_t ftype = statbuf.st_mode & S_IFMT; + if (ftype == S_IFIFO || ftype == S_IFSOCK) + return KTX_FILE_ISPIPE; + + if (statbuf.st_mode & S_IFCHR) + return KTX_INVALID_OPERATION; + + *size = (ktx_size_t)statbuf.st_size; /* See _getpos for why this cast. */ + + return KTX_SUCCESS; +} + +/** + * @~English + * @brief Initialize a ktxFileStream. + * + * @param [in] str pointer to the ktxStream to initialize. + * @param [in] file pointer to the underlying FILE object. + * @param [in] closeFileOnDestruct if not false, stdio file pointer will be closed when ktxStream + * is destructed. + * + * @return KTX_SUCCESS on success, KTX_INVALID_VALUE on error. + * + * @exception KTX_INVALID_VALUE @p stream is @c NULL or @p file is @c NULL. + */ +KTX_error_code ktxFileStream_construct(ktxStream* str, FILE* file, + ktx_bool_t closeFileOnDestruct) +{ + if (!str || !file) + return KTX_INVALID_VALUE; + + str->data.file = file; + str->readpos = 0; + str->type = eStreamTypeFile; + str->read = ktxFileStream_read; + str->skip = ktxFileStream_skip; + str->write = ktxFileStream_write; + str->getpos = ktxFileStream_getpos; + str->setpos = ktxFileStream_setpos; + str->getsize = ktxFileStream_getsize; + str->destruct = ktxFileStream_destruct; + str->closeOnDestruct = closeFileOnDestruct; + + return KTX_SUCCESS; +} + +/** + * @~English + * @brief Destruct the stream, potentially closing the underlying FILE. + * + * This only closes the underyling FILE if the @c closeOnDestruct parameter to + * ktxFileStream_construct() was not @c KTX_FALSE. + * + * @param [in] str pointer to the ktxStream whose FILE is to potentially + * be closed. + */ +void +ktxFileStream_destruct(ktxStream* str) +{ + assert(str && str->type == eStreamTypeFile); + + if (str->closeOnDestruct) + fclose(str->data.file); + str->data.file = 0; +} diff --git a/thirdparty/libktx/lib/filestream.h b/thirdparty/libktx/lib/filestream.h new file mode 100644 index 000000000000..5c0ea7d2dd1e --- /dev/null +++ b/thirdparty/libktx/lib/filestream.h @@ -0,0 +1,27 @@ +/* -*- tab-width: 4; -*- */ +/* vi: set sw=2 ts=4 expandtab: */ + +/* + * Copyright 2010-2020 The Khronos Group Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * Author: Maksim Kolesin from original code + * by Mark Callow and Georg Kolling + */ + +#ifndef FILESTREAM_H +#define FILESTREAM_H + +#include "ktx.h" + +/* + * ktxFileInit: Initialize a ktxStream to a ktxFileStream with a FILE object + */ +KTX_error_code ktxFileStream_construct(ktxStream* str, FILE* file, + ktx_bool_t closeFileOnDestruct); + +void ktxFileStream_destruct(ktxStream* str); + +#endif /* FILESTREAM_H */ diff --git a/thirdparty/libktx/lib/formatsize.h b/thirdparty/libktx/lib/formatsize.h new file mode 100644 index 000000000000..7112a3a90d72 --- /dev/null +++ b/thirdparty/libktx/lib/formatsize.h @@ -0,0 +1,58 @@ +/* -*- tab-width: 4; -*- */ +/* vi: set sw=2 ts=4 expandtab: */ + +/* + * Copyright 2019-2020 The Khronos Group Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @internal + * @file + * @~English + * + * @brief Struct for returning size information about an image format. + * + * @author Mark Callow, www.edgewise-consulting.com + */ + +#ifndef _FORMATSIZE_H_ +#define _FORMATSIZE_H_ + +#include "ktx.h" + +typedef enum ktxFormatSizeFlagBits { + KTX_FORMAT_SIZE_PACKED_BIT = 0x00000001, + KTX_FORMAT_SIZE_COMPRESSED_BIT = 0x00000002, + KTX_FORMAT_SIZE_PALETTIZED_BIT = 0x00000004, + KTX_FORMAT_SIZE_DEPTH_BIT = 0x00000008, + KTX_FORMAT_SIZE_STENCIL_BIT = 0x00000010, +} ktxFormatSizeFlagBits; + +typedef ktx_uint32_t ktxFormatSizeFlags; + +/** + * @brief Structure for holding size information for a texture format. + */ +typedef struct ktxFormatSize { + ktxFormatSizeFlags flags; + unsigned int paletteSizeInBits; // For KTX1. + unsigned int blockSizeInBits; + unsigned int blockWidth; // in texels + unsigned int blockHeight; // in texels + unsigned int blockDepth; // in texels + unsigned int minBlocksX; // Minimum required number of blocks + unsigned int minBlocksY; +} ktxFormatSize; + +#ifdef __cplusplus +extern "C" { +#endif + +bool ktxFormatSize_initFromDfd(ktxFormatSize* This, ktx_uint32_t* pDfd); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif /* _FORMATSIZE_H_ */ diff --git a/thirdparty/libktx/lib/gl_format.h b/thirdparty/libktx/lib/gl_format.h new file mode 100644 index 000000000000..2381505a68c5 --- /dev/null +++ b/thirdparty/libktx/lib/gl_format.h @@ -0,0 +1,2654 @@ +/* +================================================================================================ + +Description : OpenGL formats/types and properties. +Author : J.M.P. van Waveren +Date : 07/17/2016 +Language : C99 +Format : Real tabs with the tab size equal to 4 spaces. +Copyright : Copyright (c) 2016 Oculus VR, LLC. All Rights reserved. + + +LICENSE +======= + +Copyright 2016 Oculus VR, LLC. +SPDX-License-Identifier: Apache-2.0 + + +DESCRIPTION +=========== + +This header stores the OpenGL formats/types and two simple routines +to derive the format/type from an internal format. These routines +are useful to verify the data in a KTX container files. The OpenGL +constants are generally useful to convert files like KTX and glTF +to different graphics APIs. + +This header stores the OpenGL formats/types that are used as parameters +to the following OpenGL functions: + +void glTexImage2D( GLenum target, GLint level, GLint internalFormat, + GLsizei width, GLsizei height, GLint border, + GLenum format, GLenum type, const GLvoid * data ); +void glTexImage3D( GLenum target, GLint level, GLint internalFormat, + GLsizei width, GLsizei height, GLsizei depth, GLint border, + GLenum format, GLenum type, const GLvoid * data ); +void glCompressedTexImage2D( GLenum target, GLint level, GLenum internalformat, + GLsizei width, GLsizei height, GLint border, + GLsizei imageSize, const GLvoid * data ); +void glCompressedTexImage3D( GLenum target, GLint level, GLenum internalformat, + GLsizei width, GLsizei height, GLsizei depth, GLint border, + GLsizei imageSize, const GLvoid * data ); +void glTexStorage2D( GLenum target, GLsizei levels, GLenum internalformat, + GLsizei width, GLsizei height ); +void glTexStorage3D( GLenum target, GLsizei levels, GLenum internalformat, + GLsizei width, GLsizei height, GLsizei depth ); +void glVertexAttribPointer( GLuint index, GLint size, GLenum type, GLboolean normalized, + GLsizei stride, const GLvoid * pointer); + + +IMPLEMENTATION +============== + +This file does not include OpenGL / OpenGL ES headers because: + + 1. Including OpenGL / OpenGL ES headers is platform dependent and + may require a separate installation of an OpenGL SDK. + 2. The OpenGL format/type constants are the same between extensions and core. + 3. The OpenGL format/type constants are the same between OpenGL and OpenGL ES. + 4. The OpenGL constants in this header are also used to derive Vulkan formats + from the OpenGL formats/types stored in files like KTX and glTF. These file + formats may use OpenGL formats/types that are not supported by the OpenGL + implementation on the platform but are supported by the Vulkan implementation. + + +ENTRY POINTS +============ + +static inline GLenum glGetFormatFromInternalFormat( const GLenum internalFormat ); +static inline GLenum glGetTypeFromInternalFormat( const GLenum internalFormat ); +static inline void glGetFormatSize( const GLenum internalFormat, GlFormatSize * pFormatSize ); +static inline unsigned int glGetTypeSizeFromType( const GLenum type ); +static inline GLenum glGetInternalFormatFromVkFormat ( VkFormat format ); + +MODIFICATIONS for use in libktx +=============================== + +2018.3.23 Added glGetTypeSizeFromType. Mark Callow, Edgewise Consulting. +2019.3.09 #if 0 around GL type declarations. 〃 +2019.5.30 Use common ktxFormatSize to return results. 〃 +2019.5.30 Return blockSizeInBits 0 for default case of glGetFormatSize. 〃 +2019.5.30 Added glGetInternalFormatFromVkFormat. 〃 + +================================================================================================ +*/ + +#if !defined( GL_FORMAT_H ) +#define GL_FORMAT_H + +#include +#include "formatsize.h" +#include "vkformat_enum.h" + +#if defined(_WIN32) && !defined(__MINGW32__) +#ifndef NOMINMAX +#define NOMINMAX +#endif +#ifndef __cplusplus +#undef inline +#define inline __inline +#endif // __cplusplus +#endif + +/* +=========================================================================== +Avoid warnings or even errors when using strict C99. "Redefinition of +(type) is a C11 feature." All includers in libktx also include ktx.h where +they are also defined. +=========================================================================== +*/ +#if 0 +typedef unsigned int GLenum; +typedef unsigned char GLboolean; +typedef unsigned int GLuint; +#endif + +#if !defined( GL_INVALID_VALUE ) +#define GL_INVALID_VALUE 0x0501 +#endif + +/* +================================================================================================================================ + +Format to glTexImage2D and glTexImage3D. + +================================================================================================================================ +*/ + +#if !defined( GL_RED ) +#define GL_RED 0x1903 // same as GL_RED_EXT +#endif +#if !defined( GL_GREEN ) +#define GL_GREEN 0x1904 // deprecated +#endif +#if !defined( GL_BLUE ) +#define GL_BLUE 0x1905 // deprecated +#endif +#if !defined( GL_ALPHA ) +#define GL_ALPHA 0x1906 // deprecated +#endif +#if !defined( GL_LUMINANCE ) +#define GL_LUMINANCE 0x1909 // deprecated +#endif +#if !defined( GL_SLUMINANCE ) +#define GL_SLUMINANCE 0x8C46 // deprecated, same as GL_SLUMINANCE_EXT +#endif +#if !defined( GL_LUMINANCE_ALPHA ) +#define GL_LUMINANCE_ALPHA 0x190A // deprecated +#endif +#if !defined( GL_SLUMINANCE_ALPHA ) +#define GL_SLUMINANCE_ALPHA 0x8C44 // deprecated, same as GL_SLUMINANCE_ALPHA_EXT +#endif +#if !defined( GL_INTENSITY ) +#define GL_INTENSITY 0x8049 // deprecated, same as GL_INTENSITY_EXT +#endif +#if !defined( GL_RG ) +#define GL_RG 0x8227 // same as GL_RG_EXT +#endif +#if !defined( GL_RGB ) +#define GL_RGB 0x1907 +#endif +#if !defined( GL_BGR ) +#define GL_BGR 0x80E0 // same as GL_BGR_EXT +#endif +#if !defined( GL_RGBA ) +#define GL_RGBA 0x1908 +#endif +#if !defined( GL_BGRA ) +#define GL_BGRA 0x80E1 // same as GL_BGRA_EXT +#endif +#if !defined( GL_RED_INTEGER ) +#define GL_RED_INTEGER 0x8D94 // same as GL_RED_INTEGER_EXT +#endif +#if !defined( GL_GREEN_INTEGER ) +#define GL_GREEN_INTEGER 0x8D95 // deprecated, same as GL_GREEN_INTEGER_EXT +#endif +#if !defined( GL_BLUE_INTEGER ) +#define GL_BLUE_INTEGER 0x8D96 // deprecated, same as GL_BLUE_INTEGER_EXT +#endif +#if !defined( GL_ALPHA_INTEGER ) +#define GL_ALPHA_INTEGER 0x8D97 // deprecated, same as GL_ALPHA_INTEGER_EXT +#endif +#if !defined( GL_LUMINANCE_INTEGER ) +#define GL_LUMINANCE_INTEGER 0x8D9C // deprecated, same as GL_LUMINANCE_INTEGER_EXT +#endif +#if !defined( GL_LUMINANCE_ALPHA_INTEGER ) +#define GL_LUMINANCE_ALPHA_INTEGER 0x8D9D // deprecated, same as GL_LUMINANCE_ALPHA_INTEGER_EXT +#endif +#if !defined( GL_RG_INTEGER ) +#define GL_RG_INTEGER 0x8228 // same as GL_RG_INTEGER_EXT +#endif +#if !defined( GL_RGB_INTEGER ) +#define GL_RGB_INTEGER 0x8D98 // same as GL_RGB_INTEGER_EXT +#endif +#if !defined( GL_BGR_INTEGER ) +#define GL_BGR_INTEGER 0x8D9A // same as GL_BGR_INTEGER_EXT +#endif +#if !defined( GL_RGBA_INTEGER ) +#define GL_RGBA_INTEGER 0x8D99 // same as GL_RGBA_INTEGER_EXT +#endif +#if !defined( GL_BGRA_INTEGER ) +#define GL_BGRA_INTEGER 0x8D9B // same as GL_BGRA_INTEGER_EXT +#endif +#if !defined( GL_COLOR_INDEX ) +#define GL_COLOR_INDEX 0x1900 // deprecated +#endif +#if !defined( GL_STENCIL_INDEX ) +#define GL_STENCIL_INDEX 0x1901 +#endif +#if !defined( GL_DEPTH_COMPONENT ) +#define GL_DEPTH_COMPONENT 0x1902 +#endif +#if !defined( GL_DEPTH_STENCIL ) +#define GL_DEPTH_STENCIL 0x84F9 // same as GL_DEPTH_STENCIL_NV and GL_DEPTH_STENCIL_EXT and GL_DEPTH_STENCIL_OES +#endif + +/* +================================================================================================================================ + +Type to glTexImage2D, glTexImage3D and glVertexAttribPointer. + +================================================================================================================================ +*/ + +#if !defined( GL_BYTE ) +#define GL_BYTE 0x1400 +#endif +#if !defined( GL_UNSIGNED_BYTE ) +#define GL_UNSIGNED_BYTE 0x1401 +#endif +#if !defined( GL_SHORT ) +#define GL_SHORT 0x1402 +#endif +#if !defined( GL_UNSIGNED_SHORT ) +#define GL_UNSIGNED_SHORT 0x1403 +#endif +#if !defined( GL_INT ) +#define GL_INT 0x1404 +#endif +#if !defined( GL_UNSIGNED_INT ) +#define GL_UNSIGNED_INT 0x1405 +#endif +#if !defined( GL_INT64 ) +#define GL_INT64 0x140E // same as GL_INT64_NV and GL_INT64_ARB +#endif +#if !defined( GL_UNSIGNED_INT64 ) +#define GL_UNSIGNED_INT64 0x140F // same as GL_UNSIGNED_INT64_NV and GL_UNSIGNED_INT64_ARB +#endif +#if !defined( GL_HALF_FLOAT ) +#define GL_HALF_FLOAT 0x140B // same as GL_HALF_FLOAT_NV and GL_HALF_FLOAT_ARB +#endif +#if !defined( GL_HALF_FLOAT_OES ) +#define GL_HALF_FLOAT_OES 0x8D61 // Note that this different from GL_HALF_FLOAT. +#endif +#if !defined( GL_FLOAT ) +#define GL_FLOAT 0x1406 +#endif +#if !defined( GL_DOUBLE ) +#define GL_DOUBLE 0x140A // same as GL_DOUBLE_EXT +#endif +#if !defined( GL_UNSIGNED_BYTE_3_3_2 ) +#define GL_UNSIGNED_BYTE_3_3_2 0x8032 // same as GL_UNSIGNED_BYTE_3_3_2_EXT +#endif +#if !defined( GL_UNSIGNED_BYTE_2_3_3_REV ) +#define GL_UNSIGNED_BYTE_2_3_3_REV 0x8362 // same as GL_UNSIGNED_BYTE_2_3_3_REV_EXT +#endif +#if !defined( GL_UNSIGNED_SHORT_5_6_5 ) +#define GL_UNSIGNED_SHORT_5_6_5 0x8363 // same as GL_UNSIGNED_SHORT_5_6_5_EXT +#endif +#if !defined( GL_UNSIGNED_SHORT_5_6_5_REV ) +#define GL_UNSIGNED_SHORT_5_6_5_REV 0x8364 // same as GL_UNSIGNED_SHORT_5_6_5_REV_EXT +#endif +#if !defined( GL_UNSIGNED_SHORT_4_4_4_4 ) +#define GL_UNSIGNED_SHORT_4_4_4_4 0x8033 // same as GL_UNSIGNED_SHORT_4_4_4_4_EXT +#endif +#if !defined( GL_UNSIGNED_SHORT_4_4_4_4_REV ) +#define GL_UNSIGNED_SHORT_4_4_4_4_REV 0x8365 // same as GL_UNSIGNED_SHORT_4_4_4_4_REV_IMG and GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT +#endif +#if !defined( GL_UNSIGNED_SHORT_5_5_5_1 ) +#define GL_UNSIGNED_SHORT_5_5_5_1 0x8034 // same as GL_UNSIGNED_SHORT_5_5_5_1_EXT +#endif +#if !defined( GL_UNSIGNED_SHORT_1_5_5_5_REV ) +#define GL_UNSIGNED_SHORT_1_5_5_5_REV 0x8366 // same as GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT +#endif +#if !defined( GL_UNSIGNED_INT_8_8_8_8 ) +#define GL_UNSIGNED_INT_8_8_8_8 0x8035 // same as GL_UNSIGNED_INT_8_8_8_8_EXT +#endif +#if !defined( GL_UNSIGNED_INT_8_8_8_8_REV ) +#define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367 // same as GL_UNSIGNED_INT_8_8_8_8_REV_EXT +#endif +#if !defined( GL_UNSIGNED_INT_10_10_10_2 ) +#define GL_UNSIGNED_INT_10_10_10_2 0x8036 // same as GL_UNSIGNED_INT_10_10_10_2_EXT +#endif +#if !defined( GL_UNSIGNED_INT_2_10_10_10_REV ) +#define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368 // same as GL_UNSIGNED_INT_2_10_10_10_REV_EXT +#endif +#if !defined( GL_UNSIGNED_INT_10F_11F_11F_REV ) +#define GL_UNSIGNED_INT_10F_11F_11F_REV 0x8C3B // same as GL_UNSIGNED_INT_10F_11F_11F_REV_EXT +#endif +#if !defined( GL_UNSIGNED_INT_5_9_9_9_REV ) +#define GL_UNSIGNED_INT_5_9_9_9_REV 0x8C3E // same as GL_UNSIGNED_INT_5_9_9_9_REV_EXT +#endif +#if !defined( GL_UNSIGNED_INT_24_8 ) +#define GL_UNSIGNED_INT_24_8 0x84FA // same as GL_UNSIGNED_INT_24_8_NV and GL_UNSIGNED_INT_24_8_EXT and GL_UNSIGNED_INT_24_8_OES +#endif +#if !defined( GL_FLOAT_32_UNSIGNED_INT_24_8_REV ) +#define GL_FLOAT_32_UNSIGNED_INT_24_8_REV 0x8DAD // same as GL_FLOAT_32_UNSIGNED_INT_24_8_REV_NV and GL_FLOAT_32_UNSIGNED_INT_24_8_REV_ARB +#endif + +/* +================================================================================================================================ + +Internal format to glTexImage2D, glTexImage3D, glCompressedTexImage2D, glCompressedTexImage3D, glTexStorage2D, glTexStorage3D + +================================================================================================================================ +*/ + +// +// 8 bits per component +// + +#if !defined( GL_R8 ) +#define GL_R8 0x8229 // same as GL_R8_EXT +#endif +#if !defined( GL_RG8 ) +#define GL_RG8 0x822B // same as GL_RG8_EXT +#endif +#if !defined( GL_RGB8 ) +#define GL_RGB8 0x8051 // same as GL_RGB8_EXT and GL_RGB8_OES +#endif +#if !defined( GL_RGBA8 ) +#define GL_RGBA8 0x8058 // same as GL_RGBA8_EXT and GL_RGBA8_OES +#endif + +#if !defined( GL_R8_SNORM ) +#define GL_R8_SNORM 0x8F94 +#endif +#if !defined( GL_RG8_SNORM ) +#define GL_RG8_SNORM 0x8F95 +#endif +#if !defined( GL_RGB8_SNORM ) +#define GL_RGB8_SNORM 0x8F96 +#endif +#if !defined( GL_RGBA8_SNORM ) +#define GL_RGBA8_SNORM 0x8F97 +#endif + +#if !defined( GL_R8UI ) +#define GL_R8UI 0x8232 +#endif +#if !defined( GL_RG8UI ) +#define GL_RG8UI 0x8238 +#endif +#if !defined( GL_RGB8UI ) +#define GL_RGB8UI 0x8D7D // same as GL_RGB8UI_EXT +#endif +#if !defined( GL_RGBA8UI ) +#define GL_RGBA8UI 0x8D7C // same as GL_RGBA8UI_EXT +#endif + +#if !defined( GL_R8I ) +#define GL_R8I 0x8231 +#endif +#if !defined( GL_RG8I ) +#define GL_RG8I 0x8237 +#endif +#if !defined( GL_RGB8I ) +#define GL_RGB8I 0x8D8F // same as GL_RGB8I_EXT +#endif +#if !defined( GL_RGBA8I ) +#define GL_RGBA8I 0x8D8E // same as GL_RGBA8I_EXT +#endif + +#if !defined( GL_SR8 ) +#define GL_SR8 0x8FBD // same as GL_SR8_EXT +#endif +#if !defined( GL_SRG8 ) +#define GL_SRG8 0x8FBE // same as GL_SRG8_EXT +#endif +#if !defined( GL_SRGB8 ) +#define GL_SRGB8 0x8C41 // same as GL_SRGB8_EXT +#endif +#if !defined( GL_SRGB8_ALPHA8 ) +#define GL_SRGB8_ALPHA8 0x8C43 // same as GL_SRGB8_ALPHA8_EXT +#endif + +// +// 16 bits per component +// + +#if !defined( GL_R16 ) +#define GL_R16 0x822A // same as GL_R16_EXT +#endif +#if !defined( GL_RG16 ) +#define GL_RG16 0x822C // same as GL_RG16_EXT +#endif +#if !defined( GL_RGB16 ) +#define GL_RGB16 0x8054 // same as GL_RGB16_EXT +#endif +#if !defined( GL_RGBA16 ) +#define GL_RGBA16 0x805B // same as GL_RGBA16_EXT +#endif + +#if !defined( GL_R16_SNORM ) +#define GL_R16_SNORM 0x8F98 // same as GL_R16_SNORM_EXT +#endif +#if !defined( GL_RG16_SNORM ) +#define GL_RG16_SNORM 0x8F99 // same as GL_RG16_SNORM_EXT +#endif +#if !defined( GL_RGB16_SNORM ) +#define GL_RGB16_SNORM 0x8F9A // same as GL_RGB16_SNORM_EXT +#endif +#if !defined( GL_RGBA16_SNORM ) +#define GL_RGBA16_SNORM 0x8F9B // same as GL_RGBA16_SNORM_EXT +#endif + +#if !defined( GL_R16UI ) +#define GL_R16UI 0x8234 +#endif +#if !defined( GL_RG16UI ) +#define GL_RG16UI 0x823A +#endif +#if !defined( GL_RGB16UI ) +#define GL_RGB16UI 0x8D77 // same as GL_RGB16UI_EXT +#endif +#if !defined( GL_RGBA16UI ) +#define GL_RGBA16UI 0x8D76 // same as GL_RGBA16UI_EXT +#endif + +#if !defined( GL_R16I ) +#define GL_R16I 0x8233 +#endif +#if !defined( GL_RG16I ) +#define GL_RG16I 0x8239 +#endif +#if !defined( GL_RGB16I ) +#define GL_RGB16I 0x8D89 // same as GL_RGB16I_EXT +#endif +#if !defined( GL_RGBA16I ) +#define GL_RGBA16I 0x8D88 // same as GL_RGBA16I_EXT +#endif + +#if !defined( GL_R16F ) +#define GL_R16F 0x822D // same as GL_R16F_EXT +#endif +#if !defined( GL_RG16F ) +#define GL_RG16F 0x822F // same as GL_RG16F_EXT +#endif +#if !defined( GL_RGB16F ) +#define GL_RGB16F 0x881B // same as GL_RGB16F_EXT and GL_RGB16F_ARB +#endif +#if !defined( GL_RGBA16F ) +#define GL_RGBA16F 0x881A // sama as GL_RGBA16F_EXT and GL_RGBA16F_ARB +#endif + +// +// 32 bits per component +// + +#if !defined( GL_R32UI ) +#define GL_R32UI 0x8236 +#endif +#if !defined( GL_RG32UI ) +#define GL_RG32UI 0x823C +#endif +#if !defined( GL_RGB32UI ) +#define GL_RGB32UI 0x8D71 // same as GL_RGB32UI_EXT +#endif +#if !defined( GL_RGBA32UI ) +#define GL_RGBA32UI 0x8D70 // same as GL_RGBA32UI_EXT +#endif + +#if !defined( GL_R32I ) +#define GL_R32I 0x8235 +#endif +#if !defined( GL_RG32I ) +#define GL_RG32I 0x823B +#endif +#if !defined( GL_RGB32I ) +#define GL_RGB32I 0x8D83 // same as GL_RGB32I_EXT +#endif +#if !defined( GL_RGBA32I ) +#define GL_RGBA32I 0x8D82 // same as GL_RGBA32I_EXT +#endif + +#if !defined( GL_R32F ) +#define GL_R32F 0x822E // same as GL_R32F_EXT +#endif +#if !defined( GL_RG32F ) +#define GL_RG32F 0x8230 // same as GL_RG32F_EXT +#endif +#if !defined( GL_RGB32F ) +#define GL_RGB32F 0x8815 // same as GL_RGB32F_EXT and GL_RGB32F_ARB +#endif +#if !defined( GL_RGBA32F ) +#define GL_RGBA32F 0x8814 // same as GL_RGBA32F_EXT and GL_RGBA32F_ARB +#endif + +// +// Packed +// + +#if !defined( GL_R3_G3_B2 ) +#define GL_R3_G3_B2 0x2A10 +#endif +#if !defined( GL_RGB4 ) +#define GL_RGB4 0x804F // same as GL_RGB4_EXT +#endif +#if !defined( GL_RGB5 ) +#define GL_RGB5 0x8050 // same as GL_RGB5_EXT +#endif +#if !defined( GL_RGB565 ) +#define GL_RGB565 0x8D62 // same as GL_RGB565_EXT and GL_RGB565_OES +#endif +#if !defined( GL_RGB10 ) +#define GL_RGB10 0x8052 // same as GL_RGB10_EXT +#endif +#if !defined( GL_RGB12 ) +#define GL_RGB12 0x8053 // same as GL_RGB12_EXT +#endif +#if !defined( GL_RGBA2 ) +#define GL_RGBA2 0x8055 // same as GL_RGBA2_EXT +#endif +#if !defined( GL_RGBA4 ) +#define GL_RGBA4 0x8056 // same as GL_RGBA4_EXT and GL_RGBA4_OES +#endif +#if !defined( GL_RGBA12 ) +#define GL_RGBA12 0x805A // same as GL_RGBA12_EXT +#endif +#if !defined( GL_RGB5_A1 ) +#define GL_RGB5_A1 0x8057 // same as GL_RGB5_A1_EXT and GL_RGB5_A1_OES +#endif +#if !defined( GL_RGB10_A2 ) +#define GL_RGB10_A2 0x8059 // same as GL_RGB10_A2_EXT +#endif +#if !defined( GL_RGB10_A2UI ) +#define GL_RGB10_A2UI 0x906F +#endif +#if !defined( GL_R11F_G11F_B10F ) +#define GL_R11F_G11F_B10F 0x8C3A // same as GL_R11F_G11F_B10F_APPLE and GL_R11F_G11F_B10F_EXT +#endif +#if !defined( GL_RGB9_E5 ) +#define GL_RGB9_E5 0x8C3D // same as GL_RGB9_E5_APPLE and GL_RGB9_E5_EXT +#endif + +// +// Alpha +// + +#if !defined( GL_ALPHA4 ) +#define GL_ALPHA4 0x803B // deprecated, same as GL_ALPHA4_EXT +#endif +#if !defined( GL_ALPHA8 ) +#define GL_ALPHA8 0x803C // deprecated, same as GL_ALPHA8_EXT +#endif +#if !defined( GL_ALPHA8_SNORM ) +#define GL_ALPHA8_SNORM 0x9014 // deprecated +#endif +#if !defined( GL_ALPHA8UI_EXT ) +#define GL_ALPHA8UI_EXT 0x8D7E // deprecated +#endif +#if !defined( GL_ALPHA8I_EXT ) +#define GL_ALPHA8I_EXT 0x8D90 // deprecated +#endif +#if !defined( GL_ALPHA12 ) +#define GL_ALPHA12 0x803D // deprecated, same as GL_ALPHA12_EXT +#endif +#if !defined( GL_ALPHA16 ) +#define GL_ALPHA16 0x803E // deprecated, same as GL_ALPHA16_EXT +#endif +#if !defined( GL_ALPHA16_SNORM ) +#define GL_ALPHA16_SNORM 0x9018 // deprecated +#endif +#if !defined( GL_ALPHA16UI_EXT ) +#define GL_ALPHA16UI_EXT 0x8D78 // deprecated +#endif +#if !defined( GL_ALPHA16I_EXT ) +#define GL_ALPHA16I_EXT 0x8D8A // deprecated +#endif +#if !defined( GL_ALPHA16F_ARB ) +#define GL_ALPHA16F_ARB 0x881C // deprecated, same as GL_ALPHA_FLOAT16_APPLE and GL_ALPHA_FLOAT16_ATI +#endif +#if !defined( GL_ALPHA32UI_EXT ) +#define GL_ALPHA32UI_EXT 0x8D72 // deprecated +#endif +#if !defined( GL_ALPHA32I_EXT ) +#define GL_ALPHA32I_EXT 0x8D84 // deprecated +#endif +#if !defined( GL_ALPHA32F_ARB ) +#define GL_ALPHA32F_ARB 0x8816 // deprecated, same as GL_ALPHA_FLOAT32_APPLE and GL_ALPHA_FLOAT32_ATI +#endif + +// +// Luminance +// + +#if !defined( GL_LUMINANCE4 ) +#define GL_LUMINANCE4 0x803F // deprecated, same as GL_LUMINANCE4_EXT +#endif +#if !defined( GL_LUMINANCE8 ) +#define GL_LUMINANCE8 0x8040 // deprecated, same as GL_LUMINANCE8_EXT +#endif +#if !defined( GL_LUMINANCE8_SNORM ) +#define GL_LUMINANCE8_SNORM 0x9015 // deprecated +#endif +#if !defined( GL_SLUMINANCE8 ) +#define GL_SLUMINANCE8 0x8C47 // deprecated, same as GL_SLUMINANCE8_EXT +#endif +#if !defined( GL_LUMINANCE8UI_EXT ) +#define GL_LUMINANCE8UI_EXT 0x8D80 // deprecated +#endif +#if !defined( GL_LUMINANCE8I_EXT ) +#define GL_LUMINANCE8I_EXT 0x8D92 // deprecated +#endif +#if !defined( GL_LUMINANCE12 ) +#define GL_LUMINANCE12 0x8041 // deprecated, same as GL_LUMINANCE12_EXT +#endif +#if !defined( GL_LUMINANCE16 ) +#define GL_LUMINANCE16 0x8042 // deprecated, same as GL_LUMINANCE16_EXT +#endif +#if !defined( GL_LUMINANCE16_SNORM ) +#define GL_LUMINANCE16_SNORM 0x9019 // deprecated +#endif +#if !defined( GL_LUMINANCE16UI_EXT ) +#define GL_LUMINANCE16UI_EXT 0x8D7A // deprecated +#endif +#if !defined( GL_LUMINANCE16I_EXT ) +#define GL_LUMINANCE16I_EXT 0x8D8C // deprecated +#endif +#if !defined( GL_LUMINANCE16F_ARB ) +#define GL_LUMINANCE16F_ARB 0x881E // deprecated, same as GL_LUMINANCE_FLOAT16_APPLE and GL_LUMINANCE_FLOAT16_ATI +#endif +#if !defined( GL_LUMINANCE32UI_EXT ) +#define GL_LUMINANCE32UI_EXT 0x8D74 // deprecated +#endif +#if !defined( GL_LUMINANCE32I_EXT ) +#define GL_LUMINANCE32I_EXT 0x8D86 // deprecated +#endif +#if !defined( GL_LUMINANCE32F_ARB ) +#define GL_LUMINANCE32F_ARB 0x8818 // deprecated, same as GL_LUMINANCE_FLOAT32_APPLE and GL_LUMINANCE_FLOAT32_ATI +#endif + +// +// Luminance/Alpha +// + +#if !defined( GL_LUMINANCE4_ALPHA4 ) +#define GL_LUMINANCE4_ALPHA4 0x8043 // deprecated, same as GL_LUMINANCE4_ALPHA4_EXT +#endif +#if !defined( GL_LUMINANCE6_ALPHA2 ) +#define GL_LUMINANCE6_ALPHA2 0x8044 // deprecated, same as GL_LUMINANCE6_ALPHA2_EXT +#endif +#if !defined( GL_LUMINANCE8_ALPHA8 ) +#define GL_LUMINANCE8_ALPHA8 0x8045 // deprecated, same as GL_LUMINANCE8_ALPHA8_EXT +#endif +#if !defined( GL_LUMINANCE8_ALPHA8_SNORM ) +#define GL_LUMINANCE8_ALPHA8_SNORM 0x9016 // deprecated +#endif +#if !defined( GL_SLUMINANCE8_ALPHA8 ) +#define GL_SLUMINANCE8_ALPHA8 0x8C45 // deprecated, same as GL_SLUMINANCE8_ALPHA8_EXT +#endif +#if !defined( GL_LUMINANCE_ALPHA8UI_EXT ) +#define GL_LUMINANCE_ALPHA8UI_EXT 0x8D81 // deprecated +#endif +#if !defined( GL_LUMINANCE_ALPHA8I_EXT ) +#define GL_LUMINANCE_ALPHA8I_EXT 0x8D93 // deprecated +#endif +#if !defined( GL_LUMINANCE12_ALPHA4 ) +#define GL_LUMINANCE12_ALPHA4 0x8046 // deprecated, same as GL_LUMINANCE12_ALPHA4_EXT +#endif +#if !defined( GL_LUMINANCE12_ALPHA12 ) +#define GL_LUMINANCE12_ALPHA12 0x8047 // deprecated, same as GL_LUMINANCE12_ALPHA12_EXT +#endif +#if !defined( GL_LUMINANCE16_ALPHA16 ) +#define GL_LUMINANCE16_ALPHA16 0x8048 // deprecated, same as GL_LUMINANCE16_ALPHA16_EXT +#endif +#if !defined( GL_LUMINANCE16_ALPHA16_SNORM ) +#define GL_LUMINANCE16_ALPHA16_SNORM 0x901A // deprecated +#endif +#if !defined( GL_LUMINANCE_ALPHA16UI_EXT ) +#define GL_LUMINANCE_ALPHA16UI_EXT 0x8D7B // deprecated +#endif +#if !defined( GL_LUMINANCE_ALPHA16I_EXT ) +#define GL_LUMINANCE_ALPHA16I_EXT 0x8D8D // deprecated +#endif +#if !defined( GL_LUMINANCE_ALPHA16F_ARB ) +#define GL_LUMINANCE_ALPHA16F_ARB 0x881F // deprecated, same as GL_LUMINANCE_ALPHA_FLOAT16_APPLE and GL_LUMINANCE_ALPHA_FLOAT16_ATI +#endif +#if !defined( GL_LUMINANCE_ALPHA32UI_EXT ) +#define GL_LUMINANCE_ALPHA32UI_EXT 0x8D75 // deprecated +#endif +#if !defined( GL_LUMINANCE_ALPHA32I_EXT ) +#define GL_LUMINANCE_ALPHA32I_EXT 0x8D87 // deprecated +#endif +#if !defined( GL_LUMINANCE_ALPHA32F_ARB ) +#define GL_LUMINANCE_ALPHA32F_ARB 0x8819 // deprecated, same as GL_LUMINANCE_ALPHA_FLOAT32_APPLE and GL_LUMINANCE_ALPHA_FLOAT32_ATI +#endif + +// +// Intensity +// + +#if !defined( GL_INTENSITY4 ) +#define GL_INTENSITY4 0x804A // deprecated, same as GL_INTENSITY4_EXT +#endif +#if !defined( GL_INTENSITY8 ) +#define GL_INTENSITY8 0x804B // deprecated, same as GL_INTENSITY8_EXT +#endif +#if !defined( GL_INTENSITY8_SNORM ) +#define GL_INTENSITY8_SNORM 0x9017 // deprecated +#endif +#if !defined( GL_INTENSITY8UI_EXT ) +#define GL_INTENSITY8UI_EXT 0x8D7F // deprecated +#endif +#if !defined( GL_INTENSITY8I_EXT ) +#define GL_INTENSITY8I_EXT 0x8D91 // deprecated +#endif +#if !defined( GL_INTENSITY12 ) +#define GL_INTENSITY12 0x804C // deprecated, same as GL_INTENSITY12_EXT +#endif +#if !defined( GL_INTENSITY16 ) +#define GL_INTENSITY16 0x804D // deprecated, same as GL_INTENSITY16_EXT +#endif +#if !defined( GL_INTENSITY16_SNORM ) +#define GL_INTENSITY16_SNORM 0x901B // deprecated +#endif +#if !defined( GL_INTENSITY16UI_EXT ) +#define GL_INTENSITY16UI_EXT 0x8D79 // deprecated +#endif +#if !defined( GL_INTENSITY16I_EXT ) +#define GL_INTENSITY16I_EXT 0x8D8B // deprecated +#endif +#if !defined( GL_INTENSITY16F_ARB ) +#define GL_INTENSITY16F_ARB 0x881D // deprecated, same as GL_INTENSITY_FLOAT16_APPLE and GL_INTENSITY_FLOAT16_ATI +#endif +#if !defined( GL_INTENSITY32UI_EXT ) +#define GL_INTENSITY32UI_EXT 0x8D73 // deprecated +#endif +#if !defined( GL_INTENSITY32I_EXT ) +#define GL_INTENSITY32I_EXT 0x8D85 // deprecated +#endif +#if !defined( GL_INTENSITY32F_ARB ) +#define GL_INTENSITY32F_ARB 0x8817 // deprecated, same as GL_INTENSITY_FLOAT32_APPLE and GL_INTENSITY_FLOAT32_ATI +#endif + +// +// Generic compression +// + +#if !defined( GL_COMPRESSED_RED ) +#define GL_COMPRESSED_RED 0x8225 +#endif +#if !defined( GL_COMPRESSED_ALPHA ) +#define GL_COMPRESSED_ALPHA 0x84E9 // deprecated, same as GL_COMPRESSED_ALPHA_ARB +#endif +#if !defined( GL_COMPRESSED_LUMINANCE ) +#define GL_COMPRESSED_LUMINANCE 0x84EA // deprecated, same as GL_COMPRESSED_LUMINANCE_ARB +#endif +#if !defined( GL_COMPRESSED_SLUMINANCE ) +#define GL_COMPRESSED_SLUMINANCE 0x8C4A // deprecated, same as GL_COMPRESSED_SLUMINANCE_EXT +#endif +#if !defined( GL_COMPRESSED_LUMINANCE_ALPHA ) +#define GL_COMPRESSED_LUMINANCE_ALPHA 0x84EB // deprecated, same as GL_COMPRESSED_LUMINANCE_ALPHA_ARB +#endif +#if !defined( GL_COMPRESSED_SLUMINANCE_ALPHA ) +#define GL_COMPRESSED_SLUMINANCE_ALPHA 0x8C4B // deprecated, same as GL_COMPRESSED_SLUMINANCE_ALPHA_EXT +#endif +#if !defined( GL_COMPRESSED_INTENSITY ) +#define GL_COMPRESSED_INTENSITY 0x84EC // deprecated, same as GL_COMPRESSED_INTENSITY_ARB +#endif +#if !defined( GL_COMPRESSED_RG ) +#define GL_COMPRESSED_RG 0x8226 +#endif +#if !defined( GL_COMPRESSED_RGB ) +#define GL_COMPRESSED_RGB 0x84ED // same as GL_COMPRESSED_RGB_ARB +#endif +#if !defined( GL_COMPRESSED_RGBA ) +#define GL_COMPRESSED_RGBA 0x84EE // same as GL_COMPRESSED_RGBA_ARB +#endif +#if !defined( GL_COMPRESSED_SRGB ) +#define GL_COMPRESSED_SRGB 0x8C48 // same as GL_COMPRESSED_SRGB_EXT +#endif +#if !defined( GL_COMPRESSED_SRGB_ALPHA ) +#define GL_COMPRESSED_SRGB_ALPHA 0x8C49 // same as GL_COMPRESSED_SRGB_ALPHA_EXT +#endif + +// +// FXT1 +// + +#if !defined( GL_COMPRESSED_RGB_FXT1_3DFX ) +#define GL_COMPRESSED_RGB_FXT1_3DFX 0x86B0 // deprecated +#endif +#if !defined( GL_COMPRESSED_RGBA_FXT1_3DFX ) +#define GL_COMPRESSED_RGBA_FXT1_3DFX 0x86B1 // deprecated +#endif + +// +// S3TC/DXT/BC +// + +#if !defined( GL_COMPRESSED_RGB_S3TC_DXT1_EXT ) +#define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0 +#endif +#if !defined( GL_COMPRESSED_RGBA_S3TC_DXT1_EXT ) +#define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1 +#endif +#if !defined( GL_COMPRESSED_RGBA_S3TC_DXT3_EXT ) +#define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2 +#endif +#if !defined( GL_COMPRESSED_RGBA_S3TC_DXT5_EXT ) +#define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3 +#endif + +#if !defined( GL_COMPRESSED_SRGB_S3TC_DXT1_EXT ) +#define GL_COMPRESSED_SRGB_S3TC_DXT1_EXT 0x8C4C +#endif +#if !defined( GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT ) +#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT 0x8C4D +#endif +#if !defined( GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT ) +#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT 0x8C4E +#endif +#if !defined( GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT ) +#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT 0x8C4F +#endif + +#if !defined( GL_COMPRESSED_LUMINANCE_LATC1_EXT ) +#define GL_COMPRESSED_LUMINANCE_LATC1_EXT 0x8C70 +#endif +#if !defined( GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT ) +#define GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT 0x8C72 +#endif +#if !defined( GL_COMPRESSED_SIGNED_LUMINANCE_LATC1_EXT ) +#define GL_COMPRESSED_SIGNED_LUMINANCE_LATC1_EXT 0x8C71 +#endif +#if !defined( GL_COMPRESSED_SIGNED_LUMINANCE_ALPHA_LATC2_EXT ) +#define GL_COMPRESSED_SIGNED_LUMINANCE_ALPHA_LATC2_EXT 0x8C73 +#endif + +#if !defined( GL_COMPRESSED_RED_RGTC1 ) +#define GL_COMPRESSED_RED_RGTC1 0x8DBB // same as GL_COMPRESSED_RED_RGTC1_EXT +#endif +#if !defined( GL_COMPRESSED_RG_RGTC2 ) +#define GL_COMPRESSED_RG_RGTC2 0x8DBD // same as GL_COMPRESSED_RG_RGTC2_EXT +#endif +#if !defined( GL_COMPRESSED_SIGNED_RED_RGTC1 ) +#define GL_COMPRESSED_SIGNED_RED_RGTC1 0x8DBC // same as GL_COMPRESSED_SIGNED_RED_RGTC1_EXT +#endif +#if !defined( GL_COMPRESSED_SIGNED_RG_RGTC2 ) +#define GL_COMPRESSED_SIGNED_RG_RGTC2 0x8DBE // same as GL_COMPRESSED_SIGNED_RG_RGTC2_EXT +#endif + +#if !defined( GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT ) +#define GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT 0x8E8E // same as GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB +#endif +#if !defined( GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT ) +#define GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT 0x8E8F // same as GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB +#endif +#if !defined( GL_COMPRESSED_RGBA_BPTC_UNORM ) +#define GL_COMPRESSED_RGBA_BPTC_UNORM 0x8E8C // same as GL_COMPRESSED_RGBA_BPTC_UNORM_ARB +#endif +#if !defined( GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM ) +#define GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM 0x8E8D // same as GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB +#endif + +// +// ETC +// + +#if !defined( GL_ETC1_RGB8_OES ) +#define GL_ETC1_RGB8_OES 0x8D64 +#endif + +#if !defined( GL_COMPRESSED_RGB8_ETC2 ) +#define GL_COMPRESSED_RGB8_ETC2 0x9274 +#endif +#if !defined( GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 ) +#define GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9276 +#endif +#if !defined( GL_COMPRESSED_RGBA8_ETC2_EAC ) +#define GL_COMPRESSED_RGBA8_ETC2_EAC 0x9278 +#endif + +#if !defined( GL_COMPRESSED_SRGB8_ETC2 ) +#define GL_COMPRESSED_SRGB8_ETC2 0x9275 +#endif +#if !defined( GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 ) +#define GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9277 +#endif +#if !defined( GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC ) +#define GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC 0x9279 +#endif + +#if !defined( GL_COMPRESSED_R11_EAC ) +#define GL_COMPRESSED_R11_EAC 0x9270 +#endif +#if !defined( GL_COMPRESSED_RG11_EAC ) +#define GL_COMPRESSED_RG11_EAC 0x9272 +#endif +#if !defined( GL_COMPRESSED_SIGNED_R11_EAC ) +#define GL_COMPRESSED_SIGNED_R11_EAC 0x9271 +#endif +#if !defined( GL_COMPRESSED_SIGNED_RG11_EAC ) +#define GL_COMPRESSED_SIGNED_RG11_EAC 0x9273 +#endif + +// +// PVRTC +// + +#if !defined( GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG ) +#define GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG 0x8C01 +#define GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG 0x8C00 +#define GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG 0x8C03 +#define GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG 0x8C02 +#endif +#if !defined( GL_COMPRESSED_RGBA_PVRTC_2BPPV2_IMG ) +#define GL_COMPRESSED_RGBA_PVRTC_2BPPV2_IMG 0x9137 +#define GL_COMPRESSED_RGBA_PVRTC_4BPPV2_IMG 0x9138 +#endif +#if !defined( GL_COMPRESSED_SRGB_PVRTC_2BPPV1_EXT ) +#define GL_COMPRESSED_SRGB_PVRTC_2BPPV1_EXT 0x8A54 +#define GL_COMPRESSED_SRGB_PVRTC_4BPPV1_EXT 0x8A55 +#define GL_COMPRESSED_SRGB_ALPHA_PVRTC_2BPPV1_EXT 0x8A56 +#define GL_COMPRESSED_SRGB_ALPHA_PVRTC_4BPPV1_EXT 0x8A57 +#endif +#if !defined( GL_COMPRESSED_SRGB_ALPHA_PVRTC_2BPPV2_IMG ) +#define GL_COMPRESSED_SRGB_ALPHA_PVRTC_2BPPV2_IMG 0x93F0 +#define GL_COMPRESSED_SRGB_ALPHA_PVRTC_4BPPV2_IMG 0x93F1 +#endif + +// +// ASTC +// + +#if !defined( GL_COMPRESSED_RGBA_ASTC_4x4_KHR ) +#define GL_COMPRESSED_RGBA_ASTC_4x4_KHR 0x93B0 +#define GL_COMPRESSED_RGBA_ASTC_5x4_KHR 0x93B1 +#define GL_COMPRESSED_RGBA_ASTC_5x5_KHR 0x93B2 +#define GL_COMPRESSED_RGBA_ASTC_6x5_KHR 0x93B3 +#define GL_COMPRESSED_RGBA_ASTC_6x6_KHR 0x93B4 +#define GL_COMPRESSED_RGBA_ASTC_8x5_KHR 0x93B5 +#define GL_COMPRESSED_RGBA_ASTC_8x6_KHR 0x93B6 +#define GL_COMPRESSED_RGBA_ASTC_8x8_KHR 0x93B7 +#define GL_COMPRESSED_RGBA_ASTC_10x5_KHR 0x93B8 +#define GL_COMPRESSED_RGBA_ASTC_10x6_KHR 0x93B9 +#define GL_COMPRESSED_RGBA_ASTC_10x8_KHR 0x93BA +#define GL_COMPRESSED_RGBA_ASTC_10x10_KHR 0x93BB +#define GL_COMPRESSED_RGBA_ASTC_12x10_KHR 0x93BC +#define GL_COMPRESSED_RGBA_ASTC_12x12_KHR 0x93BD +#endif + +#if !defined( GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR ) +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR 0x93D0 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR 0x93D1 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR 0x93D2 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR 0x93D3 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR 0x93D4 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR 0x93D5 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR 0x93D6 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR 0x93D7 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR 0x93D8 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR 0x93D9 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR 0x93DA +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR 0x93DB +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR 0x93DC +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR 0x93DD +#endif + +#if !defined( GL_COMPRESSED_RGBA_ASTC_3x3x3_OES ) +#define GL_COMPRESSED_RGBA_ASTC_3x3x3_OES 0x93C0 +#define GL_COMPRESSED_RGBA_ASTC_4x3x3_OES 0x93C1 +#define GL_COMPRESSED_RGBA_ASTC_4x4x3_OES 0x93C2 +#define GL_COMPRESSED_RGBA_ASTC_4x4x4_OES 0x93C3 +#define GL_COMPRESSED_RGBA_ASTC_5x4x4_OES 0x93C4 +#define GL_COMPRESSED_RGBA_ASTC_5x5x4_OES 0x93C5 +#define GL_COMPRESSED_RGBA_ASTC_5x5x5_OES 0x93C6 +#define GL_COMPRESSED_RGBA_ASTC_6x5x5_OES 0x93C7 +#define GL_COMPRESSED_RGBA_ASTC_6x6x5_OES 0x93C8 +#define GL_COMPRESSED_RGBA_ASTC_6x6x6_OES 0x93C9 +#endif + +#if !defined( GL_COMPRESSED_SRGB8_ALPHA8_ASTC_3x3x3_OES ) +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_3x3x3_OES 0x93E0 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x3x3_OES 0x93E1 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4x3_OES 0x93E2 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4x4_OES 0x93E3 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4x4_OES 0x93E4 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5x4_OES 0x93E5 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5x5_OES 0x93E6 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5x5_OES 0x93E7 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6x5_OES 0x93E8 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6x6_OES 0x93E9 +#endif + +// +// ATC +// + +#if !defined( GL_ATC_RGB_AMD ) +#define GL_ATC_RGB_AMD 0x8C92 +#define GL_ATC_RGBA_EXPLICIT_ALPHA_AMD 0x8C93 +#define GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD 0x87EE +#endif + +// +// Palletized (combined palette) +// + +#if !defined( GL_PALETTE4_RGB8_OES ) +#define GL_PALETTE4_RGB8_OES 0x8B90 +#define GL_PALETTE4_RGBA8_OES 0x8B91 +#define GL_PALETTE4_R5_G6_B5_OES 0x8B92 +#define GL_PALETTE4_RGBA4_OES 0x8B93 +#define GL_PALETTE4_RGB5_A1_OES 0x8B94 +#define GL_PALETTE8_RGB8_OES 0x8B95 +#define GL_PALETTE8_RGBA8_OES 0x8B96 +#define GL_PALETTE8_R5_G6_B5_OES 0x8B97 +#define GL_PALETTE8_RGBA4_OES 0x8B98 +#define GL_PALETTE8_RGB5_A1_OES 0x8B99 +#endif + +// +// Palletized (separate palette) +// + +#if !defined( GL_COLOR_INDEX1_EXT ) +#define GL_COLOR_INDEX1_EXT 0x80E2 // deprecated +#define GL_COLOR_INDEX2_EXT 0x80E3 // deprecated +#define GL_COLOR_INDEX4_EXT 0x80E4 // deprecated +#define GL_COLOR_INDEX8_EXT 0x80E5 // deprecated +#define GL_COLOR_INDEX12_EXT 0x80E6 // deprecated +#define GL_COLOR_INDEX16_EXT 0x80E7 // deprecated +#endif + +// +// Depth/stencil +// + +#if !defined( GL_DEPTH_COMPONENT16 ) +#define GL_DEPTH_COMPONENT16 0x81A5 // same as GL_DEPTH_COMPONENT16_SGIX and GL_DEPTH_COMPONENT16_ARB +#endif +#if !defined( GL_DEPTH_COMPONENT24 ) +#define GL_DEPTH_COMPONENT24 0x81A6 // same as GL_DEPTH_COMPONENT24_SGIX and GL_DEPTH_COMPONENT24_ARB +#endif +#if !defined( GL_DEPTH_COMPONENT32 ) +#define GL_DEPTH_COMPONENT32 0x81A7 // same as GL_DEPTH_COMPONENT32_SGIX and GL_DEPTH_COMPONENT32_ARB and GL_DEPTH_COMPONENT32_OES +#endif +#if !defined( GL_DEPTH_COMPONENT32F ) +#define GL_DEPTH_COMPONENT32F 0x8CAC // same as GL_DEPTH_COMPONENT32F_ARB +#endif +#if !defined( GL_DEPTH_COMPONENT32F_NV ) +#define GL_DEPTH_COMPONENT32F_NV 0x8DAB // note that this is different from GL_DEPTH_COMPONENT32F +#endif +#if !defined( GL_STENCIL_INDEX1 ) +#define GL_STENCIL_INDEX1 0x8D46 // same as GL_STENCIL_INDEX1_EXT +#endif +#if !defined( GL_STENCIL_INDEX4 ) +#define GL_STENCIL_INDEX4 0x8D47 // same as GL_STENCIL_INDEX4_EXT +#endif +#if !defined( GL_STENCIL_INDEX8 ) +#define GL_STENCIL_INDEX8 0x8D48 // same as GL_STENCIL_INDEX8_EXT +#endif +#if !defined( GL_STENCIL_INDEX16 ) +#define GL_STENCIL_INDEX16 0x8D49 // same as GL_STENCIL_INDEX16_EXT +#endif +#if !defined( GL_DEPTH24_STENCIL8 ) +#define GL_DEPTH24_STENCIL8 0x88F0 // same as GL_DEPTH24_STENCIL8_EXT and GL_DEPTH24_STENCIL8_OES +#endif +#if !defined( GL_DEPTH32F_STENCIL8 ) +#define GL_DEPTH32F_STENCIL8 0x8CAD // same as GL_DEPTH32F_STENCIL8_ARB +#endif +#if !defined( GL_DEPTH32F_STENCIL8_NV ) +#define GL_DEPTH32F_STENCIL8_NV 0x8DAC // note that this is different from GL_DEPTH32F_STENCIL8 +#endif + +static inline GLenum glGetFormatFromInternalFormat( const GLenum internalFormat ) +{ + switch ( internalFormat ) + { + // + // 8 bits per component + // + case GL_R8: return GL_RED; // 1-component, 8-bit unsigned normalized + case GL_RG8: return GL_RG; // 2-component, 8-bit unsigned normalized + case GL_RGB8: return GL_RGB; // 3-component, 8-bit unsigned normalized + case GL_RGBA8: return GL_RGBA; // 4-component, 8-bit unsigned normalized + + case GL_R8_SNORM: return GL_RED; // 1-component, 8-bit signed normalized + case GL_RG8_SNORM: return GL_RG; // 2-component, 8-bit signed normalized + case GL_RGB8_SNORM: return GL_RGB; // 3-component, 8-bit signed normalized + case GL_RGBA8_SNORM: return GL_RGBA; // 4-component, 8-bit signed normalized + + case GL_R8UI: return GL_RED; // 1-component, 8-bit unsigned integer + case GL_RG8UI: return GL_RG; // 2-component, 8-bit unsigned integer + case GL_RGB8UI: return GL_RGB; // 3-component, 8-bit unsigned integer + case GL_RGBA8UI: return GL_RGBA; // 4-component, 8-bit unsigned integer + + case GL_R8I: return GL_RED; // 1-component, 8-bit signed integer + case GL_RG8I: return GL_RG; // 2-component, 8-bit signed integer + case GL_RGB8I: return GL_RGB; // 3-component, 8-bit signed integer + case GL_RGBA8I: return GL_RGBA; // 4-component, 8-bit signed integer + + case GL_SR8: return GL_RED; // 1-component, 8-bit sRGB + case GL_SRG8: return GL_RG; // 2-component, 8-bit sRGB + case GL_SRGB8: return GL_RGB; // 3-component, 8-bit sRGB + case GL_SRGB8_ALPHA8: return GL_RGBA; // 4-component, 8-bit sRGB + + // + // 16 bits per component + // + case GL_R16: return GL_RED; // 1-component, 16-bit unsigned normalized + case GL_RG16: return GL_RG; // 2-component, 16-bit unsigned normalized + case GL_RGB16: return GL_RGB; // 3-component, 16-bit unsigned normalized + case GL_RGBA16: return GL_RGBA; // 4-component, 16-bit unsigned normalized + + case GL_R16_SNORM: return GL_RED; // 1-component, 16-bit signed normalized + case GL_RG16_SNORM: return GL_RG; // 2-component, 16-bit signed normalized + case GL_RGB16_SNORM: return GL_RGB; // 3-component, 16-bit signed normalized + case GL_RGBA16_SNORM: return GL_RGBA; // 4-component, 16-bit signed normalized + + case GL_R16UI: return GL_RED; // 1-component, 16-bit unsigned integer + case GL_RG16UI: return GL_RG; // 2-component, 16-bit unsigned integer + case GL_RGB16UI: return GL_RGB; // 3-component, 16-bit unsigned integer + case GL_RGBA16UI: return GL_RGBA; // 4-component, 16-bit unsigned integer + + case GL_R16I: return GL_RED; // 1-component, 16-bit signed integer + case GL_RG16I: return GL_RG; // 2-component, 16-bit signed integer + case GL_RGB16I: return GL_RGB; // 3-component, 16-bit signed integer + case GL_RGBA16I: return GL_RGBA; // 4-component, 16-bit signed integer + + case GL_R16F: return GL_RED; // 1-component, 16-bit floating-point + case GL_RG16F: return GL_RG; // 2-component, 16-bit floating-point + case GL_RGB16F: return GL_RGB; // 3-component, 16-bit floating-point + case GL_RGBA16F: return GL_RGBA; // 4-component, 16-bit floating-point + + // + // 32 bits per component + // + case GL_R32UI: return GL_RED; // 1-component, 32-bit unsigned integer + case GL_RG32UI: return GL_RG; // 2-component, 32-bit unsigned integer + case GL_RGB32UI: return GL_RGB; // 3-component, 32-bit unsigned integer + case GL_RGBA32UI: return GL_RGBA; // 4-component, 32-bit unsigned integer + + case GL_R32I: return GL_RED; // 1-component, 32-bit signed integer + case GL_RG32I: return GL_RG; // 2-component, 32-bit signed integer + case GL_RGB32I: return GL_RGB; // 3-component, 32-bit signed integer + case GL_RGBA32I: return GL_RGBA; // 4-component, 32-bit signed integer + + case GL_R32F: return GL_RED; // 1-component, 32-bit floating-point + case GL_RG32F: return GL_RG; // 2-component, 32-bit floating-point + case GL_RGB32F: return GL_RGB; // 3-component, 32-bit floating-point + case GL_RGBA32F: return GL_RGBA; // 4-component, 32-bit floating-point + + // + // Packed + // + case GL_R3_G3_B2: return GL_RGB; // 3-component 3:3:2, unsigned normalized + case GL_RGB4: return GL_RGB; // 3-component 4:4:4, unsigned normalized + case GL_RGB5: return GL_RGB; // 3-component 5:5:5, unsigned normalized + case GL_RGB565: return GL_RGB; // 3-component 5:6:5, unsigned normalized + case GL_RGB10: return GL_RGB; // 3-component 10:10:10, unsigned normalized + case GL_RGB12: return GL_RGB; // 3-component 12:12:12, unsigned normalized + case GL_RGBA2: return GL_RGBA; // 4-component 2:2:2:2, unsigned normalized + case GL_RGBA4: return GL_RGBA; // 4-component 4:4:4:4, unsigned normalized + case GL_RGBA12: return GL_RGBA; // 4-component 12:12:12:12, unsigned normalized + case GL_RGB5_A1: return GL_RGBA; // 4-component 5:5:5:1, unsigned normalized + case GL_RGB10_A2: return GL_RGBA; // 4-component 10:10:10:2, unsigned normalized + case GL_RGB10_A2UI: return GL_RGBA; // 4-component 10:10:10:2, unsigned integer + case GL_R11F_G11F_B10F: return GL_RGB; // 3-component 11:11:10, floating-point + case GL_RGB9_E5: return GL_RGB; // 3-component/exp 9:9:9/5, floating-point + + // + // S3TC/DXT/BC + // + + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: return GL_RGB; // line through 3D space, 4x4 blocks, unsigned normalized + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: return GL_RGBA; // line through 3D space plus 1-bit alpha, 4x4 blocks, unsigned normalized + case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: return GL_RGBA; // line through 3D space plus line through 1D space, 4x4 blocks, unsigned normalized + case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: return GL_RGBA; // line through 3D space plus 4-bit alpha, 4x4 blocks, unsigned normalized + + case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT: return GL_RGB; // line through 3D space, 4x4 blocks, sRGB + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT: return GL_RGBA; // line through 3D space plus 1-bit alpha, 4x4 blocks, sRGB + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT: return GL_RGBA; // line through 3D space plus line through 1D space, 4x4 blocks, sRGB + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: return GL_RGBA; // line through 3D space plus 4-bit alpha, 4x4 blocks, sRGB + + case GL_COMPRESSED_LUMINANCE_LATC1_EXT: return GL_RED; // line through 1D space, 4x4 blocks, unsigned normalized + case GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT: return GL_RG; // two lines through 1D space, 4x4 blocks, unsigned normalized + case GL_COMPRESSED_SIGNED_LUMINANCE_LATC1_EXT: return GL_RED; // line through 1D space, 4x4 blocks, signed normalized + case GL_COMPRESSED_SIGNED_LUMINANCE_ALPHA_LATC2_EXT: return GL_RG; // two lines through 1D space, 4x4 blocks, signed normalized + + case GL_COMPRESSED_RED_RGTC1: return GL_RED; // line through 1D space, 4x4 blocks, unsigned normalized + case GL_COMPRESSED_RG_RGTC2: return GL_RG; // two lines through 1D space, 4x4 blocks, unsigned normalized + case GL_COMPRESSED_SIGNED_RED_RGTC1: return GL_RED; // line through 1D space, 4x4 blocks, signed normalized + case GL_COMPRESSED_SIGNED_RG_RGTC2: return GL_RG; // two lines through 1D space, 4x4 blocks, signed normalized + + case GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT: return GL_RGB; // 3-component, 4x4 blocks, unsigned floating-point + case GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT: return GL_RGB; // 3-component, 4x4 blocks, signed floating-point + case GL_COMPRESSED_RGBA_BPTC_UNORM: return GL_RGBA; // 4-component, 4x4 blocks, unsigned normalized + case GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM: return GL_RGBA; // 4-component, 4x4 blocks, sRGB + + // + // ETC + // + case GL_ETC1_RGB8_OES: return GL_RGB; // 3-component ETC1, 4x4 blocks, unsigned normalized + + case GL_COMPRESSED_RGB8_ETC2: return GL_RGB; // 3-component ETC2, 4x4 blocks, unsigned normalized + case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2: return GL_RGBA; // 4-component ETC2 with 1-bit alpha, 4x4 blocks, unsigned normalized + case GL_COMPRESSED_RGBA8_ETC2_EAC: return GL_RGBA; // 4-component ETC2, 4x4 blocks, unsigned normalized + + case GL_COMPRESSED_SRGB8_ETC2: return GL_RGB; // 3-component ETC2, 4x4 blocks, sRGB + case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2: return GL_RGBA; // 4-component ETC2 with 1-bit alpha, 4x4 blocks, sRGB + case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC: return GL_RGBA; // 4-component ETC2, 4x4 blocks, sRGB + + case GL_COMPRESSED_R11_EAC: return GL_RED; // 1-component ETC, 4x4 blocks, unsigned normalized + case GL_COMPRESSED_RG11_EAC: return GL_RG; // 2-component ETC, 4x4 blocks, unsigned normalized + case GL_COMPRESSED_SIGNED_R11_EAC: return GL_RED; // 1-component ETC, 4x4 blocks, signed normalized + case GL_COMPRESSED_SIGNED_RG11_EAC: return GL_RG; // 2-component ETC, 4x4 blocks, signed normalized + + // + // PVRTC + // + case GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG: return GL_RGB; // 3-component PVRTC, 16x8 blocks, unsigned normalized + case GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG: return GL_RGB; // 3-component PVRTC, 8x8 blocks, unsigned normalized + case GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG: return GL_RGBA; // 4-component PVRTC, 16x8 blocks, unsigned normalized + case GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG: return GL_RGBA; // 4-component PVRTC, 8x8 blocks, unsigned normalized + case GL_COMPRESSED_RGBA_PVRTC_2BPPV2_IMG: return GL_RGBA; // 4-component PVRTC, 8x4 blocks, unsigned normalized + case GL_COMPRESSED_RGBA_PVRTC_4BPPV2_IMG: return GL_RGBA; // 4-component PVRTC, 4x4 blocks, unsigned normalized + + case GL_COMPRESSED_SRGB_PVRTC_2BPPV1_EXT: return GL_RGB; // 3-component PVRTC, 16x8 blocks, sRGB + case GL_COMPRESSED_SRGB_PVRTC_4BPPV1_EXT: return GL_RGB; // 3-component PVRTC, 8x8 blocks, sRGB + case GL_COMPRESSED_SRGB_ALPHA_PVRTC_2BPPV1_EXT: return GL_RGBA; // 4-component PVRTC, 16x8 blocks, sRGB + case GL_COMPRESSED_SRGB_ALPHA_PVRTC_4BPPV1_EXT: return GL_RGBA; // 4-component PVRTC, 8x8 blocks, sRGB + case GL_COMPRESSED_SRGB_ALPHA_PVRTC_2BPPV2_IMG: return GL_RGBA; // 4-component PVRTC, 8x4 blocks, sRGB + case GL_COMPRESSED_SRGB_ALPHA_PVRTC_4BPPV2_IMG: return GL_RGBA; // 4-component PVRTC, 4x4 blocks, sRGB + + // + // ASTC + // + case GL_COMPRESSED_RGBA_ASTC_4x4_KHR: return GL_RGBA; // 4-component ASTC, 4x4 blocks, unsigned normalized + case GL_COMPRESSED_RGBA_ASTC_5x4_KHR: return GL_RGBA; // 4-component ASTC, 5x4 blocks, unsigned normalized + case GL_COMPRESSED_RGBA_ASTC_5x5_KHR: return GL_RGBA; // 4-component ASTC, 5x5 blocks, unsigned normalized + case GL_COMPRESSED_RGBA_ASTC_6x5_KHR: return GL_RGBA; // 4-component ASTC, 6x5 blocks, unsigned normalized + case GL_COMPRESSED_RGBA_ASTC_6x6_KHR: return GL_RGBA; // 4-component ASTC, 6x6 blocks, unsigned normalized + case GL_COMPRESSED_RGBA_ASTC_8x5_KHR: return GL_RGBA; // 4-component ASTC, 8x5 blocks, unsigned normalized + case GL_COMPRESSED_RGBA_ASTC_8x6_KHR: return GL_RGBA; // 4-component ASTC, 8x6 blocks, unsigned normalized + case GL_COMPRESSED_RGBA_ASTC_8x8_KHR: return GL_RGBA; // 4-component ASTC, 8x8 blocks, unsigned normalized + case GL_COMPRESSED_RGBA_ASTC_10x5_KHR: return GL_RGBA; // 4-component ASTC, 10x5 blocks, unsigned normalized + case GL_COMPRESSED_RGBA_ASTC_10x6_KHR: return GL_RGBA; // 4-component ASTC, 10x6 blocks, unsigned normalized + case GL_COMPRESSED_RGBA_ASTC_10x8_KHR: return GL_RGBA; // 4-component ASTC, 10x8 blocks, unsigned normalized + case GL_COMPRESSED_RGBA_ASTC_10x10_KHR: return GL_RGBA; // 4-component ASTC, 10x10 blocks, unsigned normalized + case GL_COMPRESSED_RGBA_ASTC_12x10_KHR: return GL_RGBA; // 4-component ASTC, 12x10 blocks, unsigned normalized + case GL_COMPRESSED_RGBA_ASTC_12x12_KHR: return GL_RGBA; // 4-component ASTC, 12x12 blocks, unsigned normalized + + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR: return GL_RGBA; // 4-component ASTC, 4x4 blocks, sRGB + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR: return GL_RGBA; // 4-component ASTC, 5x4 blocks, sRGB + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR: return GL_RGBA; // 4-component ASTC, 5x5 blocks, sRGB + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR: return GL_RGBA; // 4-component ASTC, 6x5 blocks, sRGB + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR: return GL_RGBA; // 4-component ASTC, 6x6 blocks, sRGB + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR: return GL_RGBA; // 4-component ASTC, 8x5 blocks, sRGB + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR: return GL_RGBA; // 4-component ASTC, 8x6 blocks, sRGB + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR: return GL_RGBA; // 4-component ASTC, 8x8 blocks, sRGB + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR: return GL_RGBA; // 4-component ASTC, 10x5 blocks, sRGB + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR: return GL_RGBA; // 4-component ASTC, 10x6 blocks, sRGB + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR: return GL_RGBA; // 4-component ASTC, 10x8 blocks, sRGB + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR: return GL_RGBA; // 4-component ASTC, 10x10 blocks, sRGB + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR: return GL_RGBA; // 4-component ASTC, 12x10 blocks, sRGB + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR: return GL_RGBA; // 4-component ASTC, 12x12 blocks, sRGB + + case GL_COMPRESSED_RGBA_ASTC_3x3x3_OES: return GL_RGBA; // 4-component ASTC, 3x3x3 blocks, unsigned normalized + case GL_COMPRESSED_RGBA_ASTC_4x3x3_OES: return GL_RGBA; // 4-component ASTC, 4x3x3 blocks, unsigned normalized + case GL_COMPRESSED_RGBA_ASTC_4x4x3_OES: return GL_RGBA; // 4-component ASTC, 4x4x3 blocks, unsigned normalized + case GL_COMPRESSED_RGBA_ASTC_4x4x4_OES: return GL_RGBA; // 4-component ASTC, 4x4x4 blocks, unsigned normalized + case GL_COMPRESSED_RGBA_ASTC_5x4x4_OES: return GL_RGBA; // 4-component ASTC, 5x4x4 blocks, unsigned normalized + case GL_COMPRESSED_RGBA_ASTC_5x5x4_OES: return GL_RGBA; // 4-component ASTC, 5x5x4 blocks, unsigned normalized + case GL_COMPRESSED_RGBA_ASTC_5x5x5_OES: return GL_RGBA; // 4-component ASTC, 5x5x5 blocks, unsigned normalized + case GL_COMPRESSED_RGBA_ASTC_6x5x5_OES: return GL_RGBA; // 4-component ASTC, 6x5x5 blocks, unsigned normalized + case GL_COMPRESSED_RGBA_ASTC_6x6x5_OES: return GL_RGBA; // 4-component ASTC, 6x6x5 blocks, unsigned normalized + case GL_COMPRESSED_RGBA_ASTC_6x6x6_OES: return GL_RGBA; // 4-component ASTC, 6x6x6 blocks, unsigned normalized + + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_3x3x3_OES: return GL_RGBA; // 4-component ASTC, 3x3x3 blocks, sRGB + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x3x3_OES: return GL_RGBA; // 4-component ASTC, 4x3x3 blocks, sRGB + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4x3_OES: return GL_RGBA; // 4-component ASTC, 4x4x3 blocks, sRGB + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4x4_OES: return GL_RGBA; // 4-component ASTC, 4x4x4 blocks, sRGB + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4x4_OES: return GL_RGBA; // 4-component ASTC, 5x4x4 blocks, sRGB + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5x4_OES: return GL_RGBA; // 4-component ASTC, 5x5x4 blocks, sRGB + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5x5_OES: return GL_RGBA; // 4-component ASTC, 5x5x5 blocks, sRGB + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5x5_OES: return GL_RGBA; // 4-component ASTC, 6x5x5 blocks, sRGB + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6x5_OES: return GL_RGBA; // 4-component ASTC, 6x6x5 blocks, sRGB + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6x6_OES: return GL_RGBA; // 4-component ASTC, 6x6x6 blocks, sRGB + + // + // ATC + // + case GL_ATC_RGB_AMD: return GL_RGB; // 3-component, 4x4 blocks, unsigned normalized + case GL_ATC_RGBA_EXPLICIT_ALPHA_AMD: return GL_RGBA; // 4-component, 4x4 blocks, unsigned normalized + case GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD: return GL_RGBA; // 4-component, 4x4 blocks, unsigned normalized + + // + // Palletized + // + case GL_PALETTE4_RGB8_OES: return GL_RGB; // 3-component 8:8:8, 4-bit palette, unsigned normalized + case GL_PALETTE4_RGBA8_OES: return GL_RGBA; // 4-component 8:8:8:8, 4-bit palette, unsigned normalized + case GL_PALETTE4_R5_G6_B5_OES: return GL_RGB; // 3-component 5:6:5, 4-bit palette, unsigned normalized + case GL_PALETTE4_RGBA4_OES: return GL_RGBA; // 4-component 4:4:4:4, 4-bit palette, unsigned normalized + case GL_PALETTE4_RGB5_A1_OES: return GL_RGBA; // 4-component 5:5:5:1, 4-bit palette, unsigned normalized + case GL_PALETTE8_RGB8_OES: return GL_RGB; // 3-component 8:8:8, 8-bit palette, unsigned normalized + case GL_PALETTE8_RGBA8_OES: return GL_RGBA; // 4-component 8:8:8:8, 8-bit palette, unsigned normalized + case GL_PALETTE8_R5_G6_B5_OES: return GL_RGB; // 3-component 5:6:5, 8-bit palette, unsigned normalized + case GL_PALETTE8_RGBA4_OES: return GL_RGBA; // 4-component 4:4:4:4, 8-bit palette, unsigned normalized + case GL_PALETTE8_RGB5_A1_OES: return GL_RGBA; // 4-component 5:5:5:1, 8-bit palette, unsigned normalized + + // + // Depth/stencil + // + case GL_DEPTH_COMPONENT16: return GL_DEPTH_COMPONENT; + case GL_DEPTH_COMPONENT24: return GL_DEPTH_COMPONENT; + case GL_DEPTH_COMPONENT32: return GL_DEPTH_COMPONENT; + case GL_DEPTH_COMPONENT32F: return GL_DEPTH_COMPONENT; + case GL_DEPTH_COMPONENT32F_NV: return GL_DEPTH_COMPONENT; + case GL_STENCIL_INDEX1: return GL_STENCIL_INDEX; + case GL_STENCIL_INDEX4: return GL_STENCIL_INDEX; + case GL_STENCIL_INDEX8: return GL_STENCIL_INDEX; + case GL_STENCIL_INDEX16: return GL_STENCIL_INDEX; + case GL_DEPTH24_STENCIL8: return GL_DEPTH_STENCIL; + case GL_DEPTH32F_STENCIL8: return GL_DEPTH_STENCIL; + case GL_DEPTH32F_STENCIL8_NV: return GL_DEPTH_STENCIL; + + default: return GL_INVALID_VALUE; + } +} + +static inline GLenum glGetTypeFromInternalFormat( const GLenum internalFormat ) +{ + switch ( internalFormat ) + { + // + // 8 bits per component + // + case GL_R8: return GL_UNSIGNED_BYTE; // 1-component, 8-bit unsigned normalized + case GL_RG8: return GL_UNSIGNED_BYTE; // 2-component, 8-bit unsigned normalized + case GL_RGB8: return GL_UNSIGNED_BYTE; // 3-component, 8-bit unsigned normalized + case GL_RGBA8: return GL_UNSIGNED_BYTE; // 4-component, 8-bit unsigned normalized + + case GL_R8_SNORM: return GL_BYTE; // 1-component, 8-bit signed normalized + case GL_RG8_SNORM: return GL_BYTE; // 2-component, 8-bit signed normalized + case GL_RGB8_SNORM: return GL_BYTE; // 3-component, 8-bit signed normalized + case GL_RGBA8_SNORM: return GL_BYTE; // 4-component, 8-bit signed normalized + + case GL_R8UI: return GL_UNSIGNED_BYTE; // 1-component, 8-bit unsigned integer + case GL_RG8UI: return GL_UNSIGNED_BYTE; // 2-component, 8-bit unsigned integer + case GL_RGB8UI: return GL_UNSIGNED_BYTE; // 3-component, 8-bit unsigned integer + case GL_RGBA8UI: return GL_UNSIGNED_BYTE; // 4-component, 8-bit unsigned integer + + case GL_R8I: return GL_BYTE; // 1-component, 8-bit signed integer + case GL_RG8I: return GL_BYTE; // 2-component, 8-bit signed integer + case GL_RGB8I: return GL_BYTE; // 3-component, 8-bit signed integer + case GL_RGBA8I: return GL_BYTE; // 4-component, 8-bit signed integer + + case GL_SR8: return GL_UNSIGNED_BYTE; // 1-component, 8-bit sRGB + case GL_SRG8: return GL_UNSIGNED_BYTE; // 2-component, 8-bit sRGB + case GL_SRGB8: return GL_UNSIGNED_BYTE; // 3-component, 8-bit sRGB + case GL_SRGB8_ALPHA8: return GL_UNSIGNED_BYTE; // 4-component, 8-bit sRGB + + // + // 16 bits per component + // + case GL_R16: return GL_UNSIGNED_SHORT; // 1-component, 16-bit unsigned normalized + case GL_RG16: return GL_UNSIGNED_SHORT; // 2-component, 16-bit unsigned normalized + case GL_RGB16: return GL_UNSIGNED_SHORT; // 3-component, 16-bit unsigned normalized + case GL_RGBA16: return GL_UNSIGNED_SHORT; // 4-component, 16-bit unsigned normalized + + case GL_R16_SNORM: return GL_SHORT; // 1-component, 16-bit signed normalized + case GL_RG16_SNORM: return GL_SHORT; // 2-component, 16-bit signed normalized + case GL_RGB16_SNORM: return GL_SHORT; // 3-component, 16-bit signed normalized + case GL_RGBA16_SNORM: return GL_SHORT; // 4-component, 16-bit signed normalized + + case GL_R16UI: return GL_UNSIGNED_SHORT; // 1-component, 16-bit unsigned integer + case GL_RG16UI: return GL_UNSIGNED_SHORT; // 2-component, 16-bit unsigned integer + case GL_RGB16UI: return GL_UNSIGNED_SHORT; // 3-component, 16-bit unsigned integer + case GL_RGBA16UI: return GL_UNSIGNED_SHORT; // 4-component, 16-bit unsigned integer + + case GL_R16I: return GL_SHORT; // 1-component, 16-bit signed integer + case GL_RG16I: return GL_SHORT; // 2-component, 16-bit signed integer + case GL_RGB16I: return GL_SHORT; // 3-component, 16-bit signed integer + case GL_RGBA16I: return GL_SHORT; // 4-component, 16-bit signed integer + + case GL_R16F: return GL_HALF_FLOAT; // 1-component, 16-bit floating-point + case GL_RG16F: return GL_HALF_FLOAT; // 2-component, 16-bit floating-point + case GL_RGB16F: return GL_HALF_FLOAT; // 3-component, 16-bit floating-point + case GL_RGBA16F: return GL_HALF_FLOAT; // 4-component, 16-bit floating-point + + // + // 32 bits per component + // + case GL_R32UI: return GL_UNSIGNED_INT; // 1-component, 32-bit unsigned integer + case GL_RG32UI: return GL_UNSIGNED_INT; // 2-component, 32-bit unsigned integer + case GL_RGB32UI: return GL_UNSIGNED_INT; // 3-component, 32-bit unsigned integer + case GL_RGBA32UI: return GL_UNSIGNED_INT; // 4-component, 32-bit unsigned integer + + case GL_R32I: return GL_INT; // 1-component, 32-bit signed integer + case GL_RG32I: return GL_INT; // 2-component, 32-bit signed integer + case GL_RGB32I: return GL_INT; // 3-component, 32-bit signed integer + case GL_RGBA32I: return GL_INT; // 4-component, 32-bit signed integer + + case GL_R32F: return GL_FLOAT; // 1-component, 32-bit floating-point + case GL_RG32F: return GL_FLOAT; // 2-component, 32-bit floating-point + case GL_RGB32F: return GL_FLOAT; // 3-component, 32-bit floating-point + case GL_RGBA32F: return GL_FLOAT; // 4-component, 32-bit floating-point + + // + // Packed + // + case GL_R3_G3_B2: return GL_UNSIGNED_BYTE_2_3_3_REV; // 3-component 3:3:2, unsigned normalized + case GL_RGB4: return GL_UNSIGNED_SHORT_4_4_4_4; // 3-component 4:4:4, unsigned normalized + case GL_RGB5: return GL_UNSIGNED_SHORT_5_5_5_1; // 3-component 5:5:5, unsigned normalized + case GL_RGB565: return GL_UNSIGNED_SHORT_5_6_5; // 3-component 5:6:5, unsigned normalized + case GL_RGB10: return GL_UNSIGNED_INT_10_10_10_2; // 3-component 10:10:10, unsigned normalized + case GL_RGB12: return GL_UNSIGNED_SHORT; // 3-component 12:12:12, unsigned normalized + case GL_RGBA2: return GL_UNSIGNED_BYTE; // 4-component 2:2:2:2, unsigned normalized + case GL_RGBA4: return GL_UNSIGNED_SHORT_4_4_4_4; // 4-component 4:4:4:4, unsigned normalized + case GL_RGBA12: return GL_UNSIGNED_SHORT; // 4-component 12:12:12:12, unsigned normalized + case GL_RGB5_A1: return GL_UNSIGNED_SHORT_5_5_5_1; // 4-component 5:5:5:1, unsigned normalized + case GL_RGB10_A2: return GL_UNSIGNED_INT_2_10_10_10_REV; // 4-component 10:10:10:2, unsigned normalized + case GL_RGB10_A2UI: return GL_UNSIGNED_INT_2_10_10_10_REV; // 4-component 10:10:10:2, unsigned integer + case GL_R11F_G11F_B10F: return GL_UNSIGNED_INT_10F_11F_11F_REV; // 3-component 11:11:10, floating-point + case GL_RGB9_E5: return GL_UNSIGNED_INT_5_9_9_9_REV; // 3-component/exp 9:9:9/5, floating-point + + // + // S3TC/DXT/BC + // + + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: return GL_UNSIGNED_BYTE; // line through 3D space, 4x4 blocks, unsigned normalized + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: return GL_UNSIGNED_BYTE; // line through 3D space plus 1-bit alpha, 4x4 blocks, unsigned normalized + case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: return GL_UNSIGNED_BYTE; // line through 3D space plus line through 1D space, 4x4 blocks, unsigned normalized + case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: return GL_UNSIGNED_BYTE; // line through 3D space plus 4-bit alpha, 4x4 blocks, unsigned normalized + + case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT: return GL_UNSIGNED_BYTE; // line through 3D space, 4x4 blocks, sRGB + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT: return GL_UNSIGNED_BYTE; // line through 3D space plus 1-bit alpha, 4x4 blocks, sRGB + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT: return GL_UNSIGNED_BYTE; // line through 3D space plus line through 1D space, 4x4 blocks, sRGB + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: return GL_UNSIGNED_BYTE; // line through 3D space plus 4-bit alpha, 4x4 blocks, sRGB + + case GL_COMPRESSED_LUMINANCE_LATC1_EXT: return GL_UNSIGNED_BYTE; // line through 1D space, 4x4 blocks, unsigned normalized + case GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT: return GL_UNSIGNED_BYTE; // two lines through 1D space, 4x4 blocks, unsigned normalized + case GL_COMPRESSED_SIGNED_LUMINANCE_LATC1_EXT: return GL_UNSIGNED_BYTE; // line through 1D space, 4x4 blocks, signed normalized + case GL_COMPRESSED_SIGNED_LUMINANCE_ALPHA_LATC2_EXT: return GL_UNSIGNED_BYTE; // two lines through 1D space, 4x4 blocks, signed normalized + + case GL_COMPRESSED_RED_RGTC1: return GL_UNSIGNED_BYTE; // line through 1D space, 4x4 blocks, unsigned normalized + case GL_COMPRESSED_RG_RGTC2: return GL_UNSIGNED_BYTE; // two lines through 1D space, 4x4 blocks, unsigned normalized + case GL_COMPRESSED_SIGNED_RED_RGTC1: return GL_UNSIGNED_BYTE; // line through 1D space, 4x4 blocks, signed normalized + case GL_COMPRESSED_SIGNED_RG_RGTC2: return GL_UNSIGNED_BYTE; // two lines through 1D space, 4x4 blocks, signed normalized + + case GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT: return GL_FLOAT; // 3-component, 4x4 blocks, unsigned floating-point + case GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT: return GL_FLOAT; // 3-component, 4x4 blocks, signed floating-point + case GL_COMPRESSED_RGBA_BPTC_UNORM: return GL_UNSIGNED_BYTE; // 4-component, 4x4 blocks, unsigned normalized + case GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM: return GL_UNSIGNED_BYTE; // 4-component, 4x4 blocks, sRGB + + // + // ETC + // + case GL_ETC1_RGB8_OES: return GL_UNSIGNED_BYTE; // 3-component ETC1, 4x4 blocks, unsigned normalized" ), + + case GL_COMPRESSED_RGB8_ETC2: return GL_UNSIGNED_BYTE; // 3-component ETC2, 4x4 blocks, unsigned normalized + case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2: return GL_UNSIGNED_BYTE; // 4-component ETC2 with 1-bit alpha, 4x4 blocks, unsigned normalized + case GL_COMPRESSED_RGBA8_ETC2_EAC: return GL_UNSIGNED_BYTE; // 4-component ETC2, 4x4 blocks, unsigned normalized + + case GL_COMPRESSED_SRGB8_ETC2: return GL_UNSIGNED_BYTE; // 3-component ETC2, 4x4 blocks, sRGB + case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2: return GL_UNSIGNED_BYTE; // 4-component ETC2 with 1-bit alpha, 4x4 blocks, sRGB + case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC: return GL_UNSIGNED_BYTE; // 4-component ETC2, 4x4 blocks, sRGB + + case GL_COMPRESSED_R11_EAC: return GL_UNSIGNED_BYTE; // 1-component ETC, 4x4 blocks, unsigned normalized + case GL_COMPRESSED_RG11_EAC: return GL_UNSIGNED_BYTE; // 2-component ETC, 4x4 blocks, unsigned normalized + case GL_COMPRESSED_SIGNED_R11_EAC: return GL_UNSIGNED_BYTE; // 1-component ETC, 4x4 blocks, signed normalized + case GL_COMPRESSED_SIGNED_RG11_EAC: return GL_UNSIGNED_BYTE; // 2-component ETC, 4x4 blocks, signed normalized + + // + // PVRTC + // + case GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG: return GL_UNSIGNED_BYTE; // 3-component PVRTC, 16x8 blocks, unsigned normalized + case GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG: return GL_UNSIGNED_BYTE; // 3-component PVRTC, 8x8 blocks, unsigned normalized + case GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG: return GL_UNSIGNED_BYTE; // 4-component PVRTC, 16x8 blocks, unsigned normalized + case GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG: return GL_UNSIGNED_BYTE; // 4-component PVRTC, 8x8 blocks, unsigned normalized + case GL_COMPRESSED_RGBA_PVRTC_2BPPV2_IMG: return GL_UNSIGNED_BYTE; // 4-component PVRTC, 8x4 blocks, unsigned normalized + case GL_COMPRESSED_RGBA_PVRTC_4BPPV2_IMG: return GL_UNSIGNED_BYTE; // 4-component PVRTC, 4x4 blocks, unsigned normalized + + case GL_COMPRESSED_SRGB_PVRTC_2BPPV1_EXT: return GL_UNSIGNED_BYTE; // 3-component PVRTC, 16x8 blocks, sRGB + case GL_COMPRESSED_SRGB_PVRTC_4BPPV1_EXT: return GL_UNSIGNED_BYTE; // 3-component PVRTC, 8x8 blocks, sRGB + case GL_COMPRESSED_SRGB_ALPHA_PVRTC_2BPPV1_EXT: return GL_UNSIGNED_BYTE; // 4-component PVRTC, 16x8 blocks, sRGB + case GL_COMPRESSED_SRGB_ALPHA_PVRTC_4BPPV1_EXT: return GL_UNSIGNED_BYTE; // 4-component PVRTC, 8x8 blocks, sRGB + case GL_COMPRESSED_SRGB_ALPHA_PVRTC_2BPPV2_IMG: return GL_UNSIGNED_BYTE; // 4-component PVRTC, 8x4 blocks, sRGB + case GL_COMPRESSED_SRGB_ALPHA_PVRTC_4BPPV2_IMG: return GL_UNSIGNED_BYTE; // 4-component PVRTC, 4x4 blocks, sRGB + + // + // ASTC + // + case GL_COMPRESSED_RGBA_ASTC_4x4_KHR: return GL_UNSIGNED_BYTE; // 4-component ASTC, 4x4 blocks, unsigned normalized + case GL_COMPRESSED_RGBA_ASTC_5x4_KHR: return GL_UNSIGNED_BYTE; // 4-component ASTC, 5x4 blocks, unsigned normalized + case GL_COMPRESSED_RGBA_ASTC_5x5_KHR: return GL_UNSIGNED_BYTE; // 4-component ASTC, 5x5 blocks, unsigned normalized + case GL_COMPRESSED_RGBA_ASTC_6x5_KHR: return GL_UNSIGNED_BYTE; // 4-component ASTC, 6x5 blocks, unsigned normalized + case GL_COMPRESSED_RGBA_ASTC_6x6_KHR: return GL_UNSIGNED_BYTE; // 4-component ASTC, 6x6 blocks, unsigned normalized + case GL_COMPRESSED_RGBA_ASTC_8x5_KHR: return GL_UNSIGNED_BYTE; // 4-component ASTC, 8x5 blocks, unsigned normalized + case GL_COMPRESSED_RGBA_ASTC_8x6_KHR: return GL_UNSIGNED_BYTE; // 4-component ASTC, 8x6 blocks, unsigned normalized + case GL_COMPRESSED_RGBA_ASTC_8x8_KHR: return GL_UNSIGNED_BYTE; // 4-component ASTC, 8x8 blocks, unsigned normalized + case GL_COMPRESSED_RGBA_ASTC_10x5_KHR: return GL_UNSIGNED_BYTE; // 4-component ASTC, 10x5 blocks, unsigned normalized + case GL_COMPRESSED_RGBA_ASTC_10x6_KHR: return GL_UNSIGNED_BYTE; // 4-component ASTC, 10x6 blocks, unsigned normalized + case GL_COMPRESSED_RGBA_ASTC_10x8_KHR: return GL_UNSIGNED_BYTE; // 4-component ASTC, 10x8 blocks, unsigned normalized + case GL_COMPRESSED_RGBA_ASTC_10x10_KHR: return GL_UNSIGNED_BYTE; // 4-component ASTC, 10x10 blocks, unsigned normalized + case GL_COMPRESSED_RGBA_ASTC_12x10_KHR: return GL_UNSIGNED_BYTE; // 4-component ASTC, 12x10 blocks, unsigned normalized + case GL_COMPRESSED_RGBA_ASTC_12x12_KHR: return GL_UNSIGNED_BYTE; // 4-component ASTC, 12x12 blocks, unsigned normalized + + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR: return GL_UNSIGNED_BYTE; // 4-component ASTC, 4x4 blocks, sRGB + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR: return GL_UNSIGNED_BYTE; // 4-component ASTC, 5x4 blocks, sRGB + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR: return GL_UNSIGNED_BYTE; // 4-component ASTC, 5x5 blocks, sRGB + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR: return GL_UNSIGNED_BYTE; // 4-component ASTC, 6x5 blocks, sRGB + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR: return GL_UNSIGNED_BYTE; // 4-component ASTC, 6x6 blocks, sRGB + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR: return GL_UNSIGNED_BYTE; // 4-component ASTC, 8x5 blocks, sRGB + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR: return GL_UNSIGNED_BYTE; // 4-component ASTC, 8x6 blocks, sRGB + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR: return GL_UNSIGNED_BYTE; // 4-component ASTC, 8x8 blocks, sRGB + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR: return GL_UNSIGNED_BYTE; // 4-component ASTC, 10x5 blocks, sRGB + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR: return GL_UNSIGNED_BYTE; // 4-component ASTC, 10x6 blocks, sRGB + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR: return GL_UNSIGNED_BYTE; // 4-component ASTC, 10x8 blocks, sRGB + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR: return GL_UNSIGNED_BYTE; // 4-component ASTC, 10x10 blocks, sRGB + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR: return GL_UNSIGNED_BYTE; // 4-component ASTC, 12x10 blocks, sRGB + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR: return GL_UNSIGNED_BYTE; // 4-component ASTC, 12x12 blocks, sRGB + + case GL_COMPRESSED_RGBA_ASTC_3x3x3_OES: return GL_UNSIGNED_BYTE; // 4-component ASTC, 3x3x3 blocks, unsigned normalized + case GL_COMPRESSED_RGBA_ASTC_4x3x3_OES: return GL_UNSIGNED_BYTE; // 4-component ASTC, 4x3x3 blocks, unsigned normalized + case GL_COMPRESSED_RGBA_ASTC_4x4x3_OES: return GL_UNSIGNED_BYTE; // 4-component ASTC, 4x4x3 blocks, unsigned normalized + case GL_COMPRESSED_RGBA_ASTC_4x4x4_OES: return GL_UNSIGNED_BYTE; // 4-component ASTC, 4x4x4 blocks, unsigned normalized + case GL_COMPRESSED_RGBA_ASTC_5x4x4_OES: return GL_UNSIGNED_BYTE; // 4-component ASTC, 5x4x4 blocks, unsigned normalized + case GL_COMPRESSED_RGBA_ASTC_5x5x4_OES: return GL_UNSIGNED_BYTE; // 4-component ASTC, 5x5x4 blocks, unsigned normalized + case GL_COMPRESSED_RGBA_ASTC_5x5x5_OES: return GL_UNSIGNED_BYTE; // 4-component ASTC, 5x5x5 blocks, unsigned normalized + case GL_COMPRESSED_RGBA_ASTC_6x5x5_OES: return GL_UNSIGNED_BYTE; // 4-component ASTC, 6x5x5 blocks, unsigned normalized + case GL_COMPRESSED_RGBA_ASTC_6x6x5_OES: return GL_UNSIGNED_BYTE; // 4-component ASTC, 6x6x5 blocks, unsigned normalized + case GL_COMPRESSED_RGBA_ASTC_6x6x6_OES: return GL_UNSIGNED_BYTE; // 4-component ASTC, 6x6x6 blocks, unsigned normalized + + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_3x3x3_OES: return GL_UNSIGNED_BYTE; // 4-component ASTC, 3x3x3 blocks, sRGB + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x3x3_OES: return GL_UNSIGNED_BYTE; // 4-component ASTC, 4x3x3 blocks, sRGB + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4x3_OES: return GL_UNSIGNED_BYTE; // 4-component ASTC, 4x4x3 blocks, sRGB + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4x4_OES: return GL_UNSIGNED_BYTE; // 4-component ASTC, 4x4x4 blocks, sRGB + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4x4_OES: return GL_UNSIGNED_BYTE; // 4-component ASTC, 5x4x4 blocks, sRGB + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5x4_OES: return GL_UNSIGNED_BYTE; // 4-component ASTC, 5x5x4 blocks, sRGB + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5x5_OES: return GL_UNSIGNED_BYTE; // 4-component ASTC, 5x5x5 blocks, sRGB + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5x5_OES: return GL_UNSIGNED_BYTE; // 4-component ASTC, 6x5x5 blocks, sRGB + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6x5_OES: return GL_UNSIGNED_BYTE; // 4-component ASTC, 6x6x5 blocks, sRGB + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6x6_OES: return GL_UNSIGNED_BYTE; // 4-component ASTC, 6x6x6 blocks, sRGB + + // + // ATC + // + case GL_ATC_RGB_AMD: return GL_UNSIGNED_BYTE; // 3-component, 4x4 blocks, unsigned normalized + case GL_ATC_RGBA_EXPLICIT_ALPHA_AMD: return GL_UNSIGNED_BYTE; // 4-component, 4x4 blocks, unsigned normalized + case GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD: return GL_UNSIGNED_BYTE; // 4-component, 4x4 blocks, unsigned normalized + + // + // Palletized + // + case GL_PALETTE4_RGB8_OES: return GL_UNSIGNED_BYTE; // 3-component 8:8:8, 4-bit palette, unsigned normalized + case GL_PALETTE4_RGBA8_OES: return GL_UNSIGNED_BYTE; // 4-component 8:8:8:8, 4-bit palette, unsigned normalized + case GL_PALETTE4_R5_G6_B5_OES: return GL_UNSIGNED_SHORT_5_6_5; // 3-component 5:6:5, 4-bit palette, unsigned normalized + case GL_PALETTE4_RGBA4_OES: return GL_UNSIGNED_SHORT_4_4_4_4; // 4-component 4:4:4:4, 4-bit palette, unsigned normalized + case GL_PALETTE4_RGB5_A1_OES: return GL_UNSIGNED_SHORT_5_5_5_1; // 4-component 5:5:5:1, 4-bit palette, unsigned normalized + case GL_PALETTE8_RGB8_OES: return GL_UNSIGNED_BYTE; // 3-component 8:8:8, 8-bit palette, unsigned normalized + case GL_PALETTE8_RGBA8_OES: return GL_UNSIGNED_BYTE; // 4-component 8:8:8:8, 8-bit palette, unsigned normalized + case GL_PALETTE8_R5_G6_B5_OES: return GL_UNSIGNED_SHORT_5_6_5; // 3-component 5:6:5, 8-bit palette, unsigned normalized + case GL_PALETTE8_RGBA4_OES: return GL_UNSIGNED_SHORT_4_4_4_4; // 4-component 4:4:4:4, 8-bit palette, unsigned normalized + case GL_PALETTE8_RGB5_A1_OES: return GL_UNSIGNED_SHORT_5_5_5_1; // 4-component 5:5:5:1, 8-bit palette, unsigned normalized + + // + // Depth/stencil + // + case GL_DEPTH_COMPONENT16: return GL_UNSIGNED_SHORT; + case GL_DEPTH_COMPONENT24: return GL_UNSIGNED_INT_24_8; + case GL_DEPTH_COMPONENT32: return GL_UNSIGNED_INT; + case GL_DEPTH_COMPONENT32F: return GL_FLOAT; + case GL_DEPTH_COMPONENT32F_NV: return GL_FLOAT; + case GL_STENCIL_INDEX1: return GL_UNSIGNED_BYTE; + case GL_STENCIL_INDEX4: return GL_UNSIGNED_BYTE; + case GL_STENCIL_INDEX8: return GL_UNSIGNED_BYTE; + case GL_STENCIL_INDEX16: return GL_UNSIGNED_SHORT; + case GL_DEPTH24_STENCIL8: return GL_UNSIGNED_INT_24_8; + case GL_DEPTH32F_STENCIL8: return GL_FLOAT_32_UNSIGNED_INT_24_8_REV; + case GL_DEPTH32F_STENCIL8_NV: return GL_FLOAT_32_UNSIGNED_INT_24_8_REV; + + default: return GL_INVALID_VALUE; + } +} + +static inline unsigned int glGetTypeSizeFromType(GLenum type) +{ + switch (type) { + case GL_BYTE: + case GL_UNSIGNED_BYTE: + case GL_UNSIGNED_BYTE_3_3_2: + case GL_UNSIGNED_BYTE_2_3_3_REV: + return 1; + + case GL_SHORT: + case GL_UNSIGNED_SHORT: + case GL_UNSIGNED_SHORT_5_6_5: + case GL_UNSIGNED_SHORT_4_4_4_4: + case GL_UNSIGNED_SHORT_5_5_5_1: + case GL_UNSIGNED_SHORT_5_6_5_REV: + case GL_UNSIGNED_SHORT_4_4_4_4_REV: + case GL_UNSIGNED_SHORT_1_5_5_5_REV: + case GL_HALF_FLOAT: + return 2; + + case GL_INT: + case GL_UNSIGNED_INT: + case GL_UNSIGNED_INT_8_8_8_8: + case GL_UNSIGNED_INT_8_8_8_8_REV: + case GL_UNSIGNED_INT_10_10_10_2: + case GL_UNSIGNED_INT_2_10_10_10_REV: + case GL_UNSIGNED_INT_24_8: + case GL_UNSIGNED_INT_10F_11F_11F_REV: + case GL_UNSIGNED_INT_5_9_9_9_REV: + case GL_FLOAT: + case GL_FLOAT_32_UNSIGNED_INT_24_8_REV: + return 4; + + default: + return GL_INVALID_VALUE; + } +} + +static inline void glGetFormatSize( const GLenum internalFormat, ktxFormatSize * pFormatSize ) +{ + pFormatSize->minBlocksX = pFormatSize->minBlocksY = 1; + switch ( internalFormat ) + { + // + // 8 bits per component + // + case GL_R8: // 1-component, 8-bit unsigned normalized + case GL_R8_SNORM: // 1-component, 8-bit signed normalized + case GL_R8UI: // 1-component, 8-bit unsigned integer + case GL_R8I: // 1-component, 8-bit signed integer + case GL_SR8: // 1-component, 8-bit sRGB + pFormatSize->flags = 0; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 1 * 8; + pFormatSize->blockWidth = 1; + pFormatSize->blockHeight = 1; + pFormatSize->blockDepth = 1; + break; + case GL_RG8: // 2-component, 8-bit unsigned normalized + case GL_RG8_SNORM: // 2-component, 8-bit signed normalized + case GL_RG8UI: // 2-component, 8-bit unsigned integer + case GL_RG8I: // 2-component, 8-bit signed integer + case GL_SRG8: // 2-component, 8-bit sRGB + pFormatSize->flags = 0; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 2 * 8; + pFormatSize->blockWidth = 1; + pFormatSize->blockHeight = 1; + pFormatSize->blockDepth = 1; + break; + case GL_RGB8: // 3-component, 8-bit unsigned normalized + case GL_RGB8_SNORM: // 3-component, 8-bit signed normalized + case GL_RGB8UI: // 3-component, 8-bit unsigned integer + case GL_RGB8I: // 3-component, 8-bit signed integer + case GL_SRGB8: // 3-component, 8-bit sRGB + pFormatSize->flags = 0; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 3 * 8; + pFormatSize->blockWidth = 1; + pFormatSize->blockHeight = 1; + pFormatSize->blockDepth = 1; + break; + case GL_RGBA8: // 4-component, 8-bit unsigned normalized + case GL_RGBA8_SNORM: // 4-component, 8-bit signed normalized + case GL_RGBA8UI: // 4-component, 8-bit unsigned integer + case GL_RGBA8I: // 4-component, 8-bit signed integer + case GL_SRGB8_ALPHA8: // 4-component, 8-bit sRGB + pFormatSize->flags = 0; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 4 * 8; + pFormatSize->blockWidth = 1; + pFormatSize->blockHeight = 1; + pFormatSize->blockDepth = 1; + break; + + // + // 16 bits per component + // + case GL_R16: // 1-component, 16-bit unsigned normalized + case GL_R16_SNORM: // 1-component, 16-bit signed normalized + case GL_R16UI: // 1-component, 16-bit unsigned integer + case GL_R16I: // 1-component, 16-bit signed integer + case GL_R16F: // 1-component, 16-bit floating-point + pFormatSize->flags = 0; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 2 * 8; + pFormatSize->blockWidth = 1; + pFormatSize->blockHeight = 1; + pFormatSize->blockDepth = 1; + break; + case GL_RG16: // 2-component, 16-bit unsigned normalized + case GL_RG16_SNORM: // 2-component, 16-bit signed normalized + case GL_RG16UI: // 2-component, 16-bit unsigned integer + case GL_RG16I: // 2-component, 16-bit signed integer + case GL_RG16F: // 2-component, 16-bit floating-point + pFormatSize->flags = 0; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 4 * 8; + pFormatSize->blockWidth = 1; + pFormatSize->blockHeight = 1; + pFormatSize->blockDepth = 1; + break; + case GL_RGB16: // 3-component, 16-bit unsigned normalized + case GL_RGB16_SNORM: // 3-component, 16-bit signed normalized + case GL_RGB16UI: // 3-component, 16-bit unsigned integer + case GL_RGB16I: // 3-component, 16-bit signed integer + case GL_RGB16F: // 3-component, 16-bit floating-point + pFormatSize->flags = 0; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 6 * 8; + pFormatSize->blockWidth = 1; + pFormatSize->blockHeight = 1; + pFormatSize->blockDepth = 1; + break; + case GL_RGBA16: // 4-component, 16-bit unsigned normalized + case GL_RGBA16_SNORM: // 4-component, 16-bit signed normalized + case GL_RGBA16UI: // 4-component, 16-bit unsigned integer + case GL_RGBA16I: // 4-component, 16-bit signed integer + case GL_RGBA16F: // 4-component, 16-bit floating-point + pFormatSize->flags = 0; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 8 * 8; + pFormatSize->blockWidth = 1; + pFormatSize->blockHeight = 1; + pFormatSize->blockDepth = 1; + break; + + // + // 32 bits per component + // + case GL_R32UI: // 1-component, 32-bit unsigned integer + case GL_R32I: // 1-component, 32-bit signed integer + case GL_R32F: // 1-component, 32-bit floating-point + pFormatSize->flags = 0; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 4 * 8; + pFormatSize->blockWidth = 1; + pFormatSize->blockHeight = 1; + pFormatSize->blockDepth = 1; + break; + case GL_RG32UI: // 2-component, 32-bit unsigned integer + case GL_RG32I: // 2-component, 32-bit signed integer + case GL_RG32F: // 2-component, 32-bit floating-point + pFormatSize->flags = 0; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 8 * 8; + pFormatSize->blockWidth = 1; + pFormatSize->blockHeight = 1; + pFormatSize->blockDepth = 1; + break; + case GL_RGB32UI: // 3-component, 32-bit unsigned integer + case GL_RGB32I: // 3-component, 32-bit signed integer + case GL_RGB32F: // 3-component, 32-bit floating-point + pFormatSize->flags = 0; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 12 * 8; + pFormatSize->blockWidth = 1; + pFormatSize->blockHeight = 1; + pFormatSize->blockDepth = 1; + break; + case GL_RGBA32UI: // 4-component, 32-bit unsigned integer + case GL_RGBA32I: // 4-component, 32-bit signed integer + case GL_RGBA32F: // 4-component, 32-bit floating-point + pFormatSize->flags = 0; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 16 * 8; + pFormatSize->blockWidth = 1; + pFormatSize->blockHeight = 1; + pFormatSize->blockDepth = 1; + break; + + // + // Packed + // + case GL_R3_G3_B2: // 3-component 3:3:2, unsigned normalized + pFormatSize->flags = KTX_FORMAT_SIZE_PACKED_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 8; + pFormatSize->blockWidth = 1; + pFormatSize->blockHeight = 1; + pFormatSize->blockDepth = 1; + break; + case GL_RGB4: // 3-component 4:4:4, unsigned normalized + pFormatSize->flags = KTX_FORMAT_SIZE_PACKED_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 12; + pFormatSize->blockWidth = 1; + pFormatSize->blockHeight = 1; + pFormatSize->blockDepth = 1; + break; + case GL_RGB5: // 3-component 5:5:5, unsigned normalized + pFormatSize->flags = KTX_FORMAT_SIZE_PACKED_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 16; + pFormatSize->blockWidth = 1; + pFormatSize->blockHeight = 1; + pFormatSize->blockDepth = 1; + break; + case GL_RGB565: // 3-component 5:6:5, unsigned normalized + pFormatSize->flags = KTX_FORMAT_SIZE_PACKED_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 16; + pFormatSize->blockWidth = 1; + pFormatSize->blockHeight = 1; + pFormatSize->blockDepth = 1; + break; + case GL_RGB10: // 3-component 10:10:10, unsigned normalized + pFormatSize->flags = KTX_FORMAT_SIZE_PACKED_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 32; + pFormatSize->blockWidth = 1; + pFormatSize->blockHeight = 1; + pFormatSize->blockDepth = 1; + break; + case GL_RGB12: // 3-component 12:12:12, unsigned normalized + pFormatSize->flags = KTX_FORMAT_SIZE_PACKED_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 36; + pFormatSize->blockWidth = 1; + pFormatSize->blockHeight = 1; + pFormatSize->blockDepth = 1; + break; + case GL_RGBA2: // 4-component 2:2:2:2, unsigned normalized + pFormatSize->flags = KTX_FORMAT_SIZE_PACKED_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 8; + pFormatSize->blockWidth = 1; + pFormatSize->blockHeight = 1; + pFormatSize->blockDepth = 1; + break; + case GL_RGBA4: // 4-component 4:4:4:4, unsigned normalized + pFormatSize->flags = KTX_FORMAT_SIZE_PACKED_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 16; + pFormatSize->blockWidth = 1; + pFormatSize->blockHeight = 1; + pFormatSize->blockDepth = 1; + break; + case GL_RGBA12: // 4-component 12:12:12:12, unsigned normalized + pFormatSize->flags = KTX_FORMAT_SIZE_PACKED_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 48; + pFormatSize->blockWidth = 1; + pFormatSize->blockHeight = 1; + pFormatSize->blockDepth = 1; + break; + case GL_RGB5_A1: // 4-component 5:5:5:1, unsigned normalized + pFormatSize->flags = KTX_FORMAT_SIZE_PACKED_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 32; + pFormatSize->blockWidth = 1; + pFormatSize->blockHeight = 1; + pFormatSize->blockDepth = 1; + break; + case GL_RGB10_A2: // 4-component 10:10:10:2, unsigned normalized + pFormatSize->flags = KTX_FORMAT_SIZE_PACKED_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 32; + pFormatSize->blockWidth = 1; + pFormatSize->blockHeight = 1; + pFormatSize->blockDepth = 1; + break; + case GL_RGB10_A2UI: // 4-component 10:10:10:2, unsigned integer + pFormatSize->flags = KTX_FORMAT_SIZE_PACKED_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 32; + pFormatSize->blockWidth = 1; + pFormatSize->blockHeight = 1; + pFormatSize->blockDepth = 1; + break; + case GL_R11F_G11F_B10F: // 3-component 11:11:10, floating-point + case GL_RGB9_E5: // 3-component/exp 9:9:9/5, floating-point + pFormatSize->flags = KTX_FORMAT_SIZE_PACKED_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 32; + pFormatSize->blockWidth = 1; + pFormatSize->blockHeight = 1; + pFormatSize->blockDepth = 1; + break; + + // + // S3TC/DXT/BC + // + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: // line through 3D space, 4x4 blocks, unsigned normalized + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: // line through 3D space plus 1-bit alpha, 4x4 blocks, unsigned normalized + case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT: // line through 3D space, 4x4 blocks, sRGB + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT: // line through 3D space plus 1-bit alpha, 4x4 blocks, sRGB + pFormatSize->flags = KTX_FORMAT_SIZE_COMPRESSED_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 64; + pFormatSize->blockWidth = 4; + pFormatSize->blockHeight = 4; + pFormatSize->blockDepth = 1; + break; + case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: // line through 3D space plus line through 1D space, 4x4 blocks, unsigned normalized + case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: // line through 3D space plus 4-bit alpha, 4x4 blocks, unsigned normalized + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT: // line through 3D space plus line through 1D space, 4x4 blocks, sRGB + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: // line through 3D space plus 4-bit alpha, 4x4 blocks, sRGB + pFormatSize->flags = KTX_FORMAT_SIZE_COMPRESSED_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 128; + pFormatSize->blockWidth = 4; + pFormatSize->blockHeight = 4; + pFormatSize->blockDepth = 1; + break; + + case GL_COMPRESSED_LUMINANCE_LATC1_EXT: // line through 1D space, 4x4 blocks, unsigned normalized + case GL_COMPRESSED_SIGNED_LUMINANCE_LATC1_EXT: // line through 1D space, 4x4 blocks, signed normalized + pFormatSize->flags = KTX_FORMAT_SIZE_COMPRESSED_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 64; + pFormatSize->blockWidth = 4; + pFormatSize->blockHeight = 4; + pFormatSize->blockDepth = 1; + break; + case GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT: // two lines through 1D space, 4x4 blocks, unsigned normalized + case GL_COMPRESSED_SIGNED_LUMINANCE_ALPHA_LATC2_EXT: // two lines through 1D space, 4x4 blocks, signed normalized + pFormatSize->flags = KTX_FORMAT_SIZE_COMPRESSED_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 128; + pFormatSize->blockWidth = 4; + pFormatSize->blockHeight = 4; + pFormatSize->blockDepth = 1; + break; + + case GL_COMPRESSED_RED_RGTC1: // line through 1D space, 4x4 blocks, unsigned normalized + case GL_COMPRESSED_SIGNED_RED_RGTC1: // line through 1D space, 4x4 blocks, signed normalized + pFormatSize->flags = KTX_FORMAT_SIZE_COMPRESSED_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 64; + pFormatSize->blockWidth = 4; + pFormatSize->blockHeight = 4; + pFormatSize->blockDepth = 1; + break; + case GL_COMPRESSED_RG_RGTC2: // two lines through 1D space, 4x4 blocks, unsigned normalized + case GL_COMPRESSED_SIGNED_RG_RGTC2: // two lines through 1D space, 4x4 blocks, signed normalized + pFormatSize->flags = KTX_FORMAT_SIZE_COMPRESSED_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 128; + pFormatSize->blockWidth = 4; + pFormatSize->blockHeight = 4; + pFormatSize->blockDepth = 1; + break; + + case GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT: // 3-component, 4x4 blocks, unsigned floating-point + case GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT: // 3-component, 4x4 blocks, signed floating-point + case GL_COMPRESSED_RGBA_BPTC_UNORM: // 4-component, 4x4 blocks, unsigned normalized + case GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM: // 4-component, 4x4 blocks, sRGB + pFormatSize->flags = KTX_FORMAT_SIZE_COMPRESSED_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 128; + pFormatSize->blockWidth = 4; + pFormatSize->blockHeight = 4; + pFormatSize->blockDepth = 1; + break; + + // + // ETC + // + case GL_ETC1_RGB8_OES: // 3-component ETC1, 4x4 blocks, unsigned normalized" ), + case GL_COMPRESSED_RGB8_ETC2: // 3-component ETC2, 4x4 blocks, unsigned normalized + case GL_COMPRESSED_SRGB8_ETC2: // 3-component ETC2, 4x4 blocks, sRGB + case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2: // 4-component ETC2 with 1-bit alpha, 4x4 blocks, unsigned normalized + case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2: // 4-component ETC2 with 1-bit alpha, 4x4 blocks, sRGB + pFormatSize->flags = KTX_FORMAT_SIZE_COMPRESSED_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 64; + pFormatSize->blockWidth = 4; + pFormatSize->blockHeight = 4; + pFormatSize->blockDepth = 1; + break; + case GL_COMPRESSED_RGBA8_ETC2_EAC: // 4-component ETC2, 4x4 blocks, unsigned normalized + case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC: // 4-component ETC2, 4x4 blocks, sRGB + pFormatSize->flags = KTX_FORMAT_SIZE_COMPRESSED_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 128; + pFormatSize->blockWidth = 4; + pFormatSize->blockHeight = 4; + pFormatSize->blockDepth = 1; + break; + + case GL_COMPRESSED_R11_EAC: // 1-component ETC, 4x4 blocks, unsigned normalized + case GL_COMPRESSED_SIGNED_R11_EAC: // 1-component ETC, 4x4 blocks, signed normalized + pFormatSize->flags = KTX_FORMAT_SIZE_COMPRESSED_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 64; + pFormatSize->blockWidth = 4; + pFormatSize->blockHeight = 4; + pFormatSize->blockDepth = 1; + break; + case GL_COMPRESSED_RG11_EAC: // 2-component ETC, 4x4 blocks, unsigned normalized + case GL_COMPRESSED_SIGNED_RG11_EAC: // 2-component ETC, 4x4 blocks, signed normalized + pFormatSize->flags = KTX_FORMAT_SIZE_COMPRESSED_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 128; + pFormatSize->blockWidth = 4; + pFormatSize->blockHeight = 4; + pFormatSize->blockDepth = 1; + break; + + // + // PVRTC + // + case GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG: // 3-component PVRTC, 8x4 blocks, unsigned normalized + case GL_COMPRESSED_SRGB_PVRTC_2BPPV1_EXT: // 3-component PVRTC, 8x4 blocks, sRGB + case GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG: // 4-component PVRTC, 8x4 blocks, unsigned normalized + case GL_COMPRESSED_SRGB_ALPHA_PVRTC_2BPPV1_EXT: // 4-component PVRTC, 8x4 blocks, sRGB + pFormatSize->flags = KTX_FORMAT_SIZE_COMPRESSED_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 64; + pFormatSize->blockWidth = 8; + pFormatSize->blockHeight = 4; + pFormatSize->blockDepth = 1; + pFormatSize->minBlocksX = 2; + pFormatSize->minBlocksY = 2; + break; + case GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG: // 3-component PVRTC, 4x4 blocks, unsigned normalized + case GL_COMPRESSED_SRGB_PVRTC_4BPPV1_EXT: // 3-component PVRTC, 4x4 blocks, sRGB + case GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG: // 4-component PVRTC, 4x4 blocks, unsigned normalized + case GL_COMPRESSED_SRGB_ALPHA_PVRTC_4BPPV1_EXT: // 4-component PVRTC, 4x4 blocks, sRGB + pFormatSize->flags = KTX_FORMAT_SIZE_COMPRESSED_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 64; + pFormatSize->blockWidth = 4; + pFormatSize->blockHeight = 4; + pFormatSize->blockDepth = 1; + pFormatSize->minBlocksX = 2; + pFormatSize->minBlocksY = 2; + break; + case GL_COMPRESSED_RGBA_PVRTC_2BPPV2_IMG: // 4-component PVRTC, 8x4 blocks, unsigned normalized + case GL_COMPRESSED_SRGB_ALPHA_PVRTC_2BPPV2_IMG: // 4-component PVRTC, 8x4 blocks, sRGB + pFormatSize->flags = KTX_FORMAT_SIZE_COMPRESSED_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 64; + pFormatSize->blockWidth = 8; + pFormatSize->blockHeight = 4; + pFormatSize->blockDepth = 1; + break; + case GL_COMPRESSED_RGBA_PVRTC_4BPPV2_IMG: // 4-component PVRTC, 4x4 blocks, unsigned normalized + case GL_COMPRESSED_SRGB_ALPHA_PVRTC_4BPPV2_IMG: // 4-component PVRTC, 4x4 blocks, sRGB + pFormatSize->flags = KTX_FORMAT_SIZE_COMPRESSED_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 64; + pFormatSize->blockWidth = 4; + pFormatSize->blockHeight = 4; + pFormatSize->blockDepth = 1; + break; + + // + // ASTC + // + case GL_COMPRESSED_RGBA_ASTC_4x4_KHR: // 4-component ASTC, 4x4 blocks, unsigned normalized + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR: // 4-component ASTC, 4x4 blocks, sRGB + pFormatSize->flags = KTX_FORMAT_SIZE_COMPRESSED_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 128; + pFormatSize->blockWidth = 4; + pFormatSize->blockHeight = 4; + pFormatSize->blockDepth = 1; + break; + case GL_COMPRESSED_RGBA_ASTC_5x4_KHR: // 4-component ASTC, 5x4 blocks, unsigned normalized + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR: // 4-component ASTC, 5x4 blocks, sRGB + pFormatSize->flags = KTX_FORMAT_SIZE_COMPRESSED_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 128; + pFormatSize->blockWidth = 5; + pFormatSize->blockHeight = 4; + pFormatSize->blockDepth = 1; + break; + case GL_COMPRESSED_RGBA_ASTC_5x5_KHR: // 4-component ASTC, 5x5 blocks, unsigned normalized + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR: // 4-component ASTC, 5x5 blocks, sRGB + pFormatSize->flags = KTX_FORMAT_SIZE_COMPRESSED_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 128; + pFormatSize->blockWidth = 5; + pFormatSize->blockHeight = 5; + pFormatSize->blockDepth = 1; + break; + case GL_COMPRESSED_RGBA_ASTC_6x5_KHR: // 4-component ASTC, 6x5 blocks, unsigned normalized + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR: // 4-component ASTC, 6x5 blocks, sRGB + pFormatSize->flags = KTX_FORMAT_SIZE_COMPRESSED_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 128; + pFormatSize->blockWidth = 6; + pFormatSize->blockHeight = 5; + pFormatSize->blockDepth = 1; + break; + case GL_COMPRESSED_RGBA_ASTC_6x6_KHR: // 4-component ASTC, 6x6 blocks, unsigned normalized + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR: // 4-component ASTC, 6x6 blocks, sRGB + pFormatSize->flags = KTX_FORMAT_SIZE_COMPRESSED_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 128; + pFormatSize->blockWidth = 6; + pFormatSize->blockHeight = 6; + pFormatSize->blockDepth = 1; + break; + case GL_COMPRESSED_RGBA_ASTC_8x5_KHR: // 4-component ASTC, 8x5 blocks, unsigned normalized + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR: // 4-component ASTC, 8x5 blocks, sRGB + pFormatSize->flags = KTX_FORMAT_SIZE_COMPRESSED_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 128; + pFormatSize->blockWidth = 8; + pFormatSize->blockHeight = 5; + pFormatSize->blockDepth = 1; + break; + case GL_COMPRESSED_RGBA_ASTC_8x6_KHR: // 4-component ASTC, 8x6 blocks, unsigned normalized + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR: // 4-component ASTC, 8x6 blocks, sRGB + pFormatSize->flags = KTX_FORMAT_SIZE_COMPRESSED_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 128; + pFormatSize->blockWidth = 8; + pFormatSize->blockHeight = 6; + pFormatSize->blockDepth = 1; + break; + case GL_COMPRESSED_RGBA_ASTC_8x8_KHR: // 4-component ASTC, 8x8 blocks, unsigned normalized + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR: // 4-component ASTC, 8x8 blocks, sRGB + pFormatSize->flags = KTX_FORMAT_SIZE_COMPRESSED_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 128; + pFormatSize->blockWidth = 8; + pFormatSize->blockHeight = 8; + pFormatSize->blockDepth = 1; + break; + case GL_COMPRESSED_RGBA_ASTC_10x5_KHR: // 4-component ASTC, 10x5 blocks, unsigned normalized + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR: // 4-component ASTC, 10x5 blocks, sRGB + pFormatSize->flags = KTX_FORMAT_SIZE_COMPRESSED_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 128; + pFormatSize->blockWidth = 10; + pFormatSize->blockHeight = 5; + pFormatSize->blockDepth = 1; + break; + case GL_COMPRESSED_RGBA_ASTC_10x6_KHR: // 4-component ASTC, 10x6 blocks, unsigned normalized + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR: // 4-component ASTC, 10x6 blocks, sRGB + pFormatSize->flags = KTX_FORMAT_SIZE_COMPRESSED_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 128; + pFormatSize->blockWidth = 10; + pFormatSize->blockHeight = 6; + pFormatSize->blockDepth = 1; + break; + case GL_COMPRESSED_RGBA_ASTC_10x8_KHR: // 4-component ASTC, 10x8 blocks, unsigned normalized + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR: // 4-component ASTC, 10x8 blocks, sRGB + pFormatSize->flags = KTX_FORMAT_SIZE_COMPRESSED_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 128; + pFormatSize->blockWidth = 10; + pFormatSize->blockHeight = 8; + pFormatSize->blockDepth = 1; + break; + case GL_COMPRESSED_RGBA_ASTC_10x10_KHR: // 4-component ASTC, 10x10 blocks, unsigned normalized + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR: // 4-component ASTC, 10x10 blocks, sRGB + pFormatSize->flags = KTX_FORMAT_SIZE_COMPRESSED_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 128; + pFormatSize->blockWidth = 10; + pFormatSize->blockHeight = 10; + pFormatSize->blockDepth = 1; + break; + case GL_COMPRESSED_RGBA_ASTC_12x10_KHR: // 4-component ASTC, 12x10 blocks, unsigned normalized + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR: // 4-component ASTC, 12x10 blocks, sRGB + pFormatSize->flags = KTX_FORMAT_SIZE_COMPRESSED_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 128; + pFormatSize->blockWidth = 12; + pFormatSize->blockHeight = 10; + pFormatSize->blockDepth = 1; + break; + case GL_COMPRESSED_RGBA_ASTC_12x12_KHR: // 4-component ASTC, 12x12 blocks, unsigned normalized + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR: // 4-component ASTC, 12x12 blocks, sRGB + pFormatSize->flags = KTX_FORMAT_SIZE_COMPRESSED_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 128; + pFormatSize->blockWidth = 12; + pFormatSize->blockHeight = 12; + pFormatSize->blockDepth = 1; + break; + + case GL_COMPRESSED_RGBA_ASTC_3x3x3_OES: // 4-component ASTC, 3x3x3 blocks, unsigned normalized + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_3x3x3_OES: // 4-component ASTC, 3x3x3 blocks, sRGB + pFormatSize->flags = KTX_FORMAT_SIZE_COMPRESSED_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 128; + pFormatSize->blockWidth = 3; + pFormatSize->blockHeight = 3; + pFormatSize->blockDepth = 3; + break; + case GL_COMPRESSED_RGBA_ASTC_4x3x3_OES: // 4-component ASTC, 4x3x3 blocks, unsigned normalized + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x3x3_OES: // 4-component ASTC, 4x3x3 blocks, sRGB + pFormatSize->flags = KTX_FORMAT_SIZE_COMPRESSED_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 128; + pFormatSize->blockWidth = 4; + pFormatSize->blockHeight = 3; + pFormatSize->blockDepth = 3; + break; + case GL_COMPRESSED_RGBA_ASTC_4x4x3_OES: // 4-component ASTC, 4x4x3 blocks, unsigned normalized + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4x3_OES: // 4-component ASTC, 4x4x3 blocks, sRGB + pFormatSize->flags = KTX_FORMAT_SIZE_COMPRESSED_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 128; + pFormatSize->blockWidth = 4; + pFormatSize->blockHeight = 4; + pFormatSize->blockDepth = 3; + break; + case GL_COMPRESSED_RGBA_ASTC_4x4x4_OES: // 4-component ASTC, 4x4x4 blocks, unsigned normalized + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4x4_OES: // 4-component ASTC, 4x4x4 blocks, sRGB + pFormatSize->flags = KTX_FORMAT_SIZE_COMPRESSED_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 128; + pFormatSize->blockWidth = 4; + pFormatSize->blockHeight = 4; + pFormatSize->blockDepth = 4; + break; + case GL_COMPRESSED_RGBA_ASTC_5x4x4_OES: // 4-component ASTC, 5x4x4 blocks, unsigned normalized + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4x4_OES: // 4-component ASTC, 5x4x4 blocks, sRGB + pFormatSize->flags = KTX_FORMAT_SIZE_COMPRESSED_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 128; + pFormatSize->blockWidth = 5; + pFormatSize->blockHeight = 4; + pFormatSize->blockDepth = 4; + break; + case GL_COMPRESSED_RGBA_ASTC_5x5x4_OES: // 4-component ASTC, 5x5x4 blocks, unsigned normalized + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5x4_OES: // 4-component ASTC, 5x5x4 blocks, sRGB + pFormatSize->flags = KTX_FORMAT_SIZE_COMPRESSED_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 128; + pFormatSize->blockWidth = 5; + pFormatSize->blockHeight = 5; + pFormatSize->blockDepth = 4; + break; + case GL_COMPRESSED_RGBA_ASTC_5x5x5_OES: // 4-component ASTC, 5x5x5 blocks, unsigned normalized + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5x5_OES: // 4-component ASTC, 5x5x5 blocks, sRGB + pFormatSize->flags = KTX_FORMAT_SIZE_COMPRESSED_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 128; + pFormatSize->blockWidth = 5; + pFormatSize->blockHeight = 5; + pFormatSize->blockDepth = 5; + break; + case GL_COMPRESSED_RGBA_ASTC_6x5x5_OES: // 4-component ASTC, 6x5x5 blocks, unsigned normalized + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5x5_OES: // 4-component ASTC, 6x5x5 blocks, sRGB + pFormatSize->flags = KTX_FORMAT_SIZE_COMPRESSED_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 128; + pFormatSize->blockWidth = 6; + pFormatSize->blockHeight = 5; + pFormatSize->blockDepth = 5; + break; + case GL_COMPRESSED_RGBA_ASTC_6x6x5_OES: // 4-component ASTC, 6x6x5 blocks, unsigned normalized + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6x5_OES: // 4-component ASTC, 6x6x5 blocks, sRGB + pFormatSize->flags = KTX_FORMAT_SIZE_COMPRESSED_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 128; + pFormatSize->blockWidth = 6; + pFormatSize->blockHeight = 6; + pFormatSize->blockDepth = 5; + break; + case GL_COMPRESSED_RGBA_ASTC_6x6x6_OES: // 4-component ASTC, 6x6x6 blocks, unsigned normalized + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6x6_OES: // 4-component ASTC, 6x6x6 blocks, sRGB + pFormatSize->flags = KTX_FORMAT_SIZE_COMPRESSED_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 128; + pFormatSize->blockWidth = 6; + pFormatSize->blockHeight = 6; + pFormatSize->blockDepth = 6; + break; + + // + // ATC + // + case GL_ATC_RGB_AMD: // 3-component, 4x4 blocks, unsigned normalized + pFormatSize->flags = KTX_FORMAT_SIZE_COMPRESSED_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 64; + pFormatSize->blockWidth = 4; + pFormatSize->blockHeight = 4; + pFormatSize->blockDepth = 1; + break; + case GL_ATC_RGBA_EXPLICIT_ALPHA_AMD: // 4-component, 4x4 blocks, unsigned normalized + case GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD: // 4-component, 4x4 blocks, unsigned normalized + pFormatSize->flags = KTX_FORMAT_SIZE_COMPRESSED_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 128; + pFormatSize->blockWidth = 4; + pFormatSize->blockHeight = 4; + pFormatSize->blockDepth = 1; + break; + + // + // Palletized + // + case GL_PALETTE4_RGB8_OES: // 3-component 8:8:8, 4-bit palette, unsigned normalized + pFormatSize->flags = KTX_FORMAT_SIZE_PALETTIZED_BIT; + pFormatSize->paletteSizeInBits = 16 * 24; + pFormatSize->blockSizeInBits = 4; + pFormatSize->blockWidth = 1; + pFormatSize->blockHeight = 1; + pFormatSize->blockDepth = 1; + break; + case GL_PALETTE4_RGBA8_OES: // 4-component 8:8:8:8, 4-bit palette, unsigned normalized + pFormatSize->flags = KTX_FORMAT_SIZE_PALETTIZED_BIT; + pFormatSize->paletteSizeInBits = 16 * 32; + pFormatSize->blockSizeInBits = 4; + pFormatSize->blockWidth = 1; + pFormatSize->blockHeight = 1; + pFormatSize->blockDepth = 1; + break; + case GL_PALETTE4_R5_G6_B5_OES: // 3-component 5:6:5, 4-bit palette, unsigned normalized + case GL_PALETTE4_RGBA4_OES: // 4-component 4:4:4:4, 4-bit palette, unsigned normalized + case GL_PALETTE4_RGB5_A1_OES: // 4-component 5:5:5:1, 4-bit palette, unsigned normalized + pFormatSize->flags = KTX_FORMAT_SIZE_PALETTIZED_BIT; + pFormatSize->paletteSizeInBits = 16 * 16; + pFormatSize->blockSizeInBits = 4; + pFormatSize->blockWidth = 1; + pFormatSize->blockHeight = 1; + pFormatSize->blockDepth = 1; + break; + case GL_PALETTE8_RGB8_OES: // 3-component 8:8:8, 8-bit palette, unsigned normalized + pFormatSize->flags = KTX_FORMAT_SIZE_PALETTIZED_BIT; + pFormatSize->paletteSizeInBits = 256 * 24; + pFormatSize->blockSizeInBits = 8; + pFormatSize->blockWidth = 1; + pFormatSize->blockHeight = 1; + pFormatSize->blockDepth = 1; + break; + case GL_PALETTE8_RGBA8_OES: // 4-component 8:8:8:8, 8-bit palette, unsigned normalized + pFormatSize->flags = KTX_FORMAT_SIZE_PALETTIZED_BIT; + pFormatSize->paletteSizeInBits = 256 * 32; + pFormatSize->blockSizeInBits = 8; + pFormatSize->blockWidth = 1; + pFormatSize->blockHeight = 1; + pFormatSize->blockDepth = 1; + break; + case GL_PALETTE8_R5_G6_B5_OES: // 3-component 5:6:5, 8-bit palette, unsigned normalized + case GL_PALETTE8_RGBA4_OES: // 4-component 4:4:4:4, 8-bit palette, unsigned normalized + case GL_PALETTE8_RGB5_A1_OES: // 4-component 5:5:5:1, 8-bit palette, unsigned normalized + pFormatSize->flags = KTX_FORMAT_SIZE_PALETTIZED_BIT; + pFormatSize->paletteSizeInBits = 256 * 16; + pFormatSize->blockSizeInBits = 8; + pFormatSize->blockWidth = 1; + pFormatSize->blockHeight = 1; + pFormatSize->blockDepth = 1; + break; + + // + // Depth/stencil + // + case GL_DEPTH_COMPONENT16: + pFormatSize->flags = KTX_FORMAT_SIZE_DEPTH_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 16; + pFormatSize->blockWidth = 1; + pFormatSize->blockHeight = 1; + pFormatSize->blockDepth = 1; + break; + case GL_DEPTH_COMPONENT24: + case GL_DEPTH_COMPONENT32: + case GL_DEPTH_COMPONENT32F: + case GL_DEPTH_COMPONENT32F_NV: + pFormatSize->flags = KTX_FORMAT_SIZE_DEPTH_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 32; + pFormatSize->blockWidth = 1; + pFormatSize->blockHeight = 1; + pFormatSize->blockDepth = 1; + break; + case GL_STENCIL_INDEX1: + pFormatSize->flags = KTX_FORMAT_SIZE_STENCIL_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 1; + pFormatSize->blockWidth = 1; + pFormatSize->blockHeight = 1; + pFormatSize->blockDepth = 1; + break; + case GL_STENCIL_INDEX4: + pFormatSize->flags = KTX_FORMAT_SIZE_STENCIL_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 4; + pFormatSize->blockWidth = 1; + pFormatSize->blockHeight = 1; + pFormatSize->blockDepth = 1; + break; + case GL_STENCIL_INDEX8: + pFormatSize->flags = KTX_FORMAT_SIZE_STENCIL_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 8; + pFormatSize->blockWidth = 1; + pFormatSize->blockHeight = 1; + pFormatSize->blockDepth = 1; + break; + case GL_STENCIL_INDEX16: + pFormatSize->flags = KTX_FORMAT_SIZE_STENCIL_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 16; + pFormatSize->blockWidth = 1; + pFormatSize->blockHeight = 1; + pFormatSize->blockDepth = 1; + break; + case GL_DEPTH24_STENCIL8: + pFormatSize->flags = KTX_FORMAT_SIZE_DEPTH_BIT | KTX_FORMAT_SIZE_STENCIL_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 32; + pFormatSize->blockWidth = 1; + pFormatSize->blockHeight = 1; + pFormatSize->blockDepth = 1; + break; + case GL_DEPTH32F_STENCIL8: + case GL_DEPTH32F_STENCIL8_NV: + pFormatSize->flags = KTX_FORMAT_SIZE_DEPTH_BIT | KTX_FORMAT_SIZE_STENCIL_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 64; + pFormatSize->blockWidth = 1; + pFormatSize->blockHeight = 1; + pFormatSize->blockDepth = 1; + break; + + default: + pFormatSize->flags = 0; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 0 * 8; + pFormatSize->blockWidth = 1; + pFormatSize->blockHeight = 1; + pFormatSize->blockDepth = 1; + break; + } +} + +static inline GLint glGetInternalFormatFromVkFormat( VkFormat vkFormat ) +{ + switch ( vkFormat ) + { + // + // 8 bits per component + // + case VK_FORMAT_R8_UNORM: return GL_R8; // 1-component, 8-bit unsigned normalized + case VK_FORMAT_R8G8_UNORM: return GL_RG8; // 2-component, 8-bit unsigned normalized + case VK_FORMAT_R8G8B8_UNORM: return GL_RGB8; // 3-component, 8-bit unsigned normalized + case VK_FORMAT_R8G8B8A8_UNORM: return GL_RGBA8; // 4-component, 8-bit unsigned normalized + + case VK_FORMAT_R8_SNORM: return GL_R8_SNORM; // 1-component, 8-bit signed normalized + case VK_FORMAT_R8G8_SNORM: return GL_RG8_SNORM; // 2-component, 8-bit signed normalized + case VK_FORMAT_R8G8B8_SNORM: return GL_RGB8_SNORM; // 3-component, 8-bit signed normalized + case VK_FORMAT_R8G8B8A8_SNORM: return GL_RGBA8_SNORM; // 4-component, 8-bit signed normalized + + case VK_FORMAT_R8_UINT: return GL_R8UI; // 1-component, 8-bit unsigned integer + case VK_FORMAT_R8G8_UINT: return GL_RG8UI; // 2-component, 8-bit unsigned integer + case VK_FORMAT_R8G8B8_UINT: return GL_RGB8UI; // 3-component, 8-bit unsigned integer + case VK_FORMAT_R8G8B8A8_UINT: return GL_RGBA8UI; // 4-component, 8-bit unsigned integer + + case VK_FORMAT_R8_SINT: return GL_R8I; // 1-component, 8-bit signed integer + case VK_FORMAT_R8G8_SINT: return GL_RG8I; // 2-component, 8-bit signed integer + case VK_FORMAT_R8G8B8_SINT: return GL_RGB8I; // 3-component, 8-bit signed integer + case VK_FORMAT_R8G8B8A8_SINT: return GL_RGBA8I; // 4-component, 8-bit signed integer + + case VK_FORMAT_R8_SRGB: return GL_SR8; // 1-component, 8-bit sRGB + case VK_FORMAT_R8G8_SRGB: return GL_SRG8; // 2-component, 8-bit sRGB + case VK_FORMAT_R8G8B8_SRGB: return GL_SRGB8; // 3-component, 8-bit sRGB + case VK_FORMAT_R8G8B8A8_SRGB: return GL_SRGB8_ALPHA8; // 4-component, 8-bit sRGB + + // + // 16 bits per component + // + case VK_FORMAT_R16_UNORM: return GL_R16; // 1-component, 16-bit unsigned normalized + case VK_FORMAT_R16G16_UNORM: return GL_RG16; // 2-component, 16-bit unsigned normalized + case VK_FORMAT_R16G16B16_UNORM: return GL_RGB16; // 3-component, 16-bit unsigned normalized + case VK_FORMAT_R16G16B16A16_UNORM: return GL_RGBA16; // 4-component, 16-bit unsigned normalized + + case VK_FORMAT_R16_SNORM: return GL_R16_SNORM; // 1-component, 16-bit signed normalized + case VK_FORMAT_R16G16_SNORM: return GL_RG16_SNORM; // 2-component, 16-bit signed normalized + case VK_FORMAT_R16G16B16_SNORM: return GL_RGB16_SNORM; // 3-component, 16-bit signed normalized + case VK_FORMAT_R16G16B16A16_SNORM: return GL_RGBA16_SNORM; // 4-component, 16-bit signed normalized + + case VK_FORMAT_R16_UINT: return GL_R16UI; // 1-component, 16-bit unsigned integer + case VK_FORMAT_R16G16_UINT: return GL_RG16UI; // 2-component, 16-bit unsigned integer + case VK_FORMAT_R16G16B16_UINT: return GL_RGB16UI; // 3-component, 16-bit unsigned integer + case VK_FORMAT_R16G16B16A16_UINT: return GL_RGBA16UI; // 4-component, 16-bit unsigned integer + + case VK_FORMAT_R16_SINT: return GL_R16I; // 1-component, 16-bit signed integer + case VK_FORMAT_R16G16_SINT: return GL_RG16I; // 2-component, 16-bit signed integer + case VK_FORMAT_R16G16B16_SINT: return GL_RGB16I; // 3-component, 16-bit signed integer + case VK_FORMAT_R16G16B16A16_SINT: return GL_RGBA16I; // 4-component, 16-bit signed integer + + case VK_FORMAT_R16_SFLOAT: return GL_R16F; // 1-component, 16-bit floating-point + case VK_FORMAT_R16G16_SFLOAT: return GL_RG16F; // 2-component, 16-bit floating-point + case VK_FORMAT_R16G16B16_SFLOAT: return GL_RGB16F; // 3-component, 16-bit floating-point + case VK_FORMAT_R16G16B16A16_SFLOAT: return GL_RGBA16F; // 4-component, 16-bit floating-point + + // + // 32 bits per component + // + case VK_FORMAT_R32_UINT: return GL_R32UI; // 1-component, 32-bit unsigned integer + case VK_FORMAT_R32G32_UINT: return GL_RG32UI; // 2-component, 32-bit unsigned integer + case VK_FORMAT_R32G32B32_UINT: return GL_RGB32UI; // 3-component, 32-bit unsigned integer + case VK_FORMAT_R32G32B32A32_UINT: return GL_RGBA32UI; // 4-component, 32-bit unsigned integer + + case VK_FORMAT_R32_SINT: return GL_R32I; // 1-component, 32-bit signed integer + case VK_FORMAT_R32G32_SINT: return GL_RG32I; // 2-component, 32-bit signed integer + case VK_FORMAT_R32G32B32_SINT: return GL_RGB32I; // 3-component, 32-bit signed integer + case VK_FORMAT_R32G32B32A32_SINT: return GL_RGBA32I; // 4-component, 32-bit signed integer + + case VK_FORMAT_R32_SFLOAT: return GL_R32F; // 1-component, 32-bit floating-point + case VK_FORMAT_R32G32_SFLOAT: return GL_RG32F; // 2-component, 32-bit floating-point + case VK_FORMAT_R32G32B32_SFLOAT: return GL_RGB32F; // 3-component, 32-bit floating-point + case VK_FORMAT_R32G32B32A32_SFLOAT: return GL_RGBA32F; // 4-component, 32-bit floating-point + + // + // Packed + // + case VK_FORMAT_R5G5B5A1_UNORM_PACK16: return GL_RGB5; // 3-component 5:5:5, unsigned normalized + case VK_FORMAT_R5G6B5_UNORM_PACK16: return GL_RGB565; // 3-component 5:6:5, unsigned normalized + case VK_FORMAT_R4G4B4A4_UNORM_PACK16: return GL_RGBA4; // 4-component 4:4:4:4, unsigned normalized + case VK_FORMAT_A1R5G5B5_UNORM_PACK16: return GL_RGB5_A1; // 4-component 5:5:5:1, unsigned normalized + case VK_FORMAT_A2R10G10B10_UNORM_PACK32: return GL_RGB10_A2; // 4-component 10:10:10:2, unsigned normalized + case VK_FORMAT_A2R10G10B10_UINT_PACK32: return GL_RGB10_A2UI; // 4-component 10:10:10:2, unsigned integer + case VK_FORMAT_B10G11R11_UFLOAT_PACK32: return GL_R11F_G11F_B10F; // 3-component 11:11:10, floating-point + case VK_FORMAT_E5B9G9R9_UFLOAT_PACK32: return GL_RGB9_E5; // 3-component/exp 9:9:9/5, floating-point + + // + // S3TC/DXT/BC + // + + case VK_FORMAT_BC1_RGB_UNORM_BLOCK: return GL_COMPRESSED_RGB_S3TC_DXT1_EXT; // line through 3D space, 4x4 blocks, unsigned normalized + case VK_FORMAT_BC1_RGBA_UNORM_BLOCK: return GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; // line through 3D space plus 1-bit alpha, 4x4 blocks, unsigned normalized + case VK_FORMAT_BC2_UNORM_BLOCK: return GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; // line through 3D space plus line through 1D space, 4x4 blocks, unsigned normalized + case VK_FORMAT_BC3_UNORM_BLOCK: return GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; // line through 3D space plus 4-bit alpha, 4x4 blocks, unsigned normalized + + case VK_FORMAT_BC1_RGB_SRGB_BLOCK: return GL_COMPRESSED_SRGB_S3TC_DXT1_EXT; // line through 3D space, 4x4 blocks, sRGB + case VK_FORMAT_BC1_RGBA_SRGB_BLOCK: return GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT; // line through 3D space plus 1-bit alpha, 4x4 blocks, sRGB + case VK_FORMAT_BC2_SRGB_BLOCK: return GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT; // line through 3D space plus line through 1D space, 4x4 blocks, sRGB + case VK_FORMAT_BC3_SRGB_BLOCK: return GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT; // line through 3D space plus 4-bit alpha, 4x4 blocks, sRGB + + case VK_FORMAT_BC4_UNORM_BLOCK: return GL_COMPRESSED_RED_RGTC1; // line through 1D space, 4x4 blocks, unsigned normalized + case VK_FORMAT_BC5_UNORM_BLOCK: return GL_COMPRESSED_RG_RGTC2; // two lines through 1D space, 4x4 blocks, unsigned normalized + case VK_FORMAT_BC4_SNORM_BLOCK: return GL_COMPRESSED_SIGNED_RED_RGTC1; // line through 1D space, 4x4 blocks, signed normalized + case VK_FORMAT_BC5_SNORM_BLOCK: return GL_COMPRESSED_SIGNED_RG_RGTC2; // two lines through 1D space, 4x4 blocks, signed normalized + + case VK_FORMAT_BC6H_UFLOAT_BLOCK: return GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT; // 3-component, 4x4 blocks, unsigned floating-point + case VK_FORMAT_BC6H_SFLOAT_BLOCK: return GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT; // 3-component, 4x4 blocks, signed floating-point + case VK_FORMAT_BC7_UNORM_BLOCK: return GL_COMPRESSED_RGBA_BPTC_UNORM; // 4-component, 4x4 blocks, unsigned normalized + case VK_FORMAT_BC7_SRGB_BLOCK: return GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM; // 4-component, 4x4 blocks, sRGB + + // + // ETC + // + case VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK: return GL_COMPRESSED_RGB8_ETC2; // 3-component ETC2, 4x4 blocks, unsigned normalized + case VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK: return GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2; // 4-component ETC2 with 1-bit alpha, 4x4 blocks, unsigned normalized + case VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK: return GL_COMPRESSED_RGBA8_ETC2_EAC; // 4-component ETC2, 4x4 blocks, unsigned normalized + + case VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK: return GL_COMPRESSED_SRGB8_ETC2; // 3-component ETC2, 4x4 blocks, sRGB + case VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK: return GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2; // 4-component ETC2 with 1-bit alpha, 4x4 blocks, sRGB + case VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK: return GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC; // 4-component ETC2, 4x4 blocks, sRGB + + case VK_FORMAT_EAC_R11_UNORM_BLOCK: return GL_COMPRESSED_R11_EAC; // 1-component ETC, 4x4 blocks, unsigned normalized + case VK_FORMAT_EAC_R11G11_UNORM_BLOCK: return GL_COMPRESSED_RG11_EAC; // 2-component ETC, 4x4 blocks, unsigned normalized + case VK_FORMAT_EAC_R11_SNORM_BLOCK: return GL_COMPRESSED_SIGNED_R11_EAC; // 1-component ETC, 4x4 blocks, signed normalized + case VK_FORMAT_EAC_R11G11_SNORM_BLOCK: return GL_COMPRESSED_SIGNED_RG11_EAC; // 2-component ETC, 4x4 blocks, signed normalized + + // + // PVRTC + // + case VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG: return GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG; // 3- or 4-component PVRTC, 16x8 blocks, unsigned normalized + case VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG: return GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG; // 3- or 4-component PVRTC, 8x8 blocks, unsigned normalized + case VK_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG: return GL_COMPRESSED_RGBA_PVRTC_2BPPV2_IMG; // 3- or 4-component PVRTC, 16x8 blocks, unsigned normalized + case VK_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG: return GL_COMPRESSED_RGBA_PVRTC_4BPPV2_IMG; // 3- or 4-component PVRTC, 4x4 blocks, unsigned normalized + + case VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG: return GL_COMPRESSED_SRGB_ALPHA_PVRTC_2BPPV1_EXT; // 4-component PVRTC, 16x8 blocks, sRGB + case VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG: return GL_COMPRESSED_SRGB_ALPHA_PVRTC_4BPPV1_EXT; // 4-component PVRTC, 8x8 blocks, sRGB + case VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG: return GL_COMPRESSED_SRGB_ALPHA_PVRTC_2BPPV2_IMG; // 4-component PVRTC, 8x4 blocks, sRGB + case VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG: return GL_COMPRESSED_SRGB_ALPHA_PVRTC_4BPPV2_IMG; // 4-component PVRTC, 4x4 blocks, sRGB + + // + // ASTC + // + case VK_FORMAT_ASTC_4x4_UNORM_BLOCK: return GL_COMPRESSED_RGBA_ASTC_4x4_KHR; // 4-component ASTC, 4x4 blocks, unsigned normalized + case VK_FORMAT_ASTC_5x4_UNORM_BLOCK: return GL_COMPRESSED_RGBA_ASTC_5x4_KHR; // 4-component ASTC, 5x4 blocks, unsigned normalized + case VK_FORMAT_ASTC_5x5_UNORM_BLOCK: return GL_COMPRESSED_RGBA_ASTC_5x5_KHR; // 4-component ASTC, 5x5 blocks, unsigned normalized + case VK_FORMAT_ASTC_6x5_UNORM_BLOCK: return GL_COMPRESSED_RGBA_ASTC_6x5_KHR; // 4-component ASTC, 6x5 blocks, unsigned normalized + case VK_FORMAT_ASTC_6x6_UNORM_BLOCK: return GL_COMPRESSED_RGBA_ASTC_6x6_KHR; // 4-component ASTC, 6x6 blocks, unsigned normalized + case VK_FORMAT_ASTC_8x5_UNORM_BLOCK: return GL_COMPRESSED_RGBA_ASTC_8x5_KHR; // 4-component ASTC, 8x5 blocks, unsigned normalized + case VK_FORMAT_ASTC_8x6_UNORM_BLOCK: return GL_COMPRESSED_RGBA_ASTC_8x6_KHR; // 4-component ASTC, 8x6 blocks, unsigned normalized + case VK_FORMAT_ASTC_8x8_UNORM_BLOCK: return GL_COMPRESSED_RGBA_ASTC_8x8_KHR; // 4-component ASTC, 8x8 blocks, unsigned normalized + case VK_FORMAT_ASTC_10x5_UNORM_BLOCK: return GL_COMPRESSED_RGBA_ASTC_10x5_KHR; // 4-component ASTC, 10x5 blocks, unsigned normalized + case VK_FORMAT_ASTC_10x6_UNORM_BLOCK: return GL_COMPRESSED_RGBA_ASTC_10x6_KHR; // 4-component ASTC, 10x6 blocks, unsigned normalized + case VK_FORMAT_ASTC_10x8_UNORM_BLOCK: return GL_COMPRESSED_RGBA_ASTC_10x8_KHR; // 4-component ASTC, 10x8 blocks, unsigned normalized + case VK_FORMAT_ASTC_10x10_UNORM_BLOCK: return GL_COMPRESSED_RGBA_ASTC_10x10_KHR; // 4-component ASTC, 10x10 blocks, unsigned normalized + case VK_FORMAT_ASTC_12x10_UNORM_BLOCK: return GL_COMPRESSED_RGBA_ASTC_12x10_KHR; // 4-component ASTC, 12x10 blocks, unsigned normalized + case VK_FORMAT_ASTC_12x12_UNORM_BLOCK: return GL_COMPRESSED_RGBA_ASTC_12x12_KHR; // 4-component ASTC, 12x12 blocks, unsigned normalized + + case VK_FORMAT_ASTC_4x4_SRGB_BLOCK: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR; // 4-component ASTC, 4x4 blocks, sRGB + case VK_FORMAT_ASTC_5x4_SRGB_BLOCK: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR; // 4-component ASTC, 5x4 blocks, sRGB + case VK_FORMAT_ASTC_5x5_SRGB_BLOCK: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR; // 4-component ASTC, 5x5 blocks, sRGB + case VK_FORMAT_ASTC_6x5_SRGB_BLOCK: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR; // 4-component ASTC, 6x5 blocks, sRGB + case VK_FORMAT_ASTC_6x6_SRGB_BLOCK: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR; // 4-component ASTC, 6x6 blocks, sRGB + case VK_FORMAT_ASTC_8x5_SRGB_BLOCK: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR; // 4-component ASTC, 8x5 blocks, sRGB + case VK_FORMAT_ASTC_8x6_SRGB_BLOCK: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR; // 4-component ASTC, 8x6 blocks, sRGB + case VK_FORMAT_ASTC_8x8_SRGB_BLOCK: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR; // 4-component ASTC, 8x8 blocks, sRGB + case VK_FORMAT_ASTC_10x5_SRGB_BLOCK: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR; // 4-component ASTC, 10x5 blocks, sRGB + case VK_FORMAT_ASTC_10x6_SRGB_BLOCK: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR; // 4-component ASTC, 10x6 blocks, sRGB + case VK_FORMAT_ASTC_10x8_SRGB_BLOCK: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR; // 4-component ASTC, 10x8 blocks, sRGB + case VK_FORMAT_ASTC_10x10_SRGB_BLOCK: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR; // 4-component ASTC, 10x10 blocks, sRGB + case VK_FORMAT_ASTC_12x10_SRGB_BLOCK: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR; // 4-component ASTC, 12x10 blocks, sRGB + case VK_FORMAT_ASTC_12x12_SRGB_BLOCK: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR; // 4-component ASTC, 12x12 blocks, sRGB + + // XXX FIXME Update once Vulkan ASTC HDR & 3D extensions are released. +#if 0 + case VK_FORMAT_UNDEFINED: return GL_COMPRESSED_RGBA_ASTC_3x3x3_OES; // 4-component ASTC, 3x3x3 blocks, unsigned normalized + case VK_FORMAT_UNDEFINED: return GL_COMPRESSED_RGBA_ASTC_4x3x3_OES; // 4-component ASTC, 4x3x3 blocks, unsigned normalized + case VK_FORMAT_UNDEFINED: return GL_COMPRESSED_RGBA_ASTC_4x4x3_OES; // 4-component ASTC, 4x4x3 blocks, unsigned normalized + case VK_FORMAT_UNDEFINED: return GL_COMPRESSED_RGBA_ASTC_4x4x4_OES; // 4-component ASTC, 4x4x4 blocks, unsigned normalized + case VK_FORMAT_UNDEFINED: return GL_COMPRESSED_RGBA_ASTC_5x4x4_OES; // 4-component ASTC, 5x4x4 blocks, unsigned normalized + case VK_FORMAT_UNDEFINED: return GL_COMPRESSED_RGBA_ASTC_5x5x4_OES; // 4-component ASTC, 5x5x4 blocks, unsigned normalized + case VK_FORMAT_UNDEFINED: return GL_COMPRESSED_RGBA_ASTC_5x5x5_OES; // 4-component ASTC, 5x5x5 blocks, unsigned normalized + case VK_FORMAT_UNDEFINED: return GL_COMPRESSED_RGBA_ASTC_6x5x5_OES; // 4-component ASTC, 6x5x5 blocks, unsigned normalized + case VK_FORMAT_UNDEFINED: return GL_COMPRESSED_RGBA_ASTC_6x6x5_OES; // 4-component ASTC, 6x6x5 blocks, unsigned normalized + case VK_FORMAT_UNDEFINED: return GL_COMPRESSED_RGBA_ASTC_6x6x6_OES; // 4-component ASTC, 6x6x6 blocks, unsigned normalized + + case VK_FORMAT_UNDEFINED: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_3x3x3_OES; // 4-component ASTC, 3x3x3 blocks, sRGB + case VK_FORMAT_UNDEFINED: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x3x3_OES; // 4-component ASTC, 4x3x3 blocks, sRGB + case VK_FORMAT_UNDEFINED: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4x3_OES; // 4-component ASTC, 4x4x3 blocks, sRGB + case VK_FORMAT_UNDEFINED: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4x4_OES; // 4-component ASTC, 4x4x4 blocks, sRGB + case VK_FORMAT_UNDEFINED: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4x4_OES; // 4-component ASTC, 5x4x4 blocks, sRGB + case VK_FORMAT_UNDEFINED: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5x4_OES; // 4-component ASTC, 5x5x4 blocks, sRGB + case VK_FORMAT_UNDEFINED: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5x5_OES; // 4-component ASTC, 5x5x5 blocks, sRGB + case VK_FORMAT_UNDEFINED: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5x5_OES; // 4-component ASTC, 6x5x5 blocks, sRGB + case VK_FORMAT_UNDEFINED: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6x5_OES; // 4-component ASTC, 6x6x5 blocks, sRGB + case VK_FORMAT_UNDEFINED: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6x6_OES; // 4-component ASTC, 6x6x6 blocks, sRGB +#endif + + // + // Depth/stencil + // + case VK_FORMAT_D16_UNORM: return GL_DEPTH_COMPONENT16; + case VK_FORMAT_X8_D24_UNORM_PACK32: return GL_DEPTH_COMPONENT24; + case VK_FORMAT_D32_SFLOAT: return GL_DEPTH_COMPONENT32F; + case VK_FORMAT_S8_UINT: return GL_STENCIL_INDEX8; + case VK_FORMAT_D24_UNORM_S8_UINT: return GL_DEPTH24_STENCIL8; + case VK_FORMAT_D32_SFLOAT_S8_UINT: return GL_DEPTH32F_STENCIL8; + + default: return GL_INVALID_VALUE; + } +} + +#endif // !GL_FORMAT_H diff --git a/thirdparty/libktx/lib/hashlist.c b/thirdparty/libktx/lib/hashlist.c new file mode 100644 index 000000000000..0ca89fc561bf --- /dev/null +++ b/thirdparty/libktx/lib/hashlist.c @@ -0,0 +1,604 @@ +/* -*- tab-width: 4; -*- */ +/* vi: set sw=2 ts=4 expandtab: */ + +/* + * Copyright 2010-2020 The Khronos Group Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @internal + * @file hashlist.c + * @~English + * + * @brief Functions for creating and using a hash list of key-value + * pairs. + * + * @author Mark Callow, HI Corporation + */ + +#include +#include +#include +#include + +// This is to avoid compile warnings. strlen is defined as returning +// size_t and is used by the uthash macros. This avoids having to +// make changes to uthash and a bunch of casts in this file. The +// casts would be required because the key and value lengths in KTX +// are specified as 4 byte quantities so we can't change _keyAndValue +// below to use size_t. +#define strlen(x) ((unsigned int)strlen(x)) + +#include "uthash.h" + +#include "ktx.h" +#include "ktxint.h" + + +/** + * @internal + * @struct ktxKVListEntry + * @brief Hash list entry structure + */ +typedef struct ktxKVListEntry { + unsigned int keyLen; /*!< Length of the key */ + char* key; /*!< Pointer to key string */ + unsigned int valueLen; /*!< Length of the value */ + void* value; /*!< Pointer to the value */ + UT_hash_handle hh; /*!< handle used by UT hash */ +} ktxKVListEntry; + + +/** + * @memberof ktxHashList @public + * @~English + * @brief Construct an empty hash list for storing key-value pairs. + * + * @param [in] pHead pointer to the location to write the list head. + */ +void +ktxHashList_Construct(ktxHashList* pHead) +{ + *pHead = NULL; +} + + +/** + * @memberof ktxHashList @public + * @~English + * @brief Construct a hash list by copying another. + * + * @param [in] pHead pointer to head of the list. + * @param [in] orig head of the original hash list. + */ +void +ktxHashList_ConstructCopy(ktxHashList* pHead, ktxHashList orig) +{ + ktxHashListEntry* entry = orig; + *pHead = NULL; + for (; entry != NULL; entry = ktxHashList_Next(entry)) { + (void)ktxHashList_AddKVPair(pHead, + entry->key, entry->valueLen, entry->value); + } +} + + +/** + * @memberof ktxHashList @public + * @~English + * @brief Destruct a hash list. + * + * All memory associated with the hash list's keys and values + * is freed. + * + * @param [in] pHead pointer to the hash list to be destroyed. + */ +void +ktxHashList_Destruct(ktxHashList* pHead) +{ + ktxKVListEntry* kv; + ktxKVListEntry* head = *pHead; + + for(kv = head; kv != NULL;) { + ktxKVListEntry* tmp = (ktxKVListEntry*)kv->hh.next; + HASH_DELETE(hh, head, kv); + free(kv); + kv = tmp; + } +} + + +/** + * @memberof ktxHashList @public + * @~English + * @brief Create an empty hash list for storing key-value pairs. + * + * @param [in,out] ppHl address of a variable in which to set a pointer to + * the newly created hash list. + * + * @return KTX_SUCCESS or one of the following error codes. + * @exception KTX_OUT_OF_MEMORY if not enough memory. + */ +KTX_error_code +ktxHashList_Create(ktxHashList** ppHl) +{ + ktxHashList* hl = (ktxHashList*)malloc(sizeof (ktxKVListEntry*)); + if (hl == NULL) + return KTX_OUT_OF_MEMORY; + + ktxHashList_Construct(hl); + *ppHl = hl; + return KTX_SUCCESS; +} + + +/** + * @memberof ktxHashList @public + * @~English + * @brief Create a copy of a hash list. + * + * @param [in,out] ppHl address of a variable in which to set a pointer to + * the newly created hash list. + * @param [in] orig head of the ktxHashList to copy. + * + * @return KTX_SUCCESS or one of the following error codes. + * @exception KTX_OUT_OF_MEMORY if not enough memory. + */ +KTX_error_code +ktxHashList_CreateCopy(ktxHashList** ppHl, ktxHashList orig) +{ + ktxHashList* hl = (ktxHashList*)malloc(sizeof (ktxKVListEntry*)); + if (hl == NULL) + return KTX_OUT_OF_MEMORY; + + ktxHashList_ConstructCopy(hl, orig); + *ppHl = hl; + return KTX_SUCCESS; +} + + +/** + * @memberof ktxHashList @public + * @~English + * @brief Destroy a hash list. + * + * All memory associated with the hash list's keys and values + * is freed. The hash list is also freed. + * + * @param [in] pHead pointer to the hash list to be destroyed. + */ +void +ktxHashList_Destroy(ktxHashList* pHead) +{ + ktxHashList_Destruct(pHead); + free(pHead); +} + +#if !__clang__ && __GNUC__ // Grumble clang grumble +// These are in uthash.h macros. I don't want to change that file. +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wimplicit-fallthrough" +#endif + +/** + * @memberof ktxHashList @public + * @~English + * @brief Add a key value pair to a hash list. + * + * The value can be empty, i.e, its length can be 0. + * + * @param [in] pHead pointer to the head of the target hash list. + * @param [in] key pointer to the UTF8 NUL-terminated string to be used as the key. + * @param [in] valueLen the number of bytes of data in @p value. + * @param [in] value pointer to the bytes of data constituting the value. + * + * @return KTX_SUCCESS or one of the following error codes. + * @exception KTX_INVALID_VALUE if @p pHead, @p key or @p value are NULL, @p key is an + * empty string or @p valueLen == 0. + */ +KTX_error_code +ktxHashList_AddKVPair(ktxHashList* pHead, const char* key, unsigned int valueLen, const void* value) +{ + if (pHead && key && (valueLen == 0 || value)) { + unsigned int keyLen = (unsigned int)strlen(key) + 1; + ktxKVListEntry* kv; + + if (keyLen == 1) + return KTX_INVALID_VALUE; /* Empty string */ + + /* Allocate all the memory as a block */ + kv = (ktxKVListEntry*)malloc(sizeof(ktxKVListEntry) + keyLen + valueLen); + /* Put key first */ + kv->key = (char *)kv + sizeof(ktxKVListEntry); + kv->keyLen = keyLen; + memcpy(kv->key, key, keyLen); + /* then value */ + kv->valueLen = valueLen; + if (valueLen > 0) { + kv->value = kv->key + keyLen; + memcpy(kv->value, value, valueLen); + } else { + kv->value = 0; + } + + HASH_ADD_KEYPTR( hh, *pHead, kv->key, kv->keyLen-1, kv); + return KTX_SUCCESS; + } else + return KTX_INVALID_VALUE; +} + + +/** + * @memberof ktxHashList @public + * @~English + * @brief Delete a key value pair in a hash list. + * + * Is a nop if the key is not in the hash. + * + * @param [in] pHead pointer to the head of the target hash list. + * @param [in] key pointer to the UTF8 NUL-terminated string to be used as the key. + * + * @return KTX_SUCCESS or one of the following error codes. + * @exception KTX_INVALID_VALUE if @p pHead is NULL or @p key is an empty + * string. + */ +KTX_error_code +ktxHashList_DeleteKVPair(ktxHashList* pHead, const char* key) +{ + if (pHead && key) { + ktxKVListEntry* kv; + + HASH_FIND_STR( *pHead, key, kv ); /* kv: pointer to target entry. */ + if (kv != NULL) + HASH_DEL(*pHead, kv); + return KTX_SUCCESS; + } else + return KTX_INVALID_VALUE; +} + + +/** + * @memberof ktxHashList @public + * @~English + * @brief Delete an entry from a hash list. + * + * @param [in] pHead pointer to the head of the target hash list. + * @param [in] pEntry pointer to the ktxHashListEntry to delete. + * + * @return KTX_SUCCESS or one of the following error codes. + * @exception KTX_INVALID_VALUE if @p pHead is NULL or @p key is an empty + * string. + */ +KTX_error_code +ktxHashList_DeleteEntry(ktxHashList* pHead, ktxHashListEntry* pEntry) +{ + if (pHead && pEntry) { + HASH_DEL(*pHead, pEntry); + return KTX_SUCCESS; + } else + return KTX_INVALID_VALUE; +} + + +/** + * @memberof ktxHashList @public + * @~English + * @brief Looks up a key in a hash list and returns the entry. + * + * @param [in] pHead pointer to the head of the target hash list. + * @param [in] key pointer to a UTF8 NUL-terminated string to find. + * @param [in,out] ppEntry @p *ppEntry is set to the point at the + * ktxHashListEntry. + * + * @return KTX_SUCCESS or one of the following error codes. + * + * @exception KTX_INVALID_VALUE if @p This, @p key or @p pValueLen or @p ppValue + * is NULL. + * @exception KTX_NOT_FOUND an entry matching @p key was not found. + */ +KTX_error_code +ktxHashList_FindEntry(ktxHashList* pHead, const char* key, + ktxHashListEntry** ppEntry) +{ + if (pHead && key) { + ktxKVListEntry* kv; + + HASH_FIND_STR( *pHead, key, kv ); /* kv: output pointer */ + + if (kv) { + *ppEntry = kv; + return KTX_SUCCESS; + } else + return KTX_NOT_FOUND; + } else + return KTX_INVALID_VALUE; +} + + +/** + * @memberof ktxHashList @public + * @~English + * @brief Looks up a key in a hash list and returns the value. + * + * @param [in] pHead pointer to the head of the target hash list. + * @param [in] key pointer to a UTF8 NUL-terminated string to find. + * @param [in,out] pValueLen @p *pValueLen is set to the number of bytes of + * data in the returned value. + * @param [in,out] ppValue @p *ppValue is set to the point to the value for + * @p key. + * + * @return KTX_SUCCESS or one of the following error codes. + * + * @exception KTX_INVALID_VALUE if @p This, @p key or @p pValueLen or @p ppValue + * is NULL. + * @exception KTX_NOT_FOUND an entry matching @p key was not found. + */ +KTX_error_code +ktxHashList_FindValue(ktxHashList *pHead, const char* key, unsigned int* pValueLen, void** ppValue) +{ + if (pValueLen && ppValue) { + ktxHashListEntry* pEntry; + KTX_error_code result; + + result = ktxHashList_FindEntry(pHead, key, &pEntry); + if (result == KTX_SUCCESS) { + ktxHashListEntry_GetValue(pEntry, pValueLen, ppValue); + return KTX_SUCCESS; + } else + return result; + } else + return KTX_INVALID_VALUE; +} + +#if !__clang__ && __GNUC__ +#pragma GCC diagnostic pop +#endif + +/** + * @memberof ktxHashList @public + * @~English + * @brief Returns the next entry in a ktxHashList. + * + * Use for iterating through the list: + * @code + * ktxHashListEntry* entry; + * for (entry = listHead; entry != NULL; entry = ktxHashList_Next(entry)) { + * ... + * }; + * @endcode + * + * Note + * + * @param [in] entry pointer to a hash list entry. Note that a ktxHashList*, + * i.e. the list head, is also a pointer to an entry so + * can be passed to this function. + * + * @return a pointer to the next entry or NULL. + * + */ +ktxHashListEntry* +ktxHashList_Next(ktxHashListEntry* entry) +{ + if (entry) { + return ((ktxKVListEntry*)entry)->hh.next; + } else + return NULL; +} + + +/** + * @memberof ktxHashList @public + * @~English + * @brief Serialize a hash list to a block of data suitable for writing + * to a file. + * + * The caller is responsible for freeing the data block returned by this + * function. + * + * @param [in] pHead pointer to the head of the target hash list. + * @param [in,out] pKvdLen @p *pKvdLen is set to the number of bytes of + * data in the returned data block. + * @param [in,out] ppKvd @p *ppKvd is set to the point to the block of + * memory containing the serialized data or + * NULL. if the hash list is empty. + * + * @return KTX_SUCCESS or one of the following error codes. + * + * @exception KTX_INVALID_VALUE if @p This, @p pKvdLen or @p ppKvd is NULL. + * @exception KTX_OUT_OF_MEMORY there was not enough memory to serialize the + * data. + */ +KTX_error_code +ktxHashList_Serialize(ktxHashList* pHead, + unsigned int* pKvdLen, unsigned char** ppKvd) +{ + + if (pHead && pKvdLen && ppKvd) { + ktxKVListEntry* kv; + unsigned int bytesOfKeyValueData = 0; + unsigned int keyValueLen; + unsigned char* sd; + char padding[4] = {0, 0, 0, 0}; + + for (kv = *pHead; kv != NULL; kv = kv->hh.next) { + /* sizeof(sd) is to make space to write keyAndValueByteSize */ + keyValueLen = kv->keyLen + kv->valueLen + sizeof(ktx_uint32_t); + /* Add valuePadding */ + keyValueLen = _KTX_PAD4(keyValueLen); + bytesOfKeyValueData += keyValueLen; + } + + if (bytesOfKeyValueData == 0) { + *pKvdLen = 0; + *ppKvd = NULL; + } else { + sd = malloc(bytesOfKeyValueData); + if (!sd) + return KTX_OUT_OF_MEMORY; + + *pKvdLen = bytesOfKeyValueData; + *ppKvd = sd; + + for (kv = *pHead; kv != NULL; kv = kv->hh.next) { + int padLen; + + keyValueLen = kv->keyLen + kv->valueLen; + *(ktx_uint32_t*)sd = keyValueLen; + sd += sizeof(ktx_uint32_t); + memcpy(sd, kv->key, kv->keyLen); + sd += kv->keyLen; + if (kv->valueLen > 0) + memcpy(sd, kv->value, kv->valueLen); + sd += kv->valueLen; + padLen = _KTX_PAD4_LEN(keyValueLen); + memcpy(sd, padding, padLen); + sd += padLen; + } + } + return KTX_SUCCESS; + } else + return KTX_INVALID_VALUE; +} + + +int sort_by_key_codepoint(ktxKVListEntry* a, ktxKVListEntry* b) { + return strcmp(a->key, b->key); +} + +/** + * @memberof ktxHashList @public + * @~English + * @brief Sort a hash list in order of the UTF8 codepoints. + * + * @param [in] pHead pointer to the head of the target hash list. + * + * @return KTX_SUCCESS or one of the following error codes. + * + * @exception KTX_INVALID_VALUE if @p This is NULL. + */ +KTX_error_code +ktxHashList_Sort(ktxHashList* pHead) +{ + if (pHead) { + //ktxKVListEntry* kv = (ktxKVListEntry*)pHead; + + HASH_SORT(*pHead, sort_by_key_codepoint); + return KTX_SUCCESS; + } else { + return KTX_INVALID_VALUE; + } +} + + +/** + * @memberof ktxHashList @public + * @~English + * @brief Construct a hash list from a block of serialized key-value + * data read from a file. + * @note The bytes of the 32-bit key-value lengths within the serialized data + * are expected to be in native endianness. + * + * @param [in] pHead pointer to the head of the target hash list. + * @param [in] kvdLen the length of the serialized key-value data. + * @param [in] pKvd pointer to the serialized key-value data. + * table. + * + * @return KTX_SUCCESS or one of the following error codes. + * + * @exception KTX_INVALID_OPERATION if @p pHead does not point to an empty list. + * @exception KTX_INVALID_VALUE if @p pKvd or @p pHt is NULL or kvdLen == 0. + * @exception KTX_OUT_OF_MEMORY there was not enough memory to create the hash + * table. + */ +KTX_error_code +ktxHashList_Deserialize(ktxHashList* pHead, unsigned int kvdLen, void* pKvd) +{ + char* src = pKvd; + KTX_error_code result; + + if (kvdLen == 0 || pKvd == NULL || pHead == NULL) + return KTX_INVALID_VALUE; + + if (*pHead != NULL) + return KTX_INVALID_OPERATION; + + result = KTX_SUCCESS; + while (result == KTX_SUCCESS && src < (char *)pKvd + kvdLen) { + char* key; + unsigned int keyLen, valueLen; + void* value; + ktx_uint32_t keyAndValueByteSize = *((ktx_uint32_t*)src); + + src += sizeof(keyAndValueByteSize); + key = src; + keyLen = (unsigned int)strlen(key) + 1; + value = key + keyLen; + + valueLen = keyAndValueByteSize - keyLen; + result = ktxHashList_AddKVPair(pHead, key, valueLen, + valueLen > 0 ? value : NULL); + if (result == KTX_SUCCESS) { + src += _KTX_PAD4(keyAndValueByteSize); + } + } + return result; +} + + +/** + * @memberof ktxHashListEntry @public + * @~English + * @brief Return the key of a ktxHashListEntry + * + * @param [in] This The target hash list entry. + * @param [in,out] pKeyLen @p *pKeyLen is set to the byte length of + * the returned key. + * @param [in,out] ppKey @p *ppKey is set to the point to the value of + * @p the key. + * + * @return KTX_SUCCESS or one of the following error codes. + * + * @exception KTX_INVALID_VALUE if @p pKvd or @p pHt is NULL or kvdLen == 0. + */ +KTX_error_code +ktxHashListEntry_GetKey(ktxHashListEntry* This, + unsigned int* pKeyLen, char** ppKey) +{ + if (pKeyLen && ppKey) { + ktxKVListEntry* kv = (ktxKVListEntry*)This; + *pKeyLen = kv->keyLen; + *ppKey = kv->key; + return KTX_SUCCESS; + } else + return KTX_INVALID_VALUE; +} + + +/** + * @memberof ktxHashListEntry @public + * @~English + * @brief Return the value from a ktxHashListEntry + * + * @param [in] This The target hash list entry. + * @param [in,out] pValueLen @p *pValueLen is set to the number of bytes of + * data in the returned value. + * @param [in,out] ppValue @p *ppValue is set to point to the value of + * of the target entry. + * + * @return KTX_SUCCESS or one of the following error codes. + * + * @exception KTX_INVALID_VALUE if @p pKvd or @p pHt is NULL or kvdLen == 0. + */ +KTX_error_code +ktxHashListEntry_GetValue(ktxHashListEntry* This, + unsigned int* pValueLen, void** ppValue) +{ + if (pValueLen && ppValue) { + ktxKVListEntry* kv = (ktxKVListEntry*)This; + *pValueLen = kv->valueLen; + *ppValue = kv->valueLen > 0 ? kv->value : NULL; + return KTX_SUCCESS; + } else + return KTX_INVALID_VALUE; +} diff --git a/thirdparty/libktx/lib/ktxint.h b/thirdparty/libktx/lib/ktxint.h new file mode 100644 index 000000000000..03c9945ce781 --- /dev/null +++ b/thirdparty/libktx/lib/ktxint.h @@ -0,0 +1,266 @@ +/* -*- tab-width: 4; -*- */ +/* vi: set sw=2 ts=4 expandtab: */ + +/* $Id: e36ad79b5eac8ea237d6a05602c71aadab575519 $ */ + +/* + * Copyright 2010-2020 The Khronos Group Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + + +/* + * Author: Mark Callow from original code by Georg Kolling + */ + +#ifndef KTXINT_H +#define KTXINT_H + +#include + +/* Define this to include the ETC unpack software in the library. */ +#ifndef SUPPORT_SOFTWARE_ETC_UNPACK + /* Include for all GL versions because have seen OpenGL ES 3 + * implementaions that do not support ETC1 (ARM Mali emulator v1.0)! + */ + #define SUPPORT_SOFTWARE_ETC_UNPACK 1 +#endif + +#ifndef MAX +#define MAX(x, y) (((x) > (y)) ? (x) : (y)) +#endif + +#define QUOTE(x) #x +#define STR(x) QUOTE(x) + +#define KTX2_IDENTIFIER_REF { 0xAB, 0x4B, 0x54, 0x58, 0x20, 0x32, 0x30, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A } +#define KTX2_HEADER_SIZE (80) + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @internal + * @brief used to pass GL context capabilites to subroutines. + */ +#define _KTX_NO_R16_FORMATS 0x0 +#define _KTX_R16_FORMATS_NORM 0x1 +#define _KTX_R16_FORMATS_SNORM 0x2 +#define _KTX_ALL_R16_FORMATS (_KTX_R16_FORMATS_NORM | _KTX_R16_FORMATS_SNORM) +extern GLint _ktxR16Formats; +extern GLboolean _ktxSupportsSRGB; + +/** + * @internal + * @~English + * @brief KTX file header. + * + * See the KTX specification for descriptions. + */ +typedef struct KTX_header { + ktx_uint8_t identifier[12]; + ktx_uint32_t endianness; + ktx_uint32_t glType; + ktx_uint32_t glTypeSize; + ktx_uint32_t glFormat; + ktx_uint32_t glInternalformat; + ktx_uint32_t glBaseInternalformat; + ktx_uint32_t pixelWidth; + ktx_uint32_t pixelHeight; + ktx_uint32_t pixelDepth; + ktx_uint32_t numberOfArrayElements; + ktx_uint32_t numberOfFaces; + ktx_uint32_t numberOfMipLevels; + ktx_uint32_t bytesOfKeyValueData; +} KTX_header; + +/* This will cause compilation to fail if the struct size doesn't match */ +typedef int KTX_header_SIZE_ASSERT [sizeof(KTX_header) == KTX_HEADER_SIZE]; + +/** + * @internal + * @~English + * @brief 32-bit KTX 2 index entry. + */ +typedef struct ktxIndexEntry32 { + ktx_uint32_t byteOffset; /*!< Offset of item from start of file. */ + ktx_uint32_t byteLength; /*!< Number of bytes of data in the item. */ +} ktxIndexEntry32; +/** + * @internal + * @~English + * @brief 64-bit KTX 2 index entry. + */ +typedef struct ktxIndexEntry64 { + ktx_uint64_t byteOffset; /*!< Offset of item from start of file. */ + ktx_uint64_t byteLength; /*!< Number of bytes of data in the item. */ +} ktxIndexEntry64; + +/** + * @internal + * @~English + * @brief KTX 2 file header. + * + * See the KTX 2 specification for descriptions. + */ +typedef struct KTX_header2 { + ktx_uint8_t identifier[12]; + ktx_uint32_t vkFormat; + ktx_uint32_t typeSize; + ktx_uint32_t pixelWidth; + ktx_uint32_t pixelHeight; + ktx_uint32_t pixelDepth; + ktx_uint32_t layerCount; + ktx_uint32_t faceCount; + ktx_uint32_t levelCount; + ktx_uint32_t supercompressionScheme; + ktxIndexEntry32 dataFormatDescriptor; + ktxIndexEntry32 keyValueData; + ktxIndexEntry64 supercompressionGlobalData; +} KTX_header2; + +/* This will cause compilation to fail if the struct size doesn't match */ +typedef int KTX_header2_SIZE_ASSERT [sizeof(KTX_header2) == KTX2_HEADER_SIZE]; + +/** + * @internal + * @~English + * @brief KTX 2 level index entry. + */ +typedef struct ktxLevelIndexEntry { + ktx_uint64_t byteOffset; /*!< Offset of level from start of file. */ + ktx_uint64_t byteLength; + /*!< Number of bytes of compressed image data in the level. */ + ktx_uint64_t uncompressedByteLength; + /*!< Number of bytes of uncompressed image data in the level. */ +} ktxLevelIndexEntry; + +/** + * @internal + * @~English + * @brief Structure for supplemental information about the texture. + * + * _ktxCheckHeader returns supplemental information about the texture in this + * structure that is derived during checking of the file header. + */ +typedef struct KTX_supplemental_info +{ + ktx_uint8_t compressed; + ktx_uint8_t generateMipmaps; + ktx_uint16_t textureDimension; +} KTX_supplemental_info; +/** + * @internal + * @var ktx_uint8_t KTX_supplemental_info::compressed + * @~English + * @brief KTX_TRUE, if this a compressed texture, KTX_FALSE otherwise? + */ +/** + * @internal + * @var ktx_uint8_t KTX_supplemental_info::generateMipmaps + * @~English + * @brief KTX_TRUE, if mipmap generation is required, KTX_FALSE otherwise. + */ +/** + * @internal + * @var ktx_uint16_t KTX_supplemental_info::textureDimension + * @~English + * @brief The number of dimensions, 1, 2 or 3, of data in the texture image. + */ + +/* + * @internal + * CheckHeader1 + * + * Reads the KTX file header and performs some sanity checking on the values + */ +KTX_error_code ktxCheckHeader1_(KTX_header* pHeader, + KTX_supplemental_info* pSuppInfo); + +/* + * @internal + * CheckHeader2 + * + * Reads the KTX 2 file header and performs some sanity checking on the values + */ +KTX_error_code ktxCheckHeader2_(KTX_header2* pHeader, + KTX_supplemental_info* pSuppInfo); + +/* + * SwapEndian16: Swaps endianness in an array of 16-bit values + */ +void _ktxSwapEndian16(ktx_uint16_t* pData16, ktx_size_t count); + +/* + * SwapEndian32: Swaps endianness in an array of 32-bit values + */ +void _ktxSwapEndian32(ktx_uint32_t* pData32, ktx_size_t count); + +/* + * SwapEndian32: Swaps endianness in an array of 64-bit values + */ +void _ktxSwapEndian64(ktx_uint64_t* pData64, ktx_size_t count); + +/* + * UnpackETC: uncompresses an ETC compressed texture image + */ +KTX_error_code _ktxUnpackETC(const GLubyte* srcETC, const GLenum srcFormat, + ktx_uint32_t active_width, ktx_uint32_t active_height, + GLubyte** dstImage, + GLenum* format, GLenum* internalFormat, GLenum* type, + GLint R16Formats, GLboolean supportsSRGB); + +/* + * Pad nbytes to next multiple of n + */ +#define _KTX_PADN(n, nbytes) (ktx_uint32_t)(n * ceilf((float)(nbytes) / n)) +/* + * Calculate bytes of of padding needed to reach next multiple of n. + */ +/* Equivalent to (n * ceil(nbytes / n)) - nbytes */ +#define _KTX_PADN_LEN(n, nbytes) \ + (ktx_uint32_t)((n * ceilf((float)(nbytes) / n)) - (nbytes)) + +/* + * Pad nbytes to next multiple of 4 + */ +#define _KTX_PAD4(nbytes) _KTX_PADN(4, nbytes) +/* + * Calculate bytes of of padding needed to reach next multiple of 4. + */ +#define _KTX_PAD4_LEN(nbytes) _KTX_PADN_LEN(4, nbytes) + +/* + * Pad nbytes to next multiple of 8 + */ +#define _KTX_PAD8(nbytes) _KTX_PADN(8, nbytes) +/* + * Calculate bytes of of padding needed to reach next multiple of 8. + */ +#define _KTX_PAD8_LEN(nbytes) _KTX_PADN_LEN(8, nbytes) + +/* + * Pad nbytes to KTX_GL_UNPACK_ALIGNMENT + */ +#define _KTX_PAD_UNPACK_ALIGN(nbytes) \ + _KTX_PADN(KTX_GL_UNPACK_ALIGNMENT, nbytes) +/* + * Calculate bytes of of padding needed to reach KTX_GL_UNPACK_ALIGNMENT. + */ +#define _KTX_PAD_UNPACK_ALIGN_LEN(nbytes) \ + _KTX_PADN_LEN(KTX_GL_UNPACK_ALIGNMENT, nbytes) + +/* + ====================================== + Internal utility functions + ====================================== +*/ + +void printKTX2Info2(ktxStream* src, KTX_header2* header); + +#ifdef __cplusplus +} +#endif + +#endif /* KTXINT_H */ diff --git a/thirdparty/libktx/lib/memstream.c b/thirdparty/libktx/lib/memstream.c new file mode 100644 index 000000000000..b963fa70cad8 --- /dev/null +++ b/thirdparty/libktx/lib/memstream.c @@ -0,0 +1,561 @@ +/* -*- tab-width: 4; -*- */ +/* vi: set sw=2 ts=4 expandtab: */ + +/* + * Copyright 2010-2020 The Khronos Group Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @~English + * + * @brief Implementation of ktxStream for memory. + * + * @author Maksim Kolesin, Under Development + * @author Georg Kolling, Imagination Technology + * @author Mark Callow, HI Corporation + */ + +#include +#include +#include + +#include "ktx.h" +#include "ktxint.h" +#include "memstream.h" + +/** +* @brief Default allocation size for a ktxMemStream. +*/ +#define KTX_MEM_DEFAULT_ALLOCATED_SIZE 256 + +/** + * @brief Structure to store information about data allocated for ktxMemStream. + */ +struct ktxMem +{ + const ktx_uint8_t* robytes;/*!< pointer to read-only data */ + ktx_uint8_t* bytes; /*!< pointer to rw data. */ + ktx_size_t alloc_size; /*!< allocated size of the memory block. */ + ktx_size_t used_size; /*!< bytes used. Effectively the write position. */ + ktx_off_t pos; /*!< read/write position. */ +}; + +static KTX_error_code ktxMem_expand(ktxMem* pMem, const ktx_size_t size); + +/** + * @brief Initialize a ktxMem struct for read-write. + * + * Memory for the stream data is allocated internally but the + * caller is responsible for freeing the memory. A pointer to + * the memory can be obtained with ktxMem_getdata(). + * + * @sa ktxMem_getdata. + * + * @param [in] pMem pointer to the @c ktxMem to initialize. + */ +static KTX_error_code +ktxMem_construct(ktxMem* pMem) +{ + pMem->pos = 0; + pMem->alloc_size = 0; + pMem->robytes = 0; + pMem->bytes = 0; + pMem->used_size = 0; + return ktxMem_expand(pMem, KTX_MEM_DEFAULT_ALLOCATED_SIZE); +} + +/** + * @brief Create & initialize a ktxMem struct for read-write. + * + * @sa ktxMem_construct. + * + * @param [in,out] ppMem pointer to the location in which to return + * a pointer to the newly created @c ktxMem. + * + * @return KTX_SUCCESS on success, KTX_OUT_OF_MEMORY on error. + * + * @exception KTX_OUT_OF_MEMORY System failed to allocate sufficient pMemory. + */ +static KTX_error_code +ktxMem_create(ktxMem** ppMem) +{ + ktxMem* pNewMem = (ktxMem*)malloc(sizeof(ktxMem)); + if (pNewMem) { + KTX_error_code result = ktxMem_construct(pNewMem); + if (result == KTX_SUCCESS) + *ppMem = pNewMem; + return result; + } + else { + return KTX_OUT_OF_MEMORY; + } +} + +/** + * @brief Initialize a ktxMem struct for read-only. + * + * @param [in] pMem pointer to the @c ktxMem to initialize. + * @param [in] bytes pointer to the data to be read. + * @param [in] numBytes number of bytes of data. + */ +static void +ktxMem_construct_ro(ktxMem* pMem, const void* bytes, ktx_size_t numBytes) +{ + pMem->pos = 0; + pMem->robytes = bytes; + pMem->bytes = 0; + pMem->used_size = numBytes; + pMem->alloc_size = numBytes; +} + +/** + * @brief Create & initialize a ktxMem struct for read-only. + * + * @sa ktxMem_construct. + * + * @param [in,out] ppMem pointer to the location in which to return + * a pointer to the newly created @c ktxMem. + * @param [in] bytes pointer to the data to be read. + * @param [in] numBytes number of bytes of data. + * + * @return KTX_SUCCESS on success, KTX_OUT_OF_MEMORY on error. + * + * @exception KTX_OUT_OF_MEMORY System failed to allocate sufficient pMemory. + */ +static KTX_error_code +ktxMem_create_ro(ktxMem** ppMem, const void* bytes, ktx_size_t numBytes) +{ + ktxMem* pNewMem = (ktxMem*)malloc(sizeof(ktxMem)); + if (pNewMem) { + ktxMem_construct_ro(pNewMem, bytes, numBytes); + *ppMem = pNewMem; + return KTX_SUCCESS; + } + else { + return KTX_OUT_OF_MEMORY; + } +} + +/* + * ktxMem_destruct not needed as ktxMem_construct caller is reponsible + * for freeing the data written. + */ + +/** + * @brief Free the memory of a struct ktxMem. + * + * @param pMem pointer to ktxMem to free. + */ +static void +ktxMem_destroy(ktxMem* pMem, ktx_bool_t freeData) +{ + assert(pMem != NULL); + if (freeData) { + free(pMem->bytes); + } + free(pMem); +} + +#ifdef KTXMEM_CLEAR_USED +/** + * @brief Clear the data of a memory stream. + * + * @param pMem pointer to ktxMem to clear. + */ +static void +ktxMem_clear(ktxMem* pMem) +{ + assert(pMem != NULL); + memset(pMem, 0, sizeof(ktxMem)); +} +#endif + +/** + * @~English + * @brief Expand a ktxMem to fit to a new size. + * + * @param [in] pMem pointer to ktxMem struct to expand. + * @param [in] newsize minimum new size required. + * + * @return KTX_SUCCESS on success, KTX_OUT_OF_MEMORY on error. + * + * @exception KTX_OUT_OF_MEMORY System failed to allocate sufficient pMemory. + */ +static KTX_error_code +ktxMem_expand(ktxMem *pMem, const ktx_size_t newsize) +{ + ktx_size_t new_alloc_size; + + assert(pMem != NULL && newsize != 0); + + new_alloc_size = pMem->alloc_size == 0 ? + KTX_MEM_DEFAULT_ALLOCATED_SIZE : pMem->alloc_size; + while (new_alloc_size < newsize) { + ktx_size_t alloc_size = new_alloc_size; + new_alloc_size <<= 1; + if (new_alloc_size < alloc_size) { + /* Overflow. Set to maximum size. newsize can't be larger. */ + new_alloc_size = (ktx_size_t)-1L; + } + } + + if (new_alloc_size == pMem->alloc_size) + return KTX_SUCCESS; + + if (!pMem->bytes) + pMem->bytes = (ktx_uint8_t*)malloc(new_alloc_size); + else + pMem->bytes = (ktx_uint8_t*)realloc(pMem->bytes, new_alloc_size); + + if (!pMem->bytes) + { + pMem->alloc_size = 0; + pMem->used_size = 0; + return KTX_OUT_OF_MEMORY; + } + + pMem->alloc_size = new_alloc_size; + return KTX_SUCCESS; +} + +/** + * @~English + * @brief Read bytes from a ktxMemStream. + * + * @param [in] str pointer to ktxMem struct, converted to a void*, that + * specifies an input stream. + * @param [in,out] dst pointer to memory where to copy read bytes. + * @param [in,out] count pointer to number of bytes to read. + * + * @return KTX_SUCCESS on success, KTX_INVALID_VALUE on error. + * + * @exception KTX_INVALID_VALUE @p str or @p dst is @c NULL or @p str->data is + * @c NULL. + * @exception KTX_FILE_UNEXPECTED_EOF not enough data to satisfy the request. + */ +static +KTX_error_code ktxMemStream_read(ktxStream* str, void* dst, const ktx_size_t count) +{ + ktxMem* mem; + ktx_off_t newpos; + const ktx_uint8_t* bytes; + + + if (!str || (mem = str->data.mem)== 0) + return KTX_INVALID_VALUE; + + newpos = mem->pos + count; + /* The first clause checks for overflow. */ + if (newpos < mem->pos || (ktx_uint32_t)newpos > mem->used_size) + return KTX_FILE_UNEXPECTED_EOF; + + bytes = mem->robytes ? mem->robytes : mem->bytes; + memcpy(dst, bytes + mem->pos, count); + mem->pos = newpos; + + return KTX_SUCCESS; +} + +/** + * @~English + * @brief Skip bytes in a ktxMemStream. + * + * @param [in] str pointer to the ktxStream on which to operate. + * @param [in] count number of bytes to skip. + * + * @return KTX_SUCCESS on success, KTX_INVALID_VALUE on error. + * + * @exception KTX_INVALID_VALUE @p str or @p mem is @c NULL or sufficient + * data is not available in ktxMem. + * @exception KTX_FILE_UNEXPECTED_EOF not enough data to satisfy the request. + */ +static +KTX_error_code ktxMemStream_skip(ktxStream* str, const ktx_size_t count) +{ + ktxMem* mem; + ktx_off_t newpos; + + if (!str || (mem = str->data.mem) == 0) + return KTX_INVALID_VALUE; + + newpos = mem->pos + count; + /* The first clause checks for overflow. */ + if (newpos < mem->pos || (ktx_uint32_t)newpos > mem->used_size) + return KTX_FILE_UNEXPECTED_EOF; + + mem->pos = newpos; + + return KTX_SUCCESS; +} + +/** + * @~English + * @brief Write bytes to a ktxMemStream. + * + * @param [out] str pointer to the ktxStream that specifies the destination. + * @param [in] src pointer to the array of elements to be written, + * converted to a const void*. + * @param [in] size size in bytes of each element to be written. + * @param [in] count number of elements, each one with a @p size of size + * bytes. + * + * @return KTX_SUCCESS on success, other KTX_* enum values on error. + * + * @exception KTX_FILE_OVERFLOW write would result in file exceeding the + * maximum permissible size. + * @exception KTX_INVALID_OPERATION @p str is a read-only stream. + * @exception KTX_INVALID_VALUE @p dst is @c NULL or @p mem is @c NULL. + * @exception KTX_OUT_OF_MEMORY See ktxMem_expand() for causes. + */ +static +KTX_error_code ktxMemStream_write(ktxStream* str, const void* src, + const ktx_size_t size, const ktx_size_t count) +{ + ktxMem* mem; + KTX_error_code rc = KTX_SUCCESS; + ktx_size_t new_size; + + if (!str || (mem = str->data.mem) == 0) + return KTX_INVALID_VALUE; + + if (mem->robytes) + return KTX_INVALID_OPERATION; /* read-only */ + + new_size = mem->pos + (size*count); + //if (new_size < mem->used_size) + if ((ktx_off_t)new_size < mem->pos) + return KTX_FILE_OVERFLOW; + + if (mem->alloc_size < new_size) { + rc = ktxMem_expand(mem, new_size); + if (rc != KTX_SUCCESS) + return rc; + } + + memcpy(mem->bytes + mem->pos, src, size*count); + mem->pos += size*count; + if (mem->pos > (ktx_off_t)mem->used_size) + mem->used_size = mem->pos; + + + return KTX_SUCCESS; +} + +/** + * @~English + * @brief Get the current read/write position in a ktxMemStream. + * + * @param [in] str pointer to the ktxStream to query. + * @param [in,out] off pointer to variable to receive the offset value. + * + * @return KTX_SUCCESS on success, other KTX_* enum values on error. + * + * @exception KTX_INVALID_VALUE @p str or @p pos is @c NULL. + */ +static +KTX_error_code ktxMemStream_getpos(ktxStream* str, ktx_off_t* const pos) +{ + if (!str || !pos) + return KTX_INVALID_VALUE; + + assert(str->type == eStreamTypeMemory); + + *pos = str->data.mem->pos; + return KTX_SUCCESS; +} + +/** + * @~English + * @brief Set the current read/write position in a ktxMemStream. + * + * Offset of 0 is the start of the file. + * + * @param [in] str pointer to the ktxStream whose r/w position is to be set. + * @param [in] off pointer to the offset value to set. + * + * @return KTX_SUCCESS on success, other KTX_* enum values on error. + * + * @exception KTX_INVALID_VALUE @p str is @c NULL. + * @exception KTX_INVALID_OPERATION @p pos > size of the allocated memory. + */ +static +KTX_error_code ktxMemStream_setpos(ktxStream* str, ktx_off_t pos) +{ + if (!str) + return KTX_INVALID_VALUE; + + assert(str->type == eStreamTypeMemory); + + if (pos > (ktx_off_t)str->data.mem->alloc_size) + return KTX_INVALID_OPERATION; + + str->data.mem->pos = pos; + return KTX_SUCCESS; +} + +/** + * @~English + * @brief Get a pointer to a ktxMemStream's data. + * + * Gets a pointer to data that has been written to the stream. Returned + * pointer will be 0 if stream is read-only. + * + * @param [in] str pointer to the ktxStream whose data pointer is to + * be queried. + * @param [in,out] ppBytes pointer to a variable in which the data pointer + * will be written. + * + * @return KTX_SUCCESS on success, other KTX_* enum values on error. + * + * @exception KTX_INVALID_VALUE @p str or @p ppBytes is @c NULL. + */ +KTX_error_code ktxMemStream_getdata(ktxStream* str, ktx_uint8_t** ppBytes) +{ + if (!str || !ppBytes) + return KTX_INVALID_VALUE; + + assert(str->type == eStreamTypeMemory); + + *ppBytes = str->data.mem->bytes; + return KTX_SUCCESS; +} + +/** + * @~English + * @brief Get the size of a ktxMemStream in bytes. + * + * @param [in] str pointer to the ktxStream whose size is to be queried. + * @param [in,out] size pointer to a variable in which size will be written. + * + * @return KTX_SUCCESS on success, other KTX_* enum values on error. + * + * @exception KTX_INVALID_VALUE @p str or @p pSize is @c NULL. + */ +static +KTX_error_code ktxMemStream_getsize(ktxStream* str, ktx_size_t* pSize) +{ + if (!str || !pSize) + return KTX_INVALID_VALUE; + + assert(str->type == eStreamTypeMemory); + + *pSize = str->data.mem->used_size; + return KTX_SUCCESS; +} + +/** + * @~English + * @brief Setup ktxMemStream function pointers. + */ +void +ktxMemStream_setup(ktxStream* str) +{ + str->type = eStreamTypeMemory; + str->read = ktxMemStream_read; + str->skip = ktxMemStream_skip; + str->write = ktxMemStream_write; + str->getpos = ktxMemStream_getpos; + str->setpos = ktxMemStream_setpos; + str->getsize = ktxMemStream_getsize; + str->destruct = ktxMemStream_destruct; +} + +/** + * @~English + * @brief Initialize a read-write ktxMemStream. + * + * Memory is allocated as data is written. The caller of this is + * responsible for freeing this memory unless @a freeOnDestruct + * is not KTX_FALSE. + * + * @param [in] str pointer to a ktxStream struct to initialize. + * @param [in] freeOnDestruct If not KTX_FALSE memory holding the data will + * be freed by the destructor. + * + * @return KTX_SUCCESS on success, other KTX_* enum values on error. + * + * @exception KTX_INVALID_VALUE @p str is @c NULL. + * @exception KTX_OUT_OF_MEMORY system failed to allocate sufficient memory. + */ +KTX_error_code ktxMemStream_construct(ktxStream* str, + ktx_bool_t freeOnDestruct) +{ + ktxMem* mem; + KTX_error_code result = KTX_SUCCESS; + + if (!str) + return KTX_INVALID_VALUE; + + result = ktxMem_create(&mem); + + if (KTX_SUCCESS == result) { + str->data.mem = mem; + ktxMemStream_setup(str); + str->closeOnDestruct = freeOnDestruct; + } + + return result; +} + +/** + * @~English + * @brief Initialize a read-only ktxMemStream. + * + * @param [in] str pointer to a ktxStream struct to initialize. + * @param [in] bytes pointer to an array of bytes containing the data. + * @param [in] numBytes size of array of data for ktxMemStream. + * + * @return KTX_SUCCESS on success, other KTX_* enum values on error. + * + * @exception KTX_INVALID_VALUE @p str or @p mem is @c NULL or @p numBytes + * is 0. + * or @p size is less than 0. + * @exception KTX_OUT_OF_MEMORY system failed to allocate sufficient memory. + */ +KTX_error_code ktxMemStream_construct_ro(ktxStream* str, + const ktx_uint8_t* bytes, + const ktx_size_t numBytes) +{ + ktxMem* mem; + KTX_error_code result = KTX_SUCCESS; + + if (!str || !bytes || numBytes == 0) + return KTX_INVALID_VALUE; + + result = ktxMem_create_ro(&mem, bytes, numBytes); + + if (KTX_SUCCESS == result) { + str->data.mem = mem; + ktxMemStream_setup(str); + str->closeOnDestruct = KTX_FALSE; + } + + return result; +} + +/** + * @~English + * @brief Free the memory used by a ktxMemStream. + * + * This only frees the memory used to store the data written to the stream, + * if the @c freeOnDestruct parameter to ktxMemStream_construct() was not + * @c KTX_FALSE. Otherwise it is the responsibility of the caller of + * ktxMemStream_construct() and a pointer to this memory should be retrieved + * using ktxMemStream_getdata() before calling this function. + * + * @sa ktxMemStream_construct, ktxMemStream_getdata. + * + * @param [in] str pointer to the ktxStream whose memory is + * to be freed. + */ +void +ktxMemStream_destruct(ktxStream* str) +{ + assert(str && str->type == eStreamTypeMemory); + + ktxMem_destroy(str->data.mem, str->closeOnDestruct); + str->data.mem = NULL; +} + diff --git a/thirdparty/libktx/lib/memstream.h b/thirdparty/libktx/lib/memstream.h new file mode 100644 index 000000000000..4ef8d59cd2ed --- /dev/null +++ b/thirdparty/libktx/lib/memstream.h @@ -0,0 +1,43 @@ +/* -*- tab-width: 4; -*- */ +/* vi: set sw=2 ts=4 expandtab: */ + +/* + * Copyright 2010-2020 The Khronos Group Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @internal + * @file + * @~English + * + * @brief Interface of ktxStream for memory. + * + * @author Maksim Kolesin + * @author Georg Kolling, Imagination Technology + * @author Mark Callow, HI Corporation + */ + +#ifndef MEMSTREAM_H +#define MEMSTREAM_H + +#include "ktx.h" + +/* + * Initialize a ktxStream to a ktxMemStream with internally + * allocated memory. Can be read or written. + */ +KTX_error_code ktxMemStream_construct(ktxStream* str, + ktx_bool_t freeOnDestruct); +/* + * Initialize a ktxStream to a read-only ktxMemStream reading + * from an array of bytes. + */ +KTX_error_code ktxMemStream_construct_ro(ktxStream* str, + const ktx_uint8_t* pBytes, + const ktx_size_t size); +void ktxMemStream_destruct(ktxStream* str); + +KTX_error_code ktxMemStream_getdata(ktxStream* str, ktx_uint8_t** ppBytes); + +#endif /* MEMSTREAM_H */ diff --git a/thirdparty/libktx/lib/swap.c b/thirdparty/libktx/lib/swap.c new file mode 100644 index 000000000000..3fdeb4f3a462 --- /dev/null +++ b/thirdparty/libktx/lib/swap.c @@ -0,0 +1,57 @@ +/* -*- tab-width: 4; -*- */ +/* vi: set sw=2 ts=4 expandtab: */ + +/* $Id: 02ea6de2d8db512ca3af08f48b98ab5f6c35e7e5 $ */ + +/* + * Copyright 2010-2020 The Khronos Group Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "ktx.h" + +/* + * SwapEndian16: Swaps endianness in an array of 16-bit values + */ +void +_ktxSwapEndian16(khronos_uint16_t* pData16, ktx_size_t count) +{ + for (ktx_size_t i = 0; i < count; ++i) + { + khronos_uint16_t x = *pData16; + *pData16++ = (x << 8) | (x >> 8); + } +} + +/* + * SwapEndian32: Swaps endianness in an array of 32-bit values + */ +void +_ktxSwapEndian32(khronos_uint32_t* pData32, ktx_size_t count) +{ + for (ktx_size_t i = 0; i < count; ++i) + { + khronos_uint32_t x = *pData32; + *pData32++ = (x << 24) | ((x & 0xFF00) << 8) | ((x & 0xFF0000) >> 8) | (x >> 24); + } +} + +/* + * SwapEndian364: Swaps endianness in an array of 32-bit values + */ +void +_ktxSwapEndian64(khronos_uint64_t* pData64, ktx_size_t count) +{ + for (ktx_size_t i = 0; i < count; ++i) + { + khronos_uint64_t x = *pData64; + *pData64++ = (x << 56) | ((x & 0xFF00) << 40) | ((x & 0xFF0000) << 24) + | ((x & 0xFF000000) << 8 ) | ((x & 0xFF00000000) >> 8) + | ((x & 0xFF0000000000) >> 24) + | ((x & 0xFF000000000000) << 40) | (x >> 56); + } +} + + + diff --git a/thirdparty/libktx/lib/texture.c b/thirdparty/libktx/lib/texture.c new file mode 100644 index 000000000000..35619a3e73f7 --- /dev/null +++ b/thirdparty/libktx/lib/texture.c @@ -0,0 +1,911 @@ +/* -*- tab-width: 4; -*- */ +/* vi: set sw=2 ts=4 expandtab: */ + +/* + * Copyright 2018-2020 Mark Callow. + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @internal + * @file writer.c + * @~English + * + * @brief ktxTexture implementation. + * + * @author Mark Callow, www.edgewise-consulting.com + */ + +#if defined(_WIN32) + #define _CRT_SECURE_NO_WARNINGS + #ifndef __cplusplus + #undef inline + #define inline __inline + #endif // __cplusplus +#endif + +#include +#include +#include +#include + +#include "ktx.h" +#include "ktxint.h" +#include "formatsize.h" +#include "filestream.h" +#include "memstream.h" +#include "texture1.h" +#include "texture2.h" +#include "unused.h" + +ktx_size_t ktxTexture_GetDataSize(ktxTexture* This); + +static ktx_uint32_t padRow(ktx_uint32_t* rowBytes); + +/** + * @memberof ktxTexture @private + * @~English + * @brief Construct (initialize) a ktxTexture base class instance. + * + * @param[in] This pointer to a ktxTexture-sized block of memory to + * initialize. + * @param[in] createInfo pointer to a ktxTextureCreateInfo struct with + * information describing the texture. + * @param[in] formatSize pointer to a ktxFormatSize giving size information + * about the texture's elements. + * + * @return KTX_SUCCESS on success, other KTX_* enum values on error. + * + * @exception KTX_INVALID_VALUE @c glInternalFormat in @p createInfo is not a + * valid OpenGL internal format value. + * @exception KTX_INVALID_VALUE @c numDimensions in @p createInfo is not 1, 2 + * or 3. + * @exception KTX_INVALID_VALUE One of base{Width,Height,Depth} in + * @p createInfo is 0. + * @exception KTX_INVALID_VALUE @c numFaces in @p createInfo is not 1 or 6. + * @exception KTX_INVALID_VALUE @c numLevels in @p createInfo is 0. + * @exception KTX_INVALID_OPERATION + * The base{Width,Height,Depth} specified + * in @p createInfo are inconsistent with + * @c numDimensions. + * @exception KTX_INVALID_OPERATION + * @p createInfo is requesting a 3D array or + * 3D cubemap texture. + * @exception KTX_INVALID_OPERATION + * @p createInfo is requesting a cubemap with + * non-square or non-2D images. + * @exception KTX_INVALID_OPERATION + * @p createInfo is requesting more mip levels + * than needed for the specified + * base{Width,Height,Depth}. + * @exception KTX_OUT_OF_MEMORY Not enough memory for the texture. + */ +KTX_error_code +ktxTexture_construct(ktxTexture* This, ktxTextureCreateInfo* createInfo, + ktxFormatSize* formatSize) +{ + DECLARE_PROTECTED(ktxTexture); + + memset(This, 0, sizeof(*This)); + This->_protected = (struct ktxTexture_protected*)malloc(sizeof(*prtctd)); + if (!This->_protected) + return KTX_OUT_OF_MEMORY; + prtctd = This->_protected; + memset(prtctd, 0, sizeof(*prtctd)); + memcpy(&prtctd->_formatSize, formatSize, sizeof(prtctd->_formatSize)); + + This->isCompressed = (formatSize->flags & KTX_FORMAT_SIZE_COMPRESSED_BIT); + + This->orientation.x = KTX_ORIENT_X_RIGHT; + This->orientation.y = KTX_ORIENT_Y_DOWN; + This->orientation.z = KTX_ORIENT_Z_OUT; + + /* Check texture dimensions. KTX files can store 8 types of textures: + * 1D, 2D, 3D, cube, and array variants of these. + */ + if (createInfo->numDimensions < 1 || createInfo->numDimensions > 3) + return KTX_INVALID_VALUE; + + if (createInfo->baseWidth == 0 || createInfo->baseHeight == 0 + || createInfo->baseDepth == 0) + return KTX_INVALID_VALUE; + + switch (createInfo->numDimensions) { + case 1: + if (createInfo->baseHeight > 1 || createInfo->baseDepth > 1) + return KTX_INVALID_OPERATION; + break; + + case 2: + if (createInfo->baseDepth > 1) + return KTX_INVALID_OPERATION; + break; + + case 3: + /* 3D array textures and 3D cubemaps are not supported by either + * OpenGL or Vulkan. + */ + if (createInfo->isArray || createInfo->numFaces != 1 + || createInfo->numLayers != 1) + return KTX_INVALID_OPERATION; + break; + } + This->numDimensions = createInfo->numDimensions; + This->baseWidth = createInfo->baseWidth; + This->baseDepth = createInfo->baseDepth; + This->baseHeight = createInfo->baseHeight; + + if (createInfo->numLayers == 0) + return KTX_INVALID_VALUE; + This->numLayers = createInfo->numLayers; + This->isArray = createInfo->isArray; + + if (createInfo->numFaces == 6) { + if (This->numDimensions != 2) { + /* cube map needs 2D faces */ + return KTX_INVALID_OPERATION; + } + if (createInfo->baseWidth != createInfo->baseHeight) { + /* cube maps require square images */ + return KTX_INVALID_OPERATION; + } + This->isCubemap = KTX_TRUE; + } else if (createInfo->numFaces != 1) { + /* numFaces must be either 1 or 6 */ + return KTX_INVALID_VALUE; + } + This->numFaces = createInfo->numFaces; + + /* Check number of mipmap levels */ + if (createInfo->numLevels == 0) + return KTX_INVALID_VALUE; + This->numLevels = createInfo->numLevels; + This->generateMipmaps = createInfo->generateMipmaps; + + if (createInfo->numLevels > 1) { + GLuint max_dim = MAX(MAX(createInfo->baseWidth, createInfo->baseHeight), + createInfo->baseDepth); + if (max_dim < ((GLuint)1 << (This->numLevels - 1))) + { + /* Can't have more mip levels than 1 + log2(max(width, height, depth)) */ + return KTX_INVALID_OPERATION; + } + } + + ktxHashList_Construct(&This->kvDataHead); + return KTX_SUCCESS; +} + +/** + * @memberof ktxTexture @private + * @~English + * @brief Construct (initialize) the part of a ktxTexture base class that is + * not related to the stream contents. + * + * @param[in] This pointer to a ktxTexture-sized block of memory to + * initialize. + * + * @return KTX_SUCCESS on success, other KTX_* enum values on error. + */ +KTX_error_code +ktxTexture_constructFromStream(ktxTexture* This, ktxStream* pStream, + ktxTextureCreateFlags createFlags) +{ + ktxStream* stream; + UNUSED(createFlags); // Reference to keep compiler happy. + + assert(This != NULL); + assert(pStream->data.mem != NULL); + assert(pStream->type == eStreamTypeFile + || pStream->type == eStreamTypeMemory + || pStream->type == eStreamTypeCustom); + + This->_protected = (struct ktxTexture_protected *) + malloc(sizeof(struct ktxTexture_protected)); + stream = ktxTexture_getStream(This); + // Copy stream info into struct for later use. + *stream = *pStream; + + This->orientation.x = KTX_ORIENT_X_RIGHT; + This->orientation.y = KTX_ORIENT_Y_DOWN; + This->orientation.z = KTX_ORIENT_Z_OUT; + + return KTX_SUCCESS; +} + + +/** + * @memberof ktxTexture @private + * @~English + * @brief Free the memory associated with the texture contents + * + * @param[in] This pointer to the ktxTextureInt whose texture contents are + * to be freed. + */ +void +ktxTexture_destruct(ktxTexture* This) +{ + ktxStream stream = *(ktxTexture_getStream(This)); + + if (stream.data.file != NULL) + stream.destruct(&stream); + if (This->kvDataHead != NULL) + ktxHashList_Destruct(&This->kvDataHead); + if (This->kvData != NULL) + free(This->kvData); + if (This->pData != NULL) + free(This->pData); + free(This->_protected); +} + + +/** + * @defgroup reader Reader + * @brief Read KTX-formatted data. + * @{ + */ + +typedef enum { KTX1, KTX2 } ktxFileType_; +typedef union { + KTX_header ktx; + KTX_header2 ktx2; +} ktxHeaderUnion_; + +/** + * @memberof ktxTexture @private + * @~English + * @brief Determine if stream data is KTX1 or KTX2. + * + * @param pStream pointer to the ktxStream to examine. + * @param pFileType pointer to a ktxFileType enum where the type of the data + * will be written. + * @param pHeader pointer to a ktxHeaderUnion where the header info. will be + * written. + */ +static KTX_error_code +ktxDetermineFileType_(ktxStream* pStream, ktxFileType_* pFileType, + ktxHeaderUnion_* pHeader) +{ + ktx_uint8_t ktx_ident_ref[12] = KTX_IDENTIFIER_REF; + ktx_uint8_t ktx2_ident_ref[12] = KTX2_IDENTIFIER_REF; + KTX_error_code result; + + assert(pStream != NULL && pFileType != NULL); + assert(pStream->data.mem != NULL); + assert(pStream->type == eStreamTypeFile + || pStream->type == eStreamTypeMemory + || pStream->type == eStreamTypeCustom); + + result = pStream->read(pStream, pHeader, sizeof(ktx2_ident_ref)); + if (result == KTX_SUCCESS) { +#if BIG_ENDIAN + // byte swap the heaader fields +#endif + // Compare identifier, is this a KTX or KTX2 file? + if (!memcmp(pHeader->ktx.identifier, ktx_ident_ref, 12)) { + *pFileType = KTX1; + } else if (!memcmp(pHeader->ktx2.identifier, ktx2_ident_ref, 12)) { + *pFileType = KTX2; + } else { + return KTX_UNKNOWN_FILE_FORMAT; + } + // Read rest of header. + if (*pFileType == KTX1) { + // Read rest of header. + result = pStream->read(pStream, &pHeader->ktx.endianness, + KTX_HEADER_SIZE - sizeof(ktx_ident_ref)); + } else { + result = pStream->read(pStream, &pHeader->ktx2.vkFormat, + KTX2_HEADER_SIZE - sizeof(ktx2_ident_ref)); + } + } + return result; +} + +/** + * @memberof ktxTexture + * @~English + * @brief Construct (initialize) a ktx1 or ktx2 texture according to the stream + * data. + * + * @copydetails ktxTexture_CreateFromStdioStream + */ +KTX_error_code +ktxTexture_CreateFromStream(ktxStream* pStream, + ktxTextureCreateFlags createFlags, + ktxTexture** newTex) +{ + ktxHeaderUnion_ header; + ktxFileType_ fileType; + KTX_error_code result; + ktxTexture* tex; + + result = ktxDetermineFileType_(pStream, &fileType, &header); + if (result != KTX_SUCCESS) + return result; + + if (fileType == KTX1) { + ktxTexture1* tex1 = (ktxTexture1*)malloc(sizeof(ktxTexture1)); + if (tex1 == NULL) + return KTX_OUT_OF_MEMORY; + memset(tex1, 0, sizeof(ktxTexture1)); + result = ktxTexture1_constructFromStreamAndHeader(tex1, pStream, + &header.ktx, + createFlags); + tex = ktxTexture(tex1); + } else { + ktxTexture2* tex2 = (ktxTexture2*)malloc(sizeof(ktxTexture2)); + if (tex2 == NULL) + return KTX_OUT_OF_MEMORY; + memset(tex2, 0, sizeof(ktxTexture2)); + result = ktxTexture2_constructFromStreamAndHeader(tex2, pStream, + &header.ktx2, + createFlags); + tex = ktxTexture(tex2); + } + + if (result == KTX_SUCCESS) + *newTex = (ktxTexture*)tex; + else { + free(tex); + *newTex = NULL; + } + return result; +} + +/** + * @memberof ktxTexture + * @~English + * @brief Create a ktxTexture1 or ktxTexture2 from a stdio stream according + * to the stream data. + * + * @copydetails ktxTexture1_CreateFromStdioStream() + */ +KTX_error_code +ktxTexture_CreateFromStdioStream(FILE* stdioStream, + ktxTextureCreateFlags createFlags, + ktxTexture** newTex) +{ + ktxStream stream; + KTX_error_code result; + + if (stdioStream == NULL || newTex == NULL) + return KTX_INVALID_VALUE; + + result = ktxFileStream_construct(&stream, stdioStream, KTX_FALSE); + if (result == KTX_SUCCESS) { + result = ktxTexture_CreateFromStream(&stream, createFlags, newTex); + } + return result; +} + +/** + * @memberof ktxTexture + * @~English + * @brief Create a ktxTexture1 or ktxTexture2 from a named KTX file according + * to the file contents. + * + * The address of a newly created ktxTexture reflecting the contents of the + * file is written to the location pointed at by @p newTex. + * + * The create flag KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT should not be set, + * if the ktxTexture is ultimately to be uploaded to OpenGL or Vulkan. This + * will minimize memory usage by allowing, for example, loading the images + * directly from the source into a Vulkan staging buffer. + * + * The create flag KTX_TEXTURE_CREATE_RAW_KVDATA_BIT should not be used. It is + * provided solely to enable implementation of the @e libktx v1 API on top of + * ktxTexture. + * + * @param[in] filename pointer to a char array containing the file name. + * @param[in] createFlags bitmask requesting specific actions during creation. + * @param[in,out] newTex pointer to a location in which store the address of + * the newly created texture. + * + * @return KTX_SUCCESS on success, other KTX_* enum values on error. + + * @exception KTX_FILE_OPEN_FAILED The file could not be opened. + * @exception KTX_INVALID_VALUE @p filename is @c NULL. + * + * For other exceptions, see ktxTexture_CreateFromStdioStream(). + */ +KTX_error_code +ktxTexture_CreateFromNamedFile(const char* const filename, + ktxTextureCreateFlags createFlags, + ktxTexture** newTex) +{ + KTX_error_code result; + ktxStream stream; + FILE* file; + + if (filename == NULL || newTex == NULL) + return KTX_INVALID_VALUE; + + file = fopen(filename, "rb"); + if (!file) + return KTX_FILE_OPEN_FAILED; + + result = ktxFileStream_construct(&stream, file, KTX_TRUE); + if (result == KTX_SUCCESS) { + result = ktxTexture_CreateFromStream(&stream, createFlags, newTex); + } + return result; +} + +/** + * @memberof ktxTexture + * @~English + * @brief Create a ktxTexture1 or ktxTexture2 from KTX-formatted data in memory + * according to the data contents. + * + * The address of a newly created ktxTexture reflecting the contents of the + * serialized KTX data is written to the location pointed at by @p newTex. + * + * The create flag KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT should not be set, + * if the ktxTexture is ultimately to be uploaded to OpenGL or Vulkan. This + * will minimize memory usage by allowing, for example, loading the images + * directly from the source into a Vulkan staging buffer. + * + * The create flag KTX_TEXTURE_CREATE_RAW_KVDATA_BIT should not be used. It is + * provided solely to enable implementation of the @e libktx v1 API on top of + * ktxTexture. + * + * @param[in] bytes pointer to the memory containing the serialized KTX data. + * @param[in] size length of the KTX data in bytes. + * @param[in] createFlags bitmask requesting specific actions during creation. + * @param[in,out] newTex pointer to a location in which store the address of + * the newly created texture. + * + * @return KTX_SUCCESS on success, other KTX_* enum values on error. + * + * @exception KTX_INVALID_VALUE Either @p bytes is NULL or @p size is 0. + * + * For other exceptions, see ktxTexture_CreateFromStdioStream(). + */ +KTX_error_code +ktxTexture_CreateFromMemory(const ktx_uint8_t* bytes, ktx_size_t size, + ktxTextureCreateFlags createFlags, + ktxTexture** newTex) +{ + KTX_error_code result; + ktxStream stream; + + if (bytes == NULL || newTex == NULL || size == 0) + return KTX_INVALID_VALUE; + + result = ktxMemStream_construct_ro(&stream, bytes, size); + if (result == KTX_SUCCESS) { + result = ktxTexture_CreateFromStream(&stream, createFlags, newTex); + } + return result;} + + +/** + * @memberof ktxTexture + * @~English + * @brief Return a pointer to the texture image data. + * + * @param[in] This pointer to the ktxTexture object of interest. + */ +ktx_uint8_t* +ktxTexture_GetData(ktxTexture* This) +{ + return This->pData; +} + +/** + * @memberof ktxTexture + * @~English + * @brief Return the total size of the texture image data in bytes. + * + * For a ktxTexture2 with supercompressionScheme != KTX_SS_NONE this will + * return the deflated size of the data. + * + * @param[in] This pointer to the ktxTexture object of interest. + */ +ktx_size_t +ktxTexture_GetDataSize(ktxTexture* This) +{ + assert(This != NULL); + return This->dataSize; +} + +/** + * @memberof ktxTexture + * @~English + * @brief Return the size in bytes of an elements of a texture's + * images. + * + * For uncompressed textures an element is one texel. For compressed + * textures it is one block. + * + * @param[in] This pointer to the ktxTexture object of interest. + */ +ktx_uint32_t +ktxTexture_GetElementSize(ktxTexture* This) +{ + assert (This != NULL); + + return (This->_protected->_formatSize.blockSizeInBits / 8); +} + +/** + * @memberof ktxTexture @private + * @~English + * @brief Calculate & return the size in bytes of an image at the specified + * mip level. + * + * For arrays, this is the size of layer, for cubemaps, the size of a face + * and for 3D textures, the size of a depth slice. + * + * The size reflects the padding of each row to KTX_GL_UNPACK_ALIGNMENT. + * + * @param[in] This pointer to the ktxTexture object of interest. + * @param[in] level level of interest. + * @param[in] fv enum specifying format version for which to calculate + * image size. + */ +ktx_size_t +ktxTexture_calcImageSize(ktxTexture* This, ktx_uint32_t level, + ktxFormatVersionEnum fv) +{ + DECLARE_PROTECTED(ktxTexture); + struct blockCount { + ktx_uint32_t x, y; + } blockCount; + ktx_uint32_t blockSizeInBytes; + ktx_uint32_t rowBytes; + + assert (This != NULL); + + float levelWidth = (float)(This->baseWidth >> level); + float levelHeight = (float)(This->baseHeight >> level); + // Round up to next whole block. We can't use KTX_PADN because some of + // the block sizes are not powers of 2. + blockCount.x + = (ktx_uint32_t)ceilf(levelWidth / prtctd->_formatSize.blockWidth); + blockCount.y + = (ktx_uint32_t)ceilf(levelHeight / prtctd->_formatSize.blockHeight); + blockCount.x = MAX(prtctd->_formatSize.minBlocksX, blockCount.x); + blockCount.y = MAX(prtctd->_formatSize.minBlocksX, blockCount.y); + + blockSizeInBytes = prtctd->_formatSize.blockSizeInBits / 8; + + if (prtctd->_formatSize.flags & KTX_FORMAT_SIZE_COMPRESSED_BIT) { + assert(This->isCompressed); + return blockCount.x * blockCount.y * blockSizeInBytes; + } else { + assert(prtctd->_formatSize.blockWidth == 1U + && prtctd->_formatSize.blockHeight == 1U + && prtctd->_formatSize.blockDepth == 1U); + rowBytes = blockCount.x * blockSizeInBytes; + if (fv == KTX_FORMAT_VERSION_ONE) + (void)padRow(&rowBytes); + return rowBytes * blockCount.y; + } +} + +/** + * @memberof ktxTexture + * @~English + * @brief Iterate over the levels or faces in a ktxTexture object. + * + * Blocks of image data are passed to an application-supplied callback + * function. This is not a strict per-image iteration. Rather it reflects how + * OpenGL needs the images. For most textures the block of data includes all + * images of a mip level which implies all layers of an array. However, for + * non-array cube map textures the block is a single face of the mip level, + * i.e the callback is called once for each face. + * + * This function works even if @p This->pData == 0 so it can be used to + * obtain offsets and sizes for each level by callers who have loaded the data + * externally. + * + * @param[in] This pointer to the ktxTexture object of interest. + * @param[in,out] iterCb the address of a callback function which is called + * with the data for each image block. + * @param[in,out] userdata the address of application-specific data which is + * passed to the callback along with the image data. + * + * @return KTX_SUCCESS on success, other KTX_* enum values on error. The + * following are returned directly by this function. @p iterCb may + * return these for other causes or may return additional errors. + * + * @exception KTX_FILE_DATA_ERROR Mip level sizes are increasing not + * decreasing + * @exception KTX_INVALID_VALUE @p This is @c NULL or @p iterCb is @c NULL. + * + */ +KTX_error_code +ktxTexture_IterateLevelFaces(ktxTexture* This, PFNKTXITERCB iterCb, + void* userdata) +{ + ktx_uint32_t miplevel; + KTX_error_code result = KTX_SUCCESS; + + if (This == NULL) + return KTX_INVALID_VALUE; + + if (iterCb == NULL) + return KTX_INVALID_VALUE; + + for (miplevel = 0; miplevel < This->numLevels; ++miplevel) + { + ktx_uint32_t faceLodSize; + ktx_uint32_t face; + ktx_uint32_t innerIterations; + GLsizei width, height, depth; + + /* Array textures have the same number of layers at each mip level. */ + width = MAX(1, This->baseWidth >> miplevel); + height = MAX(1, This->baseHeight >> miplevel); + depth = MAX(1, This->baseDepth >> miplevel); + + faceLodSize = (ktx_uint32_t)ktxTexture_calcFaceLodSize( + This, miplevel); + + /* All array layers are passed in a group because that is how + * GL & Vulkan need them. Hence no + * for (layer = 0; layer < This->numLayers) + */ + if (This->isCubemap && !This->isArray) + innerIterations = This->numFaces; + else + innerIterations = 1; + for (face = 0; face < innerIterations; ++face) + { + /* And all z_slices are also passed as a group hence no + * for (slice = 0; slice < This->depth) + */ + ktx_size_t offset; + + ktxTexture_GetImageOffset(This, miplevel, 0, face, &offset); + result = iterCb(miplevel, face, + width, height, depth, + faceLodSize, This->pData + offset, userdata); + + if (result != KTX_SUCCESS) + break; + } + } + + return result; +} + +/** + * @internal + * @brief Calculate and apply the padding needed to comply with + * KTX_GL_UNPACK_ALIGNMENT. + * + * For uncompressed textures, KTX format specifies KTX_GL_UNPACK_ALIGNMENT = 4. + * + * @param[in,out] rowBytes pointer to variable containing the packed no. of + * bytes in a row. The no. of bytes after padding + * is written into this location. + * @return the no. of bytes of padding. + */ +static ktx_uint32_t +padRow(ktx_uint32_t* rowBytes) +{ + ktx_uint32_t rowPadding; + + assert (rowBytes != NULL); + + rowPadding = _KTX_PAD_UNPACK_ALIGN_LEN(*rowBytes); + *rowBytes += rowPadding; + return rowPadding; +} + +/** + * @memberof ktxTexture @private + * @~English + * @brief Calculate the size of an array layer at the specified mip level. + * + * The size of a layer is the size of an image * either the number of faces + * or the number of depth slices. This is the size of a layer as needed to + * find the offset within the array of images of a level and layer so the size + * reflects any @c cubePadding. + * + * @param[in] This pointer to the ktxTexture object of interest. + * @param[in] level level whose layer size to return. + * + * @return the layer size in bytes. + */ +ktx_size_t +ktxTexture_layerSize(ktxTexture* This, ktx_uint32_t level, + ktxFormatVersionEnum fv) +{ + /* + * As there are no 3D cubemaps, the image's z block count will always be + * 1 for cubemaps and numFaces will always be 1 for 3D textures so the + * multiply is safe. 3D cubemaps, if they existed, would require + * imageSize * (blockCount.z + This->numFaces); + */ + DECLARE_PROTECTED(ktxTexture); + ktx_uint32_t blockCountZ; + ktx_size_t imageSize, layerSize; + + assert (This != NULL); + + blockCountZ = MAX(1, (This->baseDepth / prtctd->_formatSize.blockDepth) >> level); + imageSize = ktxTexture_calcImageSize(This, level, fv); + layerSize = imageSize * blockCountZ; + if (fv == KTX_FORMAT_VERSION_ONE && KTX_GL_UNPACK_ALIGNMENT != 4) { + if (This->isCubemap && !This->isArray) { + /* cubePadding. NOTE: this adds padding after the last face too. */ + layerSize += _KTX_PAD4(layerSize); + } + } + return layerSize * This->numFaces; +} + +/** + * @memberof ktxTexture @private + * @~English + * @brief Calculate the size of the specified mip level. + * + * The size of a level is the size of a layer * the number of layers. + * + * @param[in] This pointer to the ktxTexture object of interest. + * @param[in] level level whose layer size to return. + * + * @return the level size in bytes. + */ +ktx_size_t +ktxTexture_calcLevelSize(ktxTexture* This, ktx_uint32_t level, + ktxFormatVersionEnum fv) +{ + assert (This != NULL); + assert (level < This->numLevels); + return ktxTexture_layerSize(This, level, fv) * This->numLayers; +} + +/** + * @memberof ktxTexture @private + * @~English + * @brief Calculate the faceLodSize of the specified mip level. + * + * The faceLodSize of a level for most textures is the size of a level. For + * non-array cube map textures is the size of a face. This is the size that + * must be provided to OpenGL when uploading textures. Faces get uploaded 1 + * at a time while all layers of an array or all slices of a 3D texture are + * uploaded together. + * + * @param[in] This pointer to the ktxTexture object of interest. + * @param[in] level level whose layer size to return. + * + * @return the faceLodSize size in bytes. + */ +ktx_size_t +ktxTexture_doCalcFaceLodSize(ktxTexture* This, ktx_uint32_t level, + ktxFormatVersionEnum fv) +{ + /* + * For non-array cubemaps this is the size of a face. For everything + * else it is the size of the level. + */ + if (This->isCubemap && !This->isArray) + return ktxTexture_calcImageSize(This, level, fv); + else + return ktxTexture_calcLevelSize(This, level, fv); +} + + +/** + * @memberof ktxTexture @private + * @~English + * @brief Return the number of bytes needed to store all the image data for + * a ktxTexture. + * + * The caclulated size does not include space for storing the @c imageSize + * fields of each mip level. + * + * @param[in] This pointer to the ktxTexture object of interest. + * @param[in] fv enum specifying format version for which to calculate + * image size. + * + * @return the data size in bytes. + */ +ktx_size_t +ktxTexture_calcDataSizeTexture(ktxTexture* This) +{ + assert (This != NULL); + return ktxTexture_calcDataSizeLevels(This, This->numLevels); +} + +/** + * @memberof ktxTexture @private + * @~English + * @brief Get information about rows of an uncompresssed texture image at a + * specified level. + * + * For an image at @p level of a ktxTexture provide the number of rows, the + * packed (unpadded) number of bytes in a row and the padding necessary to + * comply with KTX_GL_UNPACK_ALIGNMENT. + * + * @param[in] This pointer to the ktxTexture object of interest. + * @param[in] level level of interest. + * @param[in,out] numRows pointer to location to store the number of rows. + * @param[in,out] pRowLengthBytes pointer to location to store number of bytes + * in a row. + * @param[in.out] pRowPadding pointer to location to store the number of bytes + * of padding. + */ +void +ktxTexture_rowInfo(ktxTexture* This, ktx_uint32_t level, + ktx_uint32_t* numRows, ktx_uint32_t* pRowLengthBytes, + ktx_uint32_t* pRowPadding) +{ + DECLARE_PROTECTED(ktxTexture); + struct blockCount { + ktx_uint32_t x; + } blockCount; + + assert (This != NULL); + + assert(!This->isCompressed); + assert(prtctd->_formatSize.blockWidth == 1U + && prtctd->_formatSize.blockHeight == 1U + && prtctd->_formatSize.blockDepth == 1U); + + blockCount.x = MAX(1, (This->baseWidth / prtctd->_formatSize.blockWidth) >> level); + *numRows = MAX(1, (This->baseHeight / prtctd->_formatSize.blockHeight) >> level); + + *pRowLengthBytes = blockCount.x * prtctd->_formatSize.blockSizeInBits / 8; + *pRowPadding = padRow(pRowLengthBytes); +} + +/** + * @memberof ktxTexture + * @~English + * @brief Return pitch betweeb rows of a texture image level in bytes. + * + * For uncompressed textures the pitch is the number of bytes between + * rows of texels. For compressed textures it is the number of bytes + * between rows of blocks. The value is padded to GL_UNPACK_ALIGNMENT, + * if necessary. For all currently known compressed formats padding + * will not be necessary. + * + * @param[in] This pointer to the ktxTexture object of interest. + * @param[in] level level of interest. + * + * @return the row pitch in bytes. + */ + ktx_uint32_t + ktxTexture_GetRowPitch(ktxTexture* This, ktx_uint32_t level) + { + DECLARE_PROTECTED(ktxTexture) + struct blockCount { + ktx_uint32_t x; + } blockCount; + ktx_uint32_t pitch; + + blockCount.x = MAX(1, (This->baseWidth / prtctd->_formatSize.blockWidth) >> level); + pitch = blockCount.x * prtctd->_formatSize.blockSizeInBits / 8; + (void)padRow(&pitch); + + return pitch; + } + +/** + * @memberof ktxTexture @private + * @~English + * @brief Query if a ktxTexture has an active stream. + * + * Tests if a ktxTexture has unread image data. The internal stream is closed + * once all the images have been read. + * + * @param[in] This pointer to the ktxTexture object of interest. + * + * @return KTX_TRUE if there is an active stream, KTX_FALSE otherwise. + */ +ktx_bool_t +ktxTexture_isActiveStream(ktxTexture* This) +{ + assert(This != NULL); + ktxStream* stream = ktxTexture_getStream(This); + return stream->data.file != NULL; +} + +/** @} */ + diff --git a/thirdparty/libktx/lib/texture.h b/thirdparty/libktx/lib/texture.h new file mode 100644 index 000000000000..e415a09d6a44 --- /dev/null +++ b/thirdparty/libktx/lib/texture.h @@ -0,0 +1,107 @@ +/* -*- tab-width: 4; -*- */ +/* vi: set sw=2 ts=4 expandtab textwidth=70: */ + +/* + * Copyright 2019-2020 The Khronos Group Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @internal + * @file texture.h + * @~English + * + * @brief Declare internal ktxTexture functions for sharing between + * compilation units. + * + * These functions are private and should not be used outside the library. + */ + +#ifndef _TEXTURE_H_ +#define _TEXTURE_H_ + +#include "ktx.h" +#include "formatsize.h" + +#define DECLARE_PRIVATE(class) class ## _private* private = This->_private +#define DECLARE_PROTECTED(class) class ## _protected* prtctd = This->_protected; + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + KTX_FORMAT_VERSION_ONE = 1, + KTX_FORMAT_VERSION_TWO = 2 +} ktxFormatVersionEnum; + +typedef ktx_size_t (* PFNCALCDATASIZELEVELS)(ktxTexture* This, + ktx_uint32_t levels); +typedef ktx_size_t (* PFNCALCFACELODSIZE)(ktxTexture* This, ktx_uint32_t level); +typedef ktx_size_t (* PFNCALCLEVELOFFSET)(ktxTexture* This, ktx_uint32_t level); +typedef struct ktxTexture_vtblInt { + PFNCALCDATASIZELEVELS calcDataSizeLevels; + PFNCALCFACELODSIZE calcFaceLodSize; + PFNCALCLEVELOFFSET calcLevelOffset; +} ktxTexture_vtblInt; + +#define ktxTexture_calcDataSizeLevels(This, levels) \ + This->_protected->_vtbl.calcDataSizeLevels(This, levels); +#define ktxTexture_calcFaceLodSize(This, level) \ + This->_protected->_vtbl.calcFaceLodSize(This, level); +#define ktxTexture_calcLevelOffset(This, level) \ + This->_protected->_vtbl.calcLevelOffset(This, level); + +/** + * @memberof ktxTexture + * @~English + * + * @brief protected members of ktxTexture. + */ +typedef struct ktxTexture_protected { + ktxTexture_vtblInt _vtbl; + ktxFormatSize _formatSize; + ktx_uint32_t _typeSize; + ktxStream _stream; +} ktxTexture_protected; + +#define ktxTexture_getStream(t) ((ktxStream*)(&(t)->_protected->_stream)) +#define ktxTexture1_getStream(t1) ktxTexture_getStream((ktxTexture*)t1) +#define ktxTexture2_getStream(t2) ktxTexture_getStream((ktxTexture*)t2) + +KTX_error_code +ktxTexture_iterateLoadedImages(ktxTexture* This, PFNKTXITERCB iterCb, + void* userdata); +KTX_error_code +ktxTexture_iterateSourceImages(ktxTexture* This, PFNKTXITERCB iterCb, + void* userdata); + +ktx_size_t ktxTexture_calcDataSizeTexture(ktxTexture* This); +ktx_size_t ktxTexture_calcImageSize(ktxTexture* This, ktx_uint32_t level, + ktxFormatVersionEnum fv); +ktx_bool_t ktxTexture_isActiveStream(ktxTexture* This); +ktx_size_t ktxTexture_calcLevelSize(ktxTexture* This, ktx_uint32_t level, + ktxFormatVersionEnum fv); +ktx_size_t ktxTexture_doCalcFaceLodSize(ktxTexture* This, ktx_uint32_t level, + ktxFormatVersionEnum fv); +ktx_size_t ktxTexture_layerSize(ktxTexture* This, ktx_uint32_t level, + ktxFormatVersionEnum fv); +void ktxTexture_rowInfo(ktxTexture* This, ktx_uint32_t level, + ktx_uint32_t* numRows, ktx_uint32_t* rowBytes, + ktx_uint32_t* rowPadding); +KTX_error_code +ktxTexture_construct(ktxTexture* This, ktxTextureCreateInfo* createInfo, + ktxFormatSize* formatSize); + +KTX_error_code +ktxTexture_constructFromStream(ktxTexture* This, ktxStream* pStream, + ktxTextureCreateFlags createFlags); + +void +ktxTexture_destruct(ktxTexture* This); + +#ifdef __cplusplus +} +#endif + +#endif /* _TEXTURE_H_ */ diff --git a/thirdparty/libktx/lib/texture1.c b/thirdparty/libktx/lib/texture1.c new file mode 100644 index 000000000000..8420f402b290 --- /dev/null +++ b/thirdparty/libktx/lib/texture1.c @@ -0,0 +1,1459 @@ +/* -*- tab-width: 4; -*- */ +/* vi: set sw=2 ts=4 expandtab: */ + +/* + * Copyright 2019-2020 The Khronos Group Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @internal + * @file texture2.c + * @~English + * + * @brief ktxTexture1 implementation. Support for KTX format. + * + * @author Mark Callow, www.edgewise-consulting.com + */ + +#if defined(_WIN32) +#define _CRT_SECURE_NO_WARNINGS +#endif + +#include +#include + +#include "dfdutils/dfd.h" +#include "ktx.h" +#include "ktxint.h" +#include "filestream.h" +#include "memstream.h" +#include "texture1.h" +#include "unused.h" +#include "gl_format.h" + +typedef struct ktxTexture1_private { + ktx_bool_t _needSwap; +} ktxTexture1_private; + +struct ktxTexture_vtbl ktxTexture1_vtbl; +struct ktxTexture_vtblInt ktxTexture1_vtblInt; + +static KTX_error_code +ktxTexture1_constructCommon(ktxTexture1* This) +{ + assert(This != NULL); + + This->classId = ktxTexture1_c; + This->vtbl = &ktxTexture1_vtbl; + This->_protected->_vtbl = ktxTexture1_vtblInt; + This->_private = (ktxTexture1_private*)malloc(sizeof(ktxTexture1_private)); + if (This->_private == NULL) { + return KTX_OUT_OF_MEMORY; + } + memset(This->_private, 0, sizeof(*This->_private)); + + return KTX_SUCCESS; +} + +/** + * @memberof ktxTexture1 @private + * @copydoc ktxTexture2_construct + */ +static KTX_error_code +ktxTexture1_construct(ktxTexture1* This, ktxTextureCreateInfo* createInfo, + ktxTextureCreateStorageEnum storageAllocation) +{ + ktxTexture_protected* prtctd; + ktxFormatSize formatSize; + GLuint typeSize; + GLenum glFormat; + KTX_error_code result; + + memset(This, 0, sizeof(*This)); + + This->glInternalformat = createInfo->glInternalformat; + glGetFormatSize(This->glInternalformat, &formatSize); + if (formatSize.blockSizeInBits == 0) { + // Most likely a deprecated legacy format. + return KTX_UNSUPPORTED_TEXTURE_TYPE; + } + glFormat= glGetFormatFromInternalFormat(createInfo->glInternalformat); + if (glFormat == GL_INVALID_VALUE) { + return KTX_INVALID_VALUE; + } + result = ktxTexture_construct(ktxTexture(This), createInfo, &formatSize); + if (result != KTX_SUCCESS) + return result; + + result = ktxTexture1_constructCommon(This); + if (result != KTX_SUCCESS) + return result; + prtctd = This->_protected; + + This->isCompressed + = (formatSize.flags & KTX_FORMAT_SIZE_COMPRESSED_BIT); + if (This->isCompressed) { + This->glFormat = 0; + This->glBaseInternalformat = glFormat; + This->glType = 0; + prtctd->_typeSize = 1; + } else { + This->glBaseInternalformat = This->glFormat = glFormat; + This->glType + = glGetTypeFromInternalFormat(createInfo->glInternalformat); + if (This->glType == GL_INVALID_VALUE) { + result = KTX_INVALID_VALUE; + goto cleanup; + } + typeSize = glGetTypeSizeFromType(This->glType); + assert(typeSize != GL_INVALID_VALUE); + + /* Do some sanity checking */ + if (typeSize != 1 && + typeSize != 2 && + typeSize != 4) + { + /* Only 8, 16, and 32-bit types are supported for byte-swapping. + * See UNPACK_SWAP_BYTES & table 8.4 in the OpenGL 4.4 spec. + */ + result = KTX_INVALID_VALUE; + goto cleanup; + } + prtctd->_typeSize = typeSize; + } + + if (storageAllocation == KTX_TEXTURE_CREATE_ALLOC_STORAGE) { + This->dataSize + = ktxTexture_calcDataSizeTexture(ktxTexture(This)); + This->pData = malloc(This->dataSize); + if (This->pData == NULL) { + result = KTX_OUT_OF_MEMORY; + goto cleanup; + } + } + return result; + +cleanup: + ktxTexture1_destruct(This); + ktxTexture_destruct(ktxTexture(This)); + return result; +} + +/** + * @memberof ktxTexture1 @private + * @brief Construct a ktxTexture1 from a ktxStream reading from a KTX source. + * + * The KTX header, that must have been read prior to calling this, is passed + * to the function. + * + * The stream object is copied into the constructed ktxTexture1. + * + * The create flag KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT should not be set, + * if the ktxTexture1 is ultimately to be uploaded to OpenGL or Vulkan. This + * will minimize memory usage by allowing, for example, loading the images + * directly from the source into a Vulkan staging buffer. + * + * The create flag KTX_TEXTURE_CREATE_RAW_KVDATA_BIT should not be used. It is + * provided solely to enable implementation of the @e libktx v1 API on top of + * ktxTexture1. + * + * @param[in] This pointer to a ktxTexture1-sized block of memory to + * initialize. + * @param[in] pStream pointer to the stream to read. + * @param[in] pHeader pointer to a KTX header that has already been read from + * the stream. + * @param[in] createFlags bitmask requesting specific actions during creation. + * + * @return KTX_SUCCESS on success, other KTX_* enum values on error. + * + * @exception KTX_FILE_DATA_ERROR + * Source data is inconsistent with the KTX + * specification. + * @exception KTX_FILE_READ_ERROR + * An error occurred while reading the source. + * @exception KTX_FILE_UNEXPECTED_EOF + * Not enough data in the source. + * @exception KTX_OUT_OF_MEMORY Not enough memory to load either the images or + * the key-value data. + * @exception KTX_UNKNOWN_FILE_FORMAT + * The source is not in KTX format. + * @exception KTX_UNSUPPORTED_TEXTURE_TYPE + * The source describes a texture type not + * supported by OpenGL or Vulkan, e.g, a 3D array. + */ +KTX_error_code +ktxTexture1_constructFromStreamAndHeader(ktxTexture1* This, ktxStream* pStream, + KTX_header* pHeader, + ktxTextureCreateFlags createFlags) +{ + ktxTexture1_private* private; + KTX_error_code result; + KTX_supplemental_info suppInfo; + ktxStream* stream; + ktx_off_t pos; + ktx_size_t size; + ktxFormatSize formatSize; + + assert(pHeader != NULL && pStream != NULL); + + memset(This, 0, sizeof(*This)); + result = ktxTexture_constructFromStream(ktxTexture(This), pStream, createFlags); + if (result != KTX_SUCCESS) + return result; + result = ktxTexture1_constructCommon(This); + if (result != KTX_SUCCESS) { + ktxTexture_destruct(ktxTexture(This)); + return result; + } + + private = This->_private; + stream = ktxTexture1_getStream(This); + + result = ktxCheckHeader1_(pHeader, &suppInfo); + if (result != KTX_SUCCESS) + goto cleanup; + + /* + * Initialize from pHeader info. + */ + This->glFormat = pHeader->glFormat; + This->glInternalformat = pHeader->glInternalformat; + This->glType = pHeader->glType; + glGetFormatSize(This->glInternalformat, &formatSize); + if (formatSize.blockSizeInBits == 0) { + // Most likely a deprecated legacy format. + result = KTX_UNSUPPORTED_TEXTURE_TYPE; + goto cleanup; + } + This->_protected->_formatSize = formatSize; + This->glBaseInternalformat = pHeader->glBaseInternalformat; + // Can these be done by a ktxTexture_constructFromStream? + This->numDimensions = suppInfo.textureDimension; + This->baseWidth = pHeader->pixelWidth; + assert(suppInfo.textureDimension > 0 && suppInfo.textureDimension < 4); + switch (suppInfo.textureDimension) { + case 1: + This->baseHeight = This->baseDepth = 1; + break; + case 2: + This->baseHeight = pHeader->pixelHeight; + This->baseDepth = 1; + break; + case 3: + This->baseHeight = pHeader->pixelHeight; + This->baseDepth = pHeader->pixelDepth; + break; + } + if (pHeader->numberOfArrayElements > 0) { + This->numLayers = pHeader->numberOfArrayElements; + This->isArray = KTX_TRUE; + } else { + This->numLayers = 1; + This->isArray = KTX_FALSE; + } + This->numFaces = pHeader->numberOfFaces; + if (pHeader->numberOfFaces == 6) + This->isCubemap = KTX_TRUE; + else + This->isCubemap = KTX_FALSE; + This->numLevels = pHeader->numberOfMipLevels; + This->isCompressed = suppInfo.compressed; + This->generateMipmaps = suppInfo.generateMipmaps; + if (pHeader->endianness == KTX_ENDIAN_REF_REV) + private->_needSwap = KTX_TRUE; + This->_protected->_typeSize = pHeader->glTypeSize; + + /* + * Make an empty hash list. + */ + ktxHashList_Construct(&This->kvDataHead); + /* + * Load KVData. + */ + if (pHeader->bytesOfKeyValueData > 0) { + if (!(createFlags & KTX_TEXTURE_CREATE_SKIP_KVDATA_BIT)) { + ktx_uint32_t kvdLen = pHeader->bytesOfKeyValueData; + ktx_uint8_t* pKvd; + + pKvd = malloc(kvdLen); + if (pKvd == NULL) { + result = KTX_OUT_OF_MEMORY; + goto cleanup; + } + + result = stream->read(stream, pKvd, kvdLen); + if (result != KTX_SUCCESS) + goto cleanup; + + if (private->_needSwap) { + /* Swap the counts inside the key & value data. */ + ktx_uint8_t* src = pKvd; + ktx_uint8_t* end = pKvd + kvdLen; + while (src < end) { + ktx_uint32_t* pKeyAndValueByteSize = (ktx_uint32_t*)src; + _ktxSwapEndian32(pKeyAndValueByteSize, 1); + src += _KTX_PAD4(*pKeyAndValueByteSize); + } + } + + if (!(createFlags & KTX_TEXTURE_CREATE_RAW_KVDATA_BIT)) { + char* orientation; + ktx_uint32_t orientationLen; + + result = ktxHashList_Deserialize(&This->kvDataHead, + kvdLen, pKvd); + free(pKvd); + if (result != KTX_SUCCESS) { + goto cleanup; + } + + result = ktxHashList_FindValue(&This->kvDataHead, + KTX_ORIENTATION_KEY, + &orientationLen, + (void**)&orientation); + assert(result != KTX_INVALID_VALUE); + if (result == KTX_SUCCESS) { + ktx_uint32_t count; + char orient[4] = {0, 0, 0, 0}; + + count = sscanf(orientation, KTX_ORIENTATION3_FMT, + &orient[0], + &orient[1], + &orient[2]); + + if (count > This->numDimensions) { + // KTX 1 is less strict than KTX2 so there is a chance + // of having more dimensions than needed. + count = This->numDimensions; + } + switch (This->numDimensions) { + case 3: + This->orientation.z = orient[2]; + FALLTHROUGH; + case 2: + This->orientation.y = orient[1]; + FALLTHROUGH; + case 1: + This->orientation.x = orient[0]; + } + } + } else { + This->kvDataLen = kvdLen; + This->kvData = pKvd; + } + } else { + stream->skip(stream, pHeader->bytesOfKeyValueData); + } + } + + /* + * Get the size of the image data. + */ + result = stream->getsize(stream, &size); + if (result != KTX_SUCCESS) + goto cleanup; + + result = stream->getpos(stream, &pos); + if (result != KTX_SUCCESS) + goto cleanup; + + /* Remove space for faceLodSize fields */ + This->dataSize = size - pos - This->numLevels * sizeof(ktx_uint32_t); + + /* + * Load the images, if requested. + */ + if (createFlags & KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT) { + result = ktxTexture1_LoadImageData(This, NULL, 0); + } + if (result == KTX_SUCCESS) + return result; + +cleanup: + ktxTexture1_destruct(This); + return result; +} + +/** + * @memberof ktxTexture1 @private + * @brief Construct a ktxTexture1 from a ktxStream reading from a KTX source. + * + * The stream object is copied into the constructed ktxTexture1. + * + * The create flag KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT should not be set, + * if the ktxTexture1 is ultimately to be uploaded to OpenGL or Vulkan. This + * will minimize memory usage by allowing, for example, loading the images + * directly from the source into a Vulkan staging buffer. + * + * The create flag KTX_TEXTURE_CREATE_RAW_KVDATA_BIT should not be used. It is + * provided solely to enable implementation of the @e libktx v1 API on top of + * ktxTexture1. + * + * @param[in] This pointer to a ktxTexture1-sized block of memory to + * initialize. + * @param[in] pStream pointer to the stream to read. + * @param[in] createFlags bitmask requesting specific actions during creation. + * + * @return KTX_SUCCESS on success, other KTX_* enum values on error. + * + * @exception KTX_FILE_READ_ERROR + * An error occurred while reading the source. + * + * For other exceptions see ktxTexture1_constructFromStreamAndHeader(). + */ +static KTX_error_code +ktxTexture1_constructFromStream(ktxTexture1* This, ktxStream* pStream, + ktxTextureCreateFlags createFlags) +{ + KTX_header header; + KTX_error_code result; + + // Read header. + result = pStream->read(pStream, &header, KTX_HEADER_SIZE); + if (result != KTX_SUCCESS) + return result; + + return ktxTexture1_constructFromStreamAndHeader(This, pStream, + &header, createFlags); +} + +/** + * @memberof ktxTexture1 @private + * @brief Construct a ktxTexture1 from a stdio stream reading from a KTX source. + * + * See ktxTextureInt_constructFromStream for details. + * + * @note Do not close the stdio stream until you are finished with the texture + * object. + * + * @param[in] This pointer to a ktxTextureInt-sized block of memory to + * initialize. + * @param[in] stdioStream a stdio FILE pointer opened on the source. + * @param[in] createFlags bitmask requesting specific actions during creation. + * + * @return KTX_SUCCESS on success, other KTX_* enum values on error. + * + * @exception KTX_INVALID_VALUE Either @p stdiostream or @p This is null. + * + * For other exceptions, see ktxTexture_constructFromStream(). + */ +static KTX_error_code +ktxTexture1_constructFromStdioStream(ktxTexture1* This, FILE* stdioStream, + ktxTextureCreateFlags createFlags) +{ + ktxStream stream; + KTX_error_code result; + + if (stdioStream == NULL || This == NULL) + return KTX_INVALID_VALUE; + + result = ktxFileStream_construct(&stream, stdioStream, KTX_FALSE); + if (result == KTX_SUCCESS) + result = ktxTexture1_constructFromStream(This, &stream, createFlags); + return result; +} + +/** + * @memberof ktxTexture1 @private + * @brief Construct a ktxTexture1 from a named KTX file. + * + * See ktxTextureInt_constructFromStream for details. + * + * @param[in] This pointer to a ktxTextureInt-sized block of memory to + * initialize. + * @param[in] filename pointer to a char array containing the file name. + * @param[in] createFlags bitmask requesting specific actions during creation. + * + * @return KTX_SUCCESS on success, other KTX_* enum values on error. + * + * @exception KTX_FILE_OPEN_FAILED The file could not be opened. + * @exception KTX_INVALID_VALUE @p filename is @c NULL. + * + * For other exceptions, see ktxTexture_constructFromStream(). + */ +static KTX_error_code +ktxTexture1_constructFromNamedFile(ktxTexture1* This, + const char* const filename, + ktxTextureCreateFlags createFlags) +{ + FILE* file; + ktxStream stream; + KTX_error_code result; + + if (This == NULL || filename == NULL) + return KTX_INVALID_VALUE; + + file = fopen(filename, "rb"); + if (!file) + return KTX_FILE_OPEN_FAILED; + + result = ktxFileStream_construct(&stream, file, KTX_TRUE); + if (result == KTX_SUCCESS) + result = ktxTexture1_constructFromStream(This, &stream, createFlags); + + return result; +} + +/** + * @memberof ktxTexture1 @private + * @brief Construct a ktxTexture1 from KTX-formatted data in memory. + * + * See ktxTextureInt_constructFromStream for details. + * + * @param[in] This pointer to a ktxTextureInt-sized block of memory to + * initialize. + * @param[in] bytes pointer to the memory containing the serialized KTX data. + * @param[in] size length of the KTX data in bytes. + * @param[in] createFlags bitmask requesting specific actions during creation. + * + * @return KTX_SUCCESS on success, other KTX_* enum values on error. + * + * @exception KTX_INVALID_VALUE Either @p bytes is NULL or @p size is 0. + * + * For other exceptions, see ktxTexture_constructFromStream(). + */ +static KTX_error_code +ktxTexture1_constructFromMemory(ktxTexture1* This, + const ktx_uint8_t* bytes, ktx_size_t size, + ktxTextureCreateFlags createFlags) +{ + ktxStream stream; + KTX_error_code result; + + if (bytes == NULL || size == 0) + return KTX_INVALID_VALUE; + + result = ktxMemStream_construct_ro(&stream, bytes, size); + if (result == KTX_SUCCESS) + result = ktxTexture1_constructFromStream(This, &stream, createFlags); + + return result; +} + +void +ktxTexture1_destruct(ktxTexture1* This) +{ + if (This->_private) free(This->_private); + ktxTexture_destruct(ktxTexture(This)); +} + +/** + * @defgroup reader Reader + * @brief Read KTX-formatted data. + * @{ + */ + +/** + * @memberof ktxTexture1 + * @ingroup writer + * @brief Create a new empty ktxTexture1. + * + * The address of the newly created ktxTexture1 is written to the location + * pointed at by @p newTex. + * + * @param[in] createInfo pointer to a ktxTextureCreateInfo struct with + * information describing the texture. + * @param[in] storageAllocation + * enum indicating whether or not to allocate storage + * for the texture images. + * @param[in,out] newTex pointer to a location in which store the address of + * the newly created texture. + * + * @return KTX_SUCCESS on success, other KTX_* enum values on error. + * + * @exception KTX_INVALID_VALUE @c glInternalFormat in @p createInfo is not a + * valid OpenGL internal format value. + * @exception KTX_INVALID_VALUE @c numDimensions in @p createInfo is not 1, 2 + * or 3. + * @exception KTX_INVALID_VALUE One of base{Width,Height,Depth} in + * @p createInfo is 0. + * @exception KTX_INVALID_VALUE @c numFaces in @p createInfo is not 1 or 6. + * @exception KTX_INVALID_VALUE @c numLevels in @p createInfo is 0. + * @exception KTX_INVALID_OPERATION + * The base{Width,Height,Depth} specified + * in @p createInfo are inconsistent with + * @c numDimensions. + * @exception KTX_INVALID_OPERATION + * @p createInfo is requesting a 3D array or + * 3D cubemap texture. + * @exception KTX_INVALID_OPERATION + * @p createInfo is requesting a cubemap with + * non-square or non-2D images. + * @exception KTX_INVALID_OPERATION + * @p createInfo is requesting more mip levels + * than needed for the specified + * base{Width,Height,Depth}. + * @exception KTX_OUT_OF_MEMORY Not enough memory for the texture's images. + */ +KTX_error_code +ktxTexture1_Create(ktxTextureCreateInfo* createInfo, + ktxTextureCreateStorageEnum storageAllocation, + ktxTexture1** newTex) +{ + KTX_error_code result; + + if (newTex == NULL) + return KTX_INVALID_VALUE; + + ktxTexture1* tex = (ktxTexture1*)malloc(sizeof(ktxTexture1)); + if (tex == NULL) + return KTX_OUT_OF_MEMORY; + + result = ktxTexture1_construct(tex, createInfo, storageAllocation); + if (result != KTX_SUCCESS) { + free(tex); + } else { + *newTex = tex; + } + return result; +} + +/** + * @memberof ktxTexture1 + * @~English + * @brief Create a ktxTexture1 from a stdio stream reading from a KTX source. + * + * The address of a newly created ktxTexture1 reflecting the contents of the + * stdio stream is written to the location pointed at by @p newTex. + * + * The create flag KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT should not be set, + * if the ktxTexture1 is ultimately to be uploaded to OpenGL or Vulkan. This + * will minimize memory usage by allowing, for example, loading the images + * directly from the source into a Vulkan staging buffer. + * + * The create flag KTX_TEXTURE_CREATE_RAW_KVDATA_BIT should not be used. It is + * provided solely to enable implementation of the @e libktx v1 API on top of + * ktxTexture1. + * + * @param[in] stdioStream stdio FILE pointer created from the desired file. + * @param[in] createFlags bitmask requesting specific actions during creation. + * @param[in,out] newTex pointer to a location in which store the address of + * the newly created texture. + * + * @return KTX_SUCCESS on success, other KTX_* enum values on error. + * + * @exception KTX_INVALID_VALUE @p newTex is @c NULL. + * @exception KTX_FILE_DATA_ERROR + * Source data is inconsistent with the KTX + * specification. + * @exception KTX_FILE_READ_ERROR + * An error occurred while reading the source. + * @exception KTX_FILE_UNEXPECTED_EOF + * Not enough data in the source. + * @exception KTX_OUT_OF_MEMORY Not enough memory to create the texture object, + * load the images or load the key-value data. + * @exception KTX_UNKNOWN_FILE_FORMAT + * The source is not in KTX format. + * @exception KTX_UNSUPPORTED_TEXTURE_TYPE + * The source describes a texture type not + * supported by OpenGL or Vulkan, e.g, a 3D array. + */ +KTX_error_code +ktxTexture1_CreateFromStdioStream(FILE* stdioStream, + ktxTextureCreateFlags createFlags, + ktxTexture1** newTex) +{ + KTX_error_code result; + if (newTex == NULL) + return KTX_INVALID_VALUE; + + ktxTexture1* tex = (ktxTexture1*)malloc(sizeof(ktxTexture1)); + if (tex == NULL) + return KTX_OUT_OF_MEMORY; + + result = ktxTexture1_constructFromStdioStream(tex, stdioStream, + createFlags); + if (result == KTX_SUCCESS) + *newTex = (ktxTexture1*)tex; + else { + free(tex); + *newTex = NULL; + } + return result; +} + +/* + * @memberof ktxTexture1 + * @~English + * @brief Create a ktxTexture1 from a named KTX file. + * + * The address of a newly created ktxTexture1 reflecting the contents of the + * file is written to the location pointed at by @p newTex. + * + * The create flag KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT should not be set, + * if the ktxTexture1 is ultimately to be uploaded to OpenGL or Vulkan. This + * will minimize memory usage by allowing, for example, loading the images + * directly from the source into a Vulkan staging buffer. + * + * The create flag KTX_TEXTURE_CREATE_RAW_KVDATA_BIT should not be used. It is + * provided solely to enable implementation of the @e libktx v1 API on top of + * ktxTexture1. + * + * @param[in] filename pointer to a char array containing the file name. + * @param[in] createFlags bitmask requesting specific actions during creation. + * @param[in,out] newTex pointer to a location in which store the address of + * the newly created texture. + * + * @return KTX_SUCCESS on success, other KTX_* enum values on error. + * + * @exception KTX_FILE_OPEN_FAILED The file could not be opened. + * @exception KTX_INVALID_VALUE @p filename is @c NULL. + * + * For other exceptions, see ktxTexture_CreateFromStdioStream(). + */ +KTX_error_code +ktxTexture1_CreateFromNamedFile(const char* const filename, + ktxTextureCreateFlags createFlags, + ktxTexture1** newTex) +{ + KTX_error_code result; + + if (newTex == NULL) + return KTX_INVALID_VALUE; + + ktxTexture1* tex = (ktxTexture1*)malloc(sizeof(ktxTexture1)); + if (tex == NULL) + return KTX_OUT_OF_MEMORY; + + result = ktxTexture1_constructFromNamedFile(tex, filename, createFlags); + if (result == KTX_SUCCESS) + *newTex = (ktxTexture1*)tex; + else { + free(tex); + *newTex = NULL; + } + return result; +} + +/** + * @memberof ktxTexture1 + * @~English + * @brief Create a ktxTexture1 from KTX-formatted data in memory. + * + * The address of a newly created ktxTexture1 reflecting the contents of the + * serialized KTX data is written to the location pointed at by @p newTex. + * + * The create flag KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT should not be set, + * if the ktxTexture1 is ultimately to be uploaded to OpenGL or Vulkan. This + * will minimize memory usage by allowing, for example, loading the images + * directly from the source into a Vulkan staging buffer. + * + * The create flag KTX_TEXTURE_CREATE_RAW_KVDATA_BIT should not be used. It is + * provided solely to enable implementation of the @e libktx v1 API on top of + * ktxTexture1. + * + * @param[in] bytes pointer to the memory containing the serialized KTX data. + * @param[in] size length of the KTX data in bytes. + * @param[in] createFlags bitmask requesting specific actions during creation. + * @param[in,out] newTex pointer to a location in which store the address of + * the newly created texture. + * + * @return KTX_SUCCESS on success, other KTX_* enum values on error. + * + * @exception KTX_INVALID_VALUE Either @p bytes is NULL or @p size is 0. + * + * For other exceptions, see ktxTexture_CreateFromStdioStream(). + */ +KTX_error_code +ktxTexture1_CreateFromMemory(const ktx_uint8_t* bytes, ktx_size_t size, + ktxTextureCreateFlags createFlags, + ktxTexture1** newTex) +{ + KTX_error_code result; + if (newTex == NULL) + return KTX_INVALID_VALUE; + + ktxTexture1* tex = (ktxTexture1*)malloc(sizeof(ktxTexture1)); + if (tex == NULL) + return KTX_OUT_OF_MEMORY; + + result = ktxTexture1_constructFromMemory(tex, bytes, size, + createFlags); + if (result == KTX_SUCCESS) + *newTex = (ktxTexture1*)tex; + else { + free(tex); + *newTex = NULL; + } + return result; +} + +/** + * @memberof ktxTexture1 + * @~English + * @brief Create a ktxTexture1 from KTX-formatted data from a `ktxStream`. + * + * The address of a newly created ktxTexture1 reflecting the contents of the + * serialized KTX data is written to the location pointed at by @p newTex. + * + * The create flag KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT should not be set, + * if the ktxTexture1 is ultimately to be uploaded to OpenGL or Vulkan. This + * will minimize memory usage by allowing, for example, loading the images + * directly from the source into a Vulkan staging buffer. + * + * The create flag KTX_TEXTURE_CREATE_RAW_KVDATA_BIT should not be used. It is + * provided solely to enable implementation of the @e libktx v1 API on top of + * ktxTexture1. + * + * @param[in] stream pointer to the stream to read KTX data from. + * @param[in] createFlags bitmask requesting specific actions during creation. + * @param[in,out] newTex pointer to a location in which store the address of + * the newly created texture. + * + * @return KTX_SUCCESS on success, other KTX_* enum values on error. + * + * @exception KTX_INVALID_VALUE Either @p bytes is NULL or @p size is 0. + * + * For other exceptions, see ktxTexture_CreateFromStdioStream(). + */ +KTX_error_code +ktxTexture1_CreateFromStream(ktxStream* stream, + ktxTextureCreateFlags createFlags, + ktxTexture1** newTex) +{ + KTX_error_code result; + if (newTex == NULL) + return KTX_INVALID_VALUE; + + ktxTexture1* tex = (ktxTexture1*)malloc(sizeof(ktxTexture1)); + if (tex == NULL) + return KTX_OUT_OF_MEMORY; + + result = ktxTexture1_constructFromStream(tex, stream, createFlags); + if (result == KTX_SUCCESS) + *newTex = (ktxTexture1*)tex; + else { + free(tex); + *newTex = NULL; + } + return result; +} + +/** + * @memberof ktxTexture1 + * @~English + * @brief Destroy a ktxTexture1 object. + * + * This frees the memory associated with the texture contents and the memory + * of the ktxTexture1 object. This does @e not delete any OpenGL or Vulkan + * texture objects created by ktxTexture1_GLUpload or ktxTexture1_VkUpload. + * + * @param[in] This pointer to the ktxTexture1 object to destroy + */ +void +ktxTexture1_Destroy(ktxTexture1* This) +{ + ktxTexture1_destruct(This); + free(This); +} + +/** + * @memberof ktxTexture @private + * @~English + * @brief Calculate the size of the image data for the specified number + * of levels. + * + * The data size is the sum of the sizes of each level up to the number + * specified and includes any @c mipPadding. + * + * @param[in] This pointer to the ktxTexture object of interest. + * @param[in] levels number of levels whose data size to return. + * + * @return the data size in bytes. + */ +ktx_size_t +ktxTexture1_calcDataSizeLevels(ktxTexture1* This, ktx_uint32_t levels) +{ + ktx_uint32_t i; + ktx_size_t dataSize = 0; + + assert(This != NULL); + assert(levels <= This->numLevels); + for (i = 0; i < levels; i++) { + ktx_size_t levelSize = ktxTexture_calcLevelSize(ktxTexture(This), i, + KTX_FORMAT_VERSION_ONE); + /* mipPadding. NOTE: this adds padding after the last level too. */ + #if KTX_GL_UNPACK_ALIGNMENT != 4 + dataSize += _KTX_PAD4(levelSize); + #else + dataSize += levelSize; + #endif + } + return dataSize; +} + +/** + * @memberof ktxTexture1 @private + * @~English + * + * @copydoc ktxTexture::ktxTexture_doCalcFaceLodSize + */ +ktx_size_t +ktxTexture1_calcFaceLodSize(ktxTexture1* This, ktx_uint32_t level) +{ + return ktxTexture_doCalcFaceLodSize(ktxTexture(This), level, + KTX_FORMAT_VERSION_ONE); +} + +/** + * @memberof ktxTexture @private + * @~English + * @brief Return the offset of a level in bytes from the start of the image + * data in a ktxTexture. + * + * The caclulated size does not include space for storing the @c imageSize + * fields of each mip level. + * + * @param[in] This pointer to the ktxTexture object of interest. + * @param[in] level level whose offset to return. + * @param[in] fv enum specifying format version for which to calculate + * image size. + * + * @return the data size in bytes. + */ +ktx_size_t +ktxTexture1_calcLevelOffset(ktxTexture1* This, ktx_uint32_t level) +{ + assert (This != NULL); + assert (level < This->numLevels); + return ktxTexture1_calcDataSizeLevels(This, level); +} + +/** + * @memberof ktxTexture1 + * @~English + * @brief Find the offset of an image within a ktxTexture's image data. + * + * As there is no such thing as a 3D cubemap we make the 3rd location parameter + * do double duty. + * + * @param[in] This pointer to the ktxTexture object of interest. + * @param[in] level mip level of the image. + * @param[in] layer array layer of the image. + * @param[in] faceSlice cube map face or depth slice of the image. + * @param[in,out] pOffset pointer to location to store the offset. + * + * @return KTX_SUCCESS on success, other KTX_* enum values on error. + * + * @exception KTX_INVALID_OPERATION + * @p level, @p layer or @p faceSlice exceed the + * dimensions of the texture. + * @exception KTX_INVALID_VALID @p This is NULL. + */ +KTX_error_code +ktxTexture1_GetImageOffset(ktxTexture1* This, ktx_uint32_t level, + ktx_uint32_t layer, ktx_uint32_t faceSlice, + ktx_size_t* pOffset) +{ + + if (This == NULL) + return KTX_INVALID_VALUE; + + if (level >= This->numLevels || layer >= This->numLayers) + return KTX_INVALID_OPERATION; + + if (This->isCubemap) { + if (faceSlice >= This->numFaces) + return KTX_INVALID_OPERATION; + } else { + ktx_uint32_t maxSlice = MAX(1, This->baseDepth >> level); + if (faceSlice >= maxSlice) + return KTX_INVALID_OPERATION; + } + + // Get the size of the data up to the start of the indexed level. + *pOffset = ktxTexture_calcDataSizeLevels(ktxTexture(This), level); + + // All layers, faces & slices within a level are the same size. + if (layer != 0) { + ktx_size_t layerSize; + layerSize = ktxTexture_layerSize(ktxTexture(This), level, + KTX_FORMAT_VERSION_ONE); + *pOffset += layer * layerSize; + } + if (faceSlice != 0) { + ktx_size_t imageSize; + imageSize = ktxTexture_GetImageSize(ktxTexture(This), level); +#if (KTX_GL_UNPACK_ALIGNMENT != 4) + if (This->isCubemap) + _KTX_PAD4(imageSize); // Account for cubePadding. +#endif + *pOffset += faceSlice * imageSize; + } + + return KTX_SUCCESS; +} + +/** + * @memberof ktxTexture1 + * @~English + * @brief Return the total size in bytes of the uncompressed data of a ktxTexture1. + * + * This always returns the value of @c This->dataSize. The function is provided for + * symmetry with ktxTexture2. + * + * @param[in] This pointer to the ktxTexture1 object of interest. + * @return The size of the data in the texture. + */ +ktx_size_t +ktxTexture1_GetDataSizeUncompressed(ktxTexture1* This) +{ + return This->dataSize; +} + +/** + * @memberof ktxTexture1 + * @~English + * @brief Calculate & return the size in bytes of an image at the specified + * mip level. + * + * For arrays, this is the size of layer, for cubemaps, the size of a face + * and for 3D textures, the size of a depth slice. + * + * The size reflects the padding of each row to KTX_GL_UNPACK_ALIGNMENT. + * + * @param[in] This pointer to the ktxTexture1 object of interest. + * @param[in] level level of interest. + */ +ktx_size_t +ktxTexture1_GetImageSize(ktxTexture1* This, ktx_uint32_t level) +{ + return ktxTexture_calcImageSize(ktxTexture(This), level, + KTX_FORMAT_VERSION_ONE); +} + +/** + * @memberof ktxTexture1 @private + * @~English + * @brief Return the size of the primitive type of a single color component + * + * @param[in] This pointer to the ktxTexture1 object of interest. + * + * @return the type size in bytes. + */ +ktx_uint32_t +ktxTexture1_glTypeSize(ktxTexture1* This) +{ + assert(This != NULL); + return This->_protected->_typeSize; +} + +/** + * @memberof ktxTexture1 + * @~English + * @brief Iterate over the mip levels in a ktxTexture1 object. + * + * This is almost identical to ktxTexture_IterateLevelFaces(). The difference is + * that the blocks of image data for non-array cube maps include all faces of + * a mip level. + * + * This function works even if @p This->pData == 0 so it can be used to + * obtain offsets and sizes for each level by callers who have loaded the data + * externally. + * + * @param[in] This handle of the 1 opened on the data. + * @param[in,out] iterCb the address of a callback function which is called + * with the data for each image block. + * @param[in,out] userdata the address of application-specific data which is + * passed to the callback along with the image data. + * + * @return KTX_SUCCESS on success, other KTX_* enum values on error. The + * following are returned directly by this function. @p iterCb may + * return these for other causes or may return additional errors. + * + * @exception KTX_FILE_DATA_ERROR Mip level sizes are increasing not + * decreasing + * @exception KTX_INVALID_VALUE @p This is @c NULL or @p iterCb is @c NULL. + * + */ +KTX_error_code +ktxTexture1_IterateLevels(ktxTexture1* This, PFNKTXITERCB iterCb, void* userdata) +{ + ktx_uint32_t miplevel; + KTX_error_code result = KTX_SUCCESS; + + if (This == NULL) + return KTX_INVALID_VALUE; + + if (iterCb == NULL) + return KTX_INVALID_VALUE; + + for (miplevel = 0; miplevel < This->numLevels; ++miplevel) + { + GLsizei width, height, depth; + ktx_uint32_t levelSize; + ktx_size_t offset; + + /* Array textures have the same number of layers at each mip level. */ + width = MAX(1, This->baseWidth >> miplevel); + height = MAX(1, This->baseHeight >> miplevel); + depth = MAX(1, This->baseDepth >> miplevel); + + levelSize = (ktx_uint32_t)ktxTexture_calcLevelSize(ktxTexture(This), + miplevel, + KTX_FORMAT_VERSION_ONE); + + /* All array layers are passed in a group because that is how + * GL & Vulkan need them. Hence no + * for (layer = 0; layer < This->numLayers) + */ + ktxTexture_GetImageOffset(ktxTexture(This), miplevel, 0, 0, &offset); + result = iterCb(miplevel, 0, width, height, depth, + levelSize, This->pData + offset, userdata); + if (result != KTX_SUCCESS) + break; + } + + return result; +} + +/** + * @memberof ktxTexture1 + * @~English + * @brief Iterate over the images in a ktxTexture1 object while loading the + * image data. + * + * This operates similarly to ktxTexture_IterateLevelFaces() except that it + * loads the images from the ktxTexture1's source to a temporary buffer + * while iterating. The callback function must copy the image data if it + * wishes to preserve it as the temporary buffer is reused for each level and + * is freed when this function exits. + * + * This function is helpful for reducing memory usage when uploading the data + * to a graphics API. + * + * @param[in] This pointer to the ktxTexture1 object of interest. + * @param[in,out] iterCb the address of a callback function which is called + * with the data for each image. + * @param[in,out] userdata the address of application-specific data which is + * passed to the callback along with the image data. + * + * @return KTX_SUCCESS on success, other KTX_* enum values on error. The + * following are returned directly by this function. @p iterCb may + * return these for other causes or may return additional errors. + * + * @exception KTX_FILE_DATA_ERROR mip level sizes are increasing not + * decreasing + * @exception KTX_INVALID_OPERATION the ktxTexture1 was not created from a + * stream, i.e there is no data to load, or + * this ktxTexture1's images have already + * been loaded. + * @exception KTX_INVALID_VALUE @p This is @c NULL or @p iterCb is @c NULL. + * @exception KTX_OUT_OF_MEMORY not enough memory to allocate a block to + * hold the base level image. + */ +KTX_error_code +ktxTexture1_IterateLoadLevelFaces(ktxTexture1* This, PFNKTXITERCB iterCb, + void* userdata) +{ + DECLARE_PRIVATE(ktxTexture1); + struct ktxTexture_protected* prtctd = This->_protected; + ktxStream* stream = (ktxStream *)&prtctd->_stream; + ktx_uint32_t dataSize = 0; + ktx_uint32_t miplevel; + KTX_error_code result = KTX_SUCCESS; + void* data = NULL; + + if (This == NULL) + return KTX_INVALID_VALUE; + + if (This->classId != ktxTexture1_c) + return KTX_INVALID_OPERATION; + + if (iterCb == NULL) + return KTX_INVALID_VALUE; + + if (prtctd->_stream.data.file == NULL) + // This Texture not created from a stream or images are already loaded. + return KTX_INVALID_OPERATION; + + for (miplevel = 0; miplevel < This->numLevels; ++miplevel) + { + ktx_uint32_t faceLodSize; + ktx_uint32_t faceLodSizePadded; + ktx_uint32_t face; + ktx_uint32_t innerIterations; + GLsizei width, height, depth; + + /* Array textures have the same number of layers at each mip level. */ + width = MAX(1, This->baseWidth >> miplevel); + height = MAX(1, This->baseHeight >> miplevel); + depth = MAX(1, This->baseDepth >> miplevel); + + result = stream->read(stream, &faceLodSize, sizeof(ktx_uint32_t)); + if (result != KTX_SUCCESS) { + goto cleanup; + } + if (private->_needSwap) { + _ktxSwapEndian32(&faceLodSize, 1); + } +#if (KTX_GL_UNPACK_ALIGNMENT != 4) + faceLodSizePadded = _KTX_PAD4(faceLodSize); +#else + faceLodSizePadded = faceLodSize; +#endif + if (!data) { + /* allocate memory sufficient for the base miplevel */ + data = malloc(faceLodSizePadded); + if (!data) { + result = KTX_OUT_OF_MEMORY; + goto cleanup; + } + dataSize = faceLodSizePadded; + } + else if (dataSize < faceLodSizePadded) { + /* subsequent miplevels cannot be larger than the base miplevel */ + result = KTX_FILE_DATA_ERROR; + goto cleanup; + } + + /* All array layers are passed in a group because that is how + * GL & Vulkan need them. Hence no + * for (layer = 0; layer < This->numLayers) + */ + if (This->isCubemap && !This->isArray) + innerIterations = This->numFaces; + else + innerIterations = 1; + for (face = 0; face < innerIterations; ++face) + { + /* And all z_slices are also passed as a group hence no + * for (z_slice = 0; z_slice < This->depth) + */ + result = stream->read(stream, data, faceLodSizePadded); + if (result != KTX_SUCCESS) { + goto cleanup; + } + + /* Perform endianness conversion on texture data */ + if (private->_needSwap) { + if (prtctd->_typeSize == 2) + _ktxSwapEndian16((ktx_uint16_t*)data, faceLodSize / 2); + else if (prtctd->_typeSize == 4) + _ktxSwapEndian32((ktx_uint32_t*)data, faceLodSize / 4); + } + + result = iterCb(miplevel, face, + width, height, depth, + faceLodSize, data, userdata); + } + } + +cleanup: + free(data); + // No further need for this. + stream->destruct(stream); + + return result; +} + +/** + * @memberof ktxTexture1 + * @~English + * @brief Load all the image data from the ktxTexture1's source. + * + * The data is loaded into the provided buffer or to an internally allocated + * buffer, if @p pBuffer is @c NULL. + * + * @param[in] This pointer to the ktxTexture object of interest. + * @param[in] pBuffer pointer to the buffer in which to load the image data. + * @param[in] bufSize size of the buffer pointed at by @p pBuffer. + * + * @return KTX_SUCCESS on success, other KTX_* enum values on error. + * + * @exception KTX_INVALID_VALUE @p This is NULL. + * @exception KTX_INVALID_VALUE @p bufSize is less than the the image data size. + * @exception KTX_INVALID_OPERATION + * The data has already been loaded or the + * ktxTexture was not created from a KTX source. + * @exception KTX_OUT_OF_MEMORY Insufficient memory for the image data. + */ +KTX_error_code +ktxTexture1_LoadImageData(ktxTexture1* This, + ktx_uint8_t* pBuffer, ktx_size_t bufSize) +{ + DECLARE_PROTECTED(ktxTexture); + DECLARE_PRIVATE(ktxTexture1); + ktx_uint32_t miplevel; + ktx_uint8_t* pDest; + KTX_error_code result = KTX_SUCCESS; + + if (This == NULL) + return KTX_INVALID_VALUE; + + if (prtctd->_stream.data.file == NULL) + // This Texture not created from a stream or images already loaded; + return KTX_INVALID_OPERATION; + + if (pBuffer == NULL) { + This->pData = malloc(This->dataSize); + if (This->pData == NULL) + return KTX_OUT_OF_MEMORY; + pDest = This->pData; + } else if (bufSize < This->dataSize) { + return KTX_INVALID_VALUE; + } else { + pDest = pBuffer; + } + + // Need to loop through for correct byte swapping + for (miplevel = 0; miplevel < This->numLevels; ++miplevel) + { + ktx_uint32_t faceLodSize; + ktx_uint32_t faceLodSizePadded; + ktx_uint32_t face; + ktx_uint32_t innerIterations; + + result = prtctd->_stream.read(&prtctd->_stream, &faceLodSize, + sizeof(ktx_uint32_t)); + if (result != KTX_SUCCESS) { + goto cleanup; + } + if (private->_needSwap) { + _ktxSwapEndian32(&faceLodSize, 1); + } +#if (KTX_GL_UNPACK_ALIGNMENT != 4) + faceLodSizePadded = _KTX_PAD4(faceLodSize); +#else + faceLodSizePadded = faceLodSize; +#endif + + if (This->isCubemap && !This->isArray) + innerIterations = This->numFaces; + else + innerIterations = 1; + for (face = 0; face < innerIterations; ++face) + { + result = prtctd->_stream.read(&prtctd->_stream, pDest, + faceLodSizePadded); + if (result != KTX_SUCCESS) { + goto cleanup; + } + + /* Perform endianness conversion on texture data */ + if (private->_needSwap) { + if (prtctd->_typeSize == 2) + _ktxSwapEndian16((ktx_uint16_t*)pDest, faceLodSize / 2); + else if (prtctd->_typeSize == 4) + _ktxSwapEndian32((ktx_uint32_t*)pDest, faceLodSize / 4); + } + + pDest += faceLodSizePadded; + } + } + +cleanup: + // No further need for This-> + prtctd->_stream.destruct(&prtctd->_stream); + return result; +} + +ktx_bool_t +ktxTexture1_NeedsTranscoding(ktxTexture1* This) +{ + UNUSED(This); + return KTX_FALSE; +} + +#if !KTX_FEATURE_WRITE + +/* + * Stubs for writer functions that return a proper error code + */ + +KTX_error_code +ktxTexture1_SetImageFromMemory(ktxTexture1* This, ktx_uint32_t level, + ktx_uint32_t layer, ktx_uint32_t faceSlice, + const ktx_uint8_t* src, ktx_size_t srcSize) +{ + UNUSED(This); + UNUSED(level); + UNUSED(layer); + UNUSED(faceSlice); + UNUSED(src); + UNUSED(srcSize); + return KTX_INVALID_OPERATION; +} + +KTX_error_code +ktxTexture1_SetImageFromStdioStream(ktxTexture1* This, ktx_uint32_t level, + ktx_uint32_t layer, ktx_uint32_t faceSlice, + FILE* src, ktx_size_t srcSize) +{ + UNUSED(This); + UNUSED(level); + UNUSED(layer); + UNUSED(faceSlice); + UNUSED(src); + UNUSED(srcSize); + return KTX_INVALID_OPERATION; +} + +KTX_error_code +ktxTexture1_WriteToStdioStream(ktxTexture1* This, FILE* dstsstr) +{ + UNUSED(This); + UNUSED(dstsstr); + return KTX_INVALID_OPERATION; +} + +KTX_error_code +ktxTexture1_WriteToNamedFile(ktxTexture1* This, const char* const dstname) +{ + UNUSED(This); + UNUSED(dstname); + return KTX_INVALID_OPERATION; +} + +KTX_error_code +ktxTexture1_WriteToMemory(ktxTexture1* This, + ktx_uint8_t** ppDstBytes, ktx_size_t* pSize) +{ + UNUSED(This); + UNUSED(ppDstBytes); + UNUSED(pSize); + return KTX_INVALID_OPERATION; +} + +KTX_error_code +ktxTexture1_WriteToStream(ktxTexture1* This, + ktxStream* dststr) +{ + UNUSED(This); + UNUSED(dststr); + return KTX_INVALID_OPERATION; +} + +#endif + +/* + * Initialized here at the end to avoid the need for multiple declarations of + * these functions. + */ + +struct ktxTexture_vtblInt ktxTexture1_vtblInt = { + (PFNCALCDATASIZELEVELS)ktxTexture1_calcDataSizeLevels, + (PFNCALCFACELODSIZE)ktxTexture1_calcFaceLodSize, + (PFNCALCLEVELOFFSET)ktxTexture1_calcLevelOffset +}; + +struct ktxTexture_vtbl ktxTexture1_vtbl = { + (PFNKTEXDESTROY)ktxTexture1_Destroy, + (PFNKTEXGETIMAGEOFFSET)ktxTexture1_GetImageOffset, + (PFNKTEXGETDATASIZEUNCOMPRESSED)ktxTexture1_GetDataSizeUncompressed, + (PFNKTEXGETIMAGESIZE)ktxTexture1_GetImageSize, + (PFNKTEXITERATELEVELS)ktxTexture1_IterateLevels, + (PFNKTEXITERATELOADLEVELFACES)ktxTexture1_IterateLoadLevelFaces, + (PFNKTEXNEEDSTRANSCODING)ktxTexture1_NeedsTranscoding, + (PFNKTEXLOADIMAGEDATA)ktxTexture1_LoadImageData, + (PFNKTEXSETIMAGEFROMMEMORY)ktxTexture1_SetImageFromMemory, + (PFNKTEXSETIMAGEFROMSTDIOSTREAM)ktxTexture1_SetImageFromStdioStream, + (PFNKTEXWRITETOSTDIOSTREAM)ktxTexture1_WriteToStdioStream, + (PFNKTEXWRITETONAMEDFILE)ktxTexture1_WriteToNamedFile, + (PFNKTEXWRITETOMEMORY)ktxTexture1_WriteToMemory, + (PFNKTEXWRITETOSTREAM)ktxTexture1_WriteToStream, +}; + +/** @} */ + diff --git a/thirdparty/libktx/lib/texture1.h b/thirdparty/libktx/lib/texture1.h new file mode 100644 index 000000000000..95734cc5f746 --- /dev/null +++ b/thirdparty/libktx/lib/texture1.h @@ -0,0 +1,46 @@ +/* -*- tab-width: 4; -*- */ +/* vi: set sw=2 ts=4 expandtab textwidth=70: */ + +/* + * Copyright 2019-2020 The Khronos Group Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @internal + * @file texture1.h + * @~English + * + * @brief Declare internal ktxTexture1 functions for sharing between + * compilation units. + * + * These functions are private and should not be used outside the library. + */ + +#ifndef _TEXTURE1_H_ +#define _TEXTURE1_H_ + +#include "texture.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define CLASS ktxTexture1 +#include "texture_funcs.inl" +#undef CLASS + +KTX_error_code +ktxTexture1_constructFromStreamAndHeader(ktxTexture1* This, ktxStream* pStream, + KTX_header* pHeader, + ktxTextureCreateFlags createFlags); + +ktx_uint64_t ktxTexture1_calcDataSizeTexture(ktxTexture1* This); +ktx_size_t ktxTexture1_calcLevelOffset(ktxTexture1* This, ktx_uint32_t level); +ktx_uint32_t ktxTexture1_glTypeSize(ktxTexture1* This); + +#ifdef __cplusplus +} +#endif + +#endif /* _TEXTURE1_H_ */ diff --git a/thirdparty/libktx/lib/texture2.c b/thirdparty/libktx/lib/texture2.c new file mode 100644 index 000000000000..afbe7dcbfeed --- /dev/null +++ b/thirdparty/libktx/lib/texture2.c @@ -0,0 +1,2524 @@ +/* -*- tab-width: 4; -*- */ +/* vi: set sw=2 ts=4 expandtab: */ + +/* + * Copyright 2019-2020 The Khronos Group Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @internal + * @file texture2.c + * @~English + * + * @brief ktxTexture2 implementation. Support for KTX2 format. + * + * @author Mark Callow, www.edgewise-consulting.com + */ + +#if defined(_WIN32) +#define _CRT_SECURE_NO_WARNINGS +#endif + +#include +#include +#include +#include +#include + +#include "dfdutils/dfd.h" +#include "ktx.h" +#include "ktxint.h" +#include "filestream.h" +#include "memstream.h" +#include "texture2.h" +#include "unused.h" +#include "vk_format.h" + +// FIXME: Test this #define and put it in a header somewhere. +//#define IS_BIG_ENDIAN (1 == *(unsigned char *)&(const int){0x01000000ul}) +#define IS_BIG_ENDIAN 0 + +struct ktxTexture_vtbl ktxTexture2_vtbl; +struct ktxTexture_vtblInt ktxTexture2_vtblInt; + +#if !defined(BITFIELD_ORDER_FROM_MSB) +// Most compilers, including all those tested so far, including clang, gcc +// and msvc, order bitfields from the lsb so these struct declarations work. +// Could this be because I've only tested on little-endian machines? +// These are preferred as they are much easier to manually initialize +// and verify. +struct sampleType { + uint32_t bitOffset: 16; + uint32_t bitLength: 8; + uint32_t channelType: 8; // Includes qualifiers + uint32_t samplePosition0: 8; + uint32_t samplePosition1: 8; + uint32_t samplePosition2: 8; + uint32_t samplePosition3: 8; + uint32_t lower; + uint32_t upper; +}; + +struct BDFD { + uint32_t vendorId: 17; + uint32_t descriptorType: 15; + uint32_t versionNumber: 16; + uint32_t descriptorBlockSize: 16; + uint32_t model: 8; + uint32_t primaries: 8; + uint32_t transfer: 8; + uint32_t flags: 8; + uint32_t texelBlockDimension0: 8; + uint32_t texelBlockDimension1: 8; + uint32_t texelBlockDimension2: 8; + uint32_t texelBlockDimension3: 8; + uint32_t bytesPlane0: 8; + uint32_t bytesPlane1: 8; + uint32_t bytesPlane2: 8; + uint32_t bytesPlane3: 8; + uint32_t bytesPlane4: 8; + uint32_t bytesPlane5: 8; + uint32_t bytesPlane6: 8; + uint32_t bytesPlane7: 8; + struct sampleType samples[6]; +}; + +struct BDFD e5b9g9r9_ufloat_comparator = { + .vendorId = 0, + .descriptorType = 0, + .versionNumber = 2, + .descriptorBlockSize = sizeof(struct BDFD), + .model = KHR_DF_MODEL_RGBSDA, + .primaries = KHR_DF_PRIMARIES_BT709, + .transfer = KHR_DF_TRANSFER_LINEAR, + .flags = KHR_DF_FLAG_ALPHA_STRAIGHT, + .texelBlockDimension0 = 0, + .texelBlockDimension1 = 0, + .texelBlockDimension2 = 0, + .texelBlockDimension3 = 0, + .bytesPlane0 = 4, + .bytesPlane1 = 0, + .bytesPlane2 = 0, + .bytesPlane3 = 0, + .bytesPlane4 = 0, + .bytesPlane5 = 0, + .bytesPlane6 = 0, + .bytesPlane7 = 0, + // gcc likes this way. It does not like, e.g., + // .samples[0].bitOffset = 0, etc. which is accepted by both clang & msvc. + // I find the standards docs impenetrable so I don't know which is correct. + .samples[0] = { + .bitOffset = 0, + .bitLength = 8, + .channelType = KHR_DF_CHANNEL_RGBSDA_RED, + .samplePosition0 = 0, + .samplePosition1 = 0, + .samplePosition2 = 0, + .samplePosition3 = 0, + .lower = 0, + .upper = 8448, + }, + .samples[1] = { + .bitOffset = 27, + .bitLength = 4, + .channelType = KHR_DF_CHANNEL_RGBSDA_RED | KHR_DF_SAMPLE_DATATYPE_EXPONENT, + .samplePosition0 = 0, + .samplePosition1 = 0, + .samplePosition2 = 0, + .samplePosition3 = 0, + .lower = 15, + .upper = 31, + }, + .samples[2] = { + .bitOffset = 9, + .bitLength = 8, + .channelType = KHR_DF_CHANNEL_RGBSDA_GREEN, + .samplePosition0 = 0, + .samplePosition1 = 0, + .samplePosition2 = 0, + .samplePosition3 = 0, + .lower = 0, + .upper = 8448, + }, + .samples[3] = { + .bitOffset = 27, + .bitLength = 4, + .channelType = KHR_DF_CHANNEL_RGBSDA_GREEN | KHR_DF_SAMPLE_DATATYPE_EXPONENT, + .samplePosition0 = 0, + .samplePosition1 = 0, + .samplePosition2 = 0, + .samplePosition3 = 0, + .lower = 15, + .upper = 31, + }, + .samples[4] = { + .bitOffset = 18, + .bitLength = 8, + .channelType = KHR_DF_CHANNEL_RGBSDA_BLUE, + .samplePosition0 = 0, + .samplePosition1 = 0, + .samplePosition2 = 0, + .samplePosition3 = 0, + .lower = 0, + .upper = 8448, + }, + .samples[5] = { + .bitOffset = 27, + .bitLength = 4, + .channelType = KHR_DF_CHANNEL_RGBSDA_BLUE | KHR_DF_SAMPLE_DATATYPE_EXPONENT, + .samplePosition0 = 0, + .samplePosition1 = 0, + .samplePosition2 = 0, + .samplePosition3 = 0, + .lower = 15, + .upper = 31, + } +}; +#else +// For compilers which order bitfields from the msb rather than lsb. +#define shift(x,val) ((val) << KHR_DF_SHIFT_ ## x) +#define sampleshift(x,val) ((val) << KHR_DF_SAMPLESHIFT_ ## x) +#define e5b9g9r9_bdbwordcount KHR_DFDSIZEWORDS(6) +ktx_uint32_t e5b9g9r9_ufloat_comparator[e5b9g9r9_bdbwordcount] = { + 0, // descriptorType & vendorId + shift(DESCRIPTORBLOCKSIZE, e5b9g9r9_bdbwordcount * sizeof(ktx_uint32_t)) | shift(VERSIONNUMBER, 2), + // N.B. Allow various values of primaries, transfer & flags + shift(FLAGS, KHR_DF_FLAG_ALPHA_STRAIGHT) | shift(TRANSFER, KHR_DF_TRANSFER_LINEAR) | shift(PRIMARIES, KHR_DF_PRIMARIES_BT709) | shift(MODEL, KHR_DF_MODEL_RGBSDA), + 0, // texelBlockDimension3~0 + shift(BYTESPLANE0, 4), // All other bytesPlane fields are 0. + 0, // bytesPlane7~4 + sampleshift(CHANNELID, KHR_DF_CHANNEL_RGBSDA_RED) | sampleshift(BITLENGTH, 8) | sampleshift(BITOFFSET, 0), + 0, // samplePosition3~0 + 0, // sampleLower + 8448, // sampleUpper + sampleshift(CHANNELID, KHR_DF_CHANNEL_RGBSDA_RED | KHR_DF_SAMPLE_DATATYPE_EXPONENT) | sampleshift(BITLENGTH, 4) | sampleshift(BITOFFSET, 27), + 0, // samplePosition3~0 + 15, // sampleLower + 31, // sampleUpper + sampleshift(CHANNELID, KHR_DF_CHANNEL_RGBSDA_GREEN) | sampleshift(BITLENGTH, 8) | sampleshift(BITOFFSET, 9), + 0, // samplePosition3~0 + 0, // sampleLower + 8448, // sampleUpper + sampleshift(CHANNELID, KHR_DF_CHANNEL_RGBSDA_GREEN | KHR_DF_SAMPLE_DATATYPE_EXPONENT) | sampleshift(BITLENGTH, 4) | sampleshift(BITOFFSET, 27), + 0, // samplePosition3~0 + 15, // sampleLower + 31, // sampleUpper + sampleshift(CHANNELID, KHR_DF_CHANNEL_RGBSDA_BLUE) | sampleshift(BITLENGTH, 8) | sampleshift(BITOFFSET, 18), + 0, // samplePosition3~0 + 0, // sampleLower + 8448, // sampleUpper + sampleshift(CHANNELID, KHR_DF_CHANNEL_RGBSDA_BLUE | KHR_DF_SAMPLE_DATATYPE_EXPONENT) | sampleshift(BITLENGTH, 4) | sampleshift(BITOFFSET, 27), + 0, // samplePosition3~0 + 15, // sampleLower + 31, // sampleUpper +}; +#endif + +/** +* @private +* @~English +* @brief Initialize a ktxFormatSize object from the info in a DFD. +* +* This is used instead of referring to the DFD directly so code dealing +* with format info can be common to KTX 1 & 2. +* +* @param[in] This pointer the ktxTexture2 whose DFD to use. +* @param[in] fi pointer to the ktxFormatSize object to initialize. +* +* @return KTX_TRUE on success, otherwise KTX_FALSE. +*/ +bool +ktxFormatSize_initFromDfd(ktxFormatSize* This, ktx_uint32_t* pDfd) +{ + uint32_t* pBdb = pDfd + 1; + + // Check the DFD is of the expected type and version. + if (*pBdb != 0) { + // Either decriptorType or vendorId is not 0 + return false; + } + if (KHR_DFDVAL(pBdb, VERSIONNUMBER) != KHR_DF_VERSIONNUMBER_1_3) { + return false; + } + + // DFD has supported type and version. Process it. + This->blockWidth = KHR_DFDVAL(pBdb, TEXELBLOCKDIMENSION0) + 1; + This->blockHeight = KHR_DFDVAL(pBdb, TEXELBLOCKDIMENSION1) + 1; + This->blockDepth = KHR_DFDVAL(pBdb, TEXELBLOCKDIMENSION2) + 1; + This->blockSizeInBits = KHR_DFDVAL(pBdb, BYTESPLANE0) * 8; + This->paletteSizeInBits = 0; // No paletted formats in ktx v2. + This->flags = 0; + This->minBlocksX = This->minBlocksY = 1; + if (KHR_DFDVAL(pBdb, MODEL) >= KHR_DF_MODEL_DXT1A) { + // A block compressed format. Entire block is a single sample. + This->flags |= KTX_FORMAT_SIZE_COMPRESSED_BIT; + if (KHR_DFDVAL(pBdb, MODEL) == KHR_DF_MODEL_PVRTC) { + This->minBlocksX = This->minBlocksY = 2; + } + } else { + // An uncompressed format. + + // Special case depth & depth stencil formats + if (KHR_DFDSVAL(pBdb, 0, CHANNELID) == KHR_DF_CHANNEL_RGBSDA_DEPTH) { + if (KHR_DFDSAMPLECOUNT(pBdb) == 1) { + This->flags |= KTX_FORMAT_SIZE_DEPTH_BIT; + } else if (KHR_DFDSAMPLECOUNT(pBdb) == 2) { + This->flags |= KTX_FORMAT_SIZE_STENCIL_BIT; + This->flags |= KTX_FORMAT_SIZE_DEPTH_BIT; + This->flags |= KTX_FORMAT_SIZE_PACKED_BIT; + } else { + return false; + } + } else if (KHR_DFDSVAL(pBdb, 0, CHANNELID) == KHR_DF_CHANNEL_RGBSDA_STENCIL) { + This->flags |= KTX_FORMAT_SIZE_STENCIL_BIT; + } else if (KHR_DFDSAMPLECOUNT(pBdb) == 6 +#if !defined(BITFIELD_ORDER_FROM_MSB) + && !memcmp(((uint32_t*)&e5b9g9r9_ufloat_comparator) + KHR_DF_WORD_TEXELBLOCKDIMENSION0, &pBdb[KHR_DF_WORD_TEXELBLOCKDIMENSION0], sizeof(e5b9g9r9_ufloat_comparator)-(KHR_DF_WORD_TEXELBLOCKDIMENSION0)*sizeof(uint32_t))) { +#else + && !memcmp(&e5b9g9r9_ufloat_comparator[KHR_DF_WORD_TEXELBLOCKDIMENSION0], &pBdb[KHR_DF_WORD_TEXELBLOCKDIMENSION0], sizeof(e5b9g9r9_ufloat_comparator)-(KHR_DF_WORD_TEXELBLOCKDIMENSION0)*sizeof(uint32_t))) { +#endif + // Special case VK_FORMAT_E5B9G9R9_UFLOAT_PACK32 as interpretDFD + // only handles "simple formats", i.e. where channels are described + // in contiguous bits. + This->flags |= KTX_FORMAT_SIZE_PACKED_BIT; + } else { + InterpretedDFDChannel rgba[4]; + uint32_t wordBytes; + enum InterpretDFDResult result; + + result = interpretDFD(pDfd, &rgba[0], &rgba[1], &rgba[2], &rgba[3], + &wordBytes); + if (result >= i_UNSUPPORTED_ERROR_BIT) + return false; + if (result & i_PACKED_FORMAT_BIT) + This->flags |= KTX_FORMAT_SIZE_PACKED_BIT; + } + } + if (This->blockSizeInBits == 0) { + // The DFD shows a supercompressed texture. Complete the ktxFormatSize + // struct by figuring out the post inflation value for bytesPlane0. + // Setting it here simplifies stuff later in this file. Setting the + // post inflation block size here will not cause any problems for + // the following reasons. (1) in v2 files levelIndex is always used to + // calculate data size and, of course, for the level offsets. (2) Finer + // grain access to supercompressed data than levels is not possible. + uint32_t blockByteLength; + recreateBytesPlane0FromSampleInfo(pDfd, &blockByteLength); + This->blockSizeInBits = blockByteLength * 8; + } + return true; +} + +/** + * @private + * @~English + * @brief Create a DFD for a VkFormat. + * + * This KTX-specific function adds support for combined depth stencil formats + * which are not supported by @e dfdutils' @c vk2dfd function because they + * are not seen outside a Vulkan device. KTX has its own definitions for + * these that enable uploading, with some effort. + * + * @param[in] vkFormat the format for which to create a DFD. + */ +static uint32_t* +ktxVk2dfd(ktx_uint32_t vkFormat) +{ + switch(vkFormat) { + case VK_FORMAT_D16_UNORM_S8_UINT: + // 2 16-bit words. D16 in the first. S8 in the 8 LSBs of the second. + return createDFDDepthStencil(16, 8, 4); + case VK_FORMAT_D24_UNORM_S8_UINT: + // 1 32-bit word. D24 in the MSBs. S8 in the LSBs. + return createDFDDepthStencil(24, 8, 4); + case VK_FORMAT_D32_SFLOAT_S8_UINT: + // 2 32-bit words. D32 float in the first word. S8 in LSBs of the + // second. + return createDFDDepthStencil(32, 8, 8); + default: + return vk2dfd(vkFormat); + } +} + +/** + * @memberof ktxTexture2 @private + * @~English + * @brief Do the part of ktxTexture2 construction that is common to + * new textures and those constructed from a stream. + * + * @param[in] This pointer to a ktxTexture2-sized block of memory to + * initialize. + * @param[in] numLevels the number of levels the texture must have. + * + * @return KTX_SUCCESS on success, other KTX_* enum values on error. + * @exception KTX_OUT_OF_MEMORY Not enough memory for the texture data. + */ +static KTX_error_code +ktxTexture2_constructCommon(ktxTexture2* This, ktx_uint32_t numLevels) +{ + assert(This != NULL); + ktx_size_t privateSize; + + This->classId = ktxTexture2_c; + This->vtbl = &ktxTexture2_vtbl; + This->_protected->_vtbl = ktxTexture2_vtblInt; + privateSize = sizeof(ktxTexture2_private) + + sizeof(ktxLevelIndexEntry) * (numLevels - 1); + This->_private = (ktxTexture2_private*)malloc(privateSize); + if (This->_private == NULL) { + return KTX_OUT_OF_MEMORY; + } + memset(This->_private, 0, privateSize); + return KTX_SUCCESS; +} + +/** + * @memberof ktxTexture2 @private + * @~English + * @brief Construct a new, empty, ktxTexture2. + * + * @param[in] This pointer to a ktxTexture2-sized block of memory to + * initialize. + * @param[in] createInfo pointer to a ktxTextureCreateInfo struct with + * information describing the texture. + * @param[in] storageAllocation + * enum indicating whether or not to allocate storage + * for the texture images. + * @return KTX_SUCCESS on success, other KTX_* enum values on error. + * @exception KTX_OUT_OF_MEMORY Not enough memory for the texture or image data. + * @exception KTX_UNSUPPORTED_TEXTURE_TYPE + * The request VkFormat is one of the + * prohibited formats. + */ +static KTX_error_code +ktxTexture2_construct(ktxTexture2* This, ktxTextureCreateInfo* createInfo, + ktxTextureCreateStorageEnum storageAllocation) +{ + ktxFormatSize formatSize; + KTX_error_code result; + + memset(This, 0, sizeof(*This)); + + if (createInfo->vkFormat != VK_FORMAT_UNDEFINED) { + This->pDfd = ktxVk2dfd(createInfo->vkFormat); + if (!This->pDfd) + return KTX_INVALID_VALUE; // Format is unknown or unsupported. + +#ifdef _DEBUG + // If this fires, an unsupported format or incorrect DFD + // has crept into vk2dfd. + assert(ktxFormatSize_initFromDfd(&formatSize, This->pDfd)); +#else + (void)ktxFormatSize_initFromDfd(&formatSize, This->pDfd); +#endif + + } else { + // TODO: Validate createInfo->pDfd. + This->pDfd = (ktx_uint32_t*)malloc(*createInfo->pDfd); + if (!This->pDfd) + return KTX_OUT_OF_MEMORY; + memcpy(This->pDfd, createInfo->pDfd, *createInfo->pDfd); + if (ktxFormatSize_initFromDfd(&formatSize, This->pDfd)) { + result = KTX_UNSUPPORTED_TEXTURE_TYPE; + goto cleanup; + } + } + + result = ktxTexture_construct(ktxTexture(This), createInfo, &formatSize); + + if (result != KTX_SUCCESS) + return result; + result = ktxTexture2_constructCommon(This, createInfo->numLevels); + if (result != KTX_SUCCESS) + goto cleanup;; + + This->vkFormat = createInfo->vkFormat; + + // Ideally we'd set all these things in ktxFormatSize_initFromDfd + // but This->_protected is not allocated until ktxTexture_construct; + if (This->isCompressed) + This->_protected->_typeSize = 1; + else if (formatSize.flags & KTX_FORMAT_SIZE_PACKED_BIT) + This->_protected->_typeSize = formatSize.blockSizeInBits / 8; + else if (formatSize.flags & (KTX_FORMAT_SIZE_DEPTH_BIT | KTX_FORMAT_SIZE_STENCIL_BIT)) { + if (createInfo->vkFormat == VK_FORMAT_D16_UNORM_S8_UINT) + This->_protected->_typeSize = 2; + else + This->_protected->_typeSize = 4; + } else { + // Unpacked and uncompressed + uint32_t numComponents; + getDFDComponentInfoUnpacked(This->pDfd, &numComponents, + &This->_protected->_typeSize); + } + + This->supercompressionScheme = KTX_SS_NONE; + + This->_private->_requiredLevelAlignment + = ktxTexture2_calcRequiredLevelAlignment(This); + + // Create levelIndex. Offsets are from start of the KTX2 stream. + ktxLevelIndexEntry* levelIndex = This->_private->_levelIndex; + + This->_private->_firstLevelFileOffset = 0; + + for (ktx_uint32_t level = 0; level < This->numLevels; level++) { + levelIndex[level].uncompressedByteLength = + ktxTexture_calcLevelSize(ktxTexture(This), level, + KTX_FORMAT_VERSION_TWO); + levelIndex[level].byteLength = + levelIndex[level].uncompressedByteLength; + levelIndex[level].byteOffset = + ktxTexture_calcLevelOffset(ktxTexture(This), level); + } + + // Allocate storage, if requested. + if (storageAllocation == KTX_TEXTURE_CREATE_ALLOC_STORAGE) { + This->dataSize + = ktxTexture_calcDataSizeTexture(ktxTexture(This)); + This->pData = malloc(This->dataSize); + if (This->pData == NULL) { + result = KTX_OUT_OF_MEMORY; + goto cleanup; + } + } + return result; + +cleanup: + ktxTexture2_destruct(This); + return result; +} + +/** + * @memberof ktxTexture2 @private + * @~English + * @brief Construct a ktxTexture by copying a source ktxTexture. + * + * @param[in] This pointer to a ktxTexture2-sized block of memory to + * initialize. + * @param[in] orig pointer to the source texture to copy. + * + * @return KTX_SUCCESS on success, other KTX_* enum values on error. + * + * @exception KTX_OUT_OF_MEMORY Not enough memory for the texture data. + */ +static KTX_error_code +ktxTexture2_constructCopy(ktxTexture2* This, ktxTexture2* orig) +{ + KTX_error_code result; + + memcpy(This, orig, sizeof(ktxTexture2)); + // Zero all the pointers to make error handling easier + This->_protected = NULL; + This->_private = NULL; + This->pDfd = NULL; + This->kvData = NULL; + This->kvDataHead = NULL; + This->pData = NULL; + + This->_protected = + (ktxTexture_protected*)malloc(sizeof(ktxTexture_protected)); + if (!This->_protected) + return KTX_OUT_OF_MEMORY; + // Must come before memcpy of _protected so as to close an active stream. + if (!orig->pData && ktxTexture_isActiveStream((ktxTexture*)orig)) + ktxTexture2_LoadImageData(orig, NULL, 0); + memcpy(This->_protected, orig->_protected, sizeof(ktxTexture_protected)); + + ktx_size_t privateSize = sizeof(ktxTexture2_private) + + sizeof(ktxLevelIndexEntry) * (orig->numLevels - 1); + This->_private = (ktxTexture2_private*)malloc(privateSize); + if (This->_private == NULL) { + result = KTX_OUT_OF_MEMORY; + goto cleanup; + } + memcpy(This->_private, orig->_private, privateSize); + if (orig->_private->_sgdByteLength > 0) { + This->_private->_supercompressionGlobalData + = (ktx_uint8_t*)malloc(orig->_private->_sgdByteLength); + if (!This->_private->_supercompressionGlobalData) { + result = KTX_OUT_OF_MEMORY; + goto cleanup; + } + memcpy(This->_private->_supercompressionGlobalData, + orig->_private->_supercompressionGlobalData, + orig->_private->_sgdByteLength); + } + + This->pDfd = (ktx_uint32_t*)malloc(*orig->pDfd); + if (!This->pDfd) { + result = KTX_OUT_OF_MEMORY; + goto cleanup; + } + memcpy(This->pDfd, orig->pDfd, *orig->pDfd); + + if (orig->kvDataHead) { + ktxHashList_ConstructCopy(&This->kvDataHead, orig->kvDataHead); + } else if (orig->kvData) { + This->kvData = (ktx_uint8_t*)malloc(orig->kvDataLen); + if (!This->kvData) { + result = KTX_OUT_OF_MEMORY; + goto cleanup; + } + memcpy(This->kvData, orig->kvData, orig->kvDataLen); + } + + // Can't share the image data as the data pointer is exposed in the + // ktxTexture2 structure. Changing it to a ref-counted pointer would + // break code. Maybe that's okay as we're still pre-release. But, + // since this constructor will be mostly be used when transcoding + // supercompressed images, it is probably not too big a deal to make + // a copy of the data. + This->pData = (ktx_uint8_t*)malloc(This->dataSize); + if (This->pData == NULL) { + result = KTX_OUT_OF_MEMORY; + goto cleanup; + } + memcpy(This->pData, orig->pData, orig->dataSize); + return KTX_SUCCESS; + +cleanup: + if (This->_protected) free(This->_protected); + if (This->_private) { + if (This->_private->_supercompressionGlobalData) + free(This->_private->_supercompressionGlobalData); + free(This->_private); + } + if (This->pDfd) free (This->pDfd); + if (This->kvDataHead) ktxHashList_Destruct(&This->kvDataHead); + + return result; +} + +/** + * @memberof ktxTexture2 @private + * @~English + * @brief Construct a ktxTexture from a ktxStream reading from a KTX source. + * + * The KTX header, which must have been read prior to calling this, is passed + * to the function. + * + * The stream object is copied into the constructed ktxTexture2. + * + * The create flag KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT should not be set, + * if the ktxTexture is ultimately to be uploaded to OpenGL or Vulkan. This + * will minimize memory usage by allowing, for example, loading the images + * directly from the source into a Vulkan staging buffer. + * + * The create flag KTX_TEXTURE_CREATE_RAW_KVDATA_BIT should not be used. It is + * provided solely to enable implementation of the @e libktx v1 API on top of + * ktxTexture. + * + * If either KTX_TEXTURE_CREATE_SKIP_KVDATA_BIT or + * KTX_TEXTURE_CREATE_RAW_KVDATA_BIT is set then the ktxTexture's orientation + * fields will be set to defaults even if the KTX source contains + * KTXorientation metadata. + * + * @param[in] This pointer to a ktxTexture2-sized block of memory to + * initialize. + * @param[in] pStream pointer to the stream to read. + * @param[in] pHeader pointer to a KTX header that has already been read from + * the stream. + * @param[in] createFlags bitmask requesting specific actions during creation. + * + * @return KTX_SUCCESS on success, other KTX_* enum values on error. + * + * @exception KTX_FILE_DATA_ERROR + * Source data is inconsistent with the KTX + * specification. + * @exception KTX_FILE_READ_ERROR + * An error occurred while reading the source. + * @exception KTX_FILE_UNEXPECTED_EOF + * Not enough data in the source. + * @exception KTX_OUT_OF_MEMORY Not enough memory to load either the images or + * the key-value data. + * @exception KTX_UNKNOWN_FILE_FORMAT + * The source is not in KTX format. + * @exception KTX_UNSUPPORTED_TEXTURE_TYPE + * The source describes a texture type not + * supported by OpenGL or Vulkan, e.g, a 3D array. + */ +KTX_error_code +ktxTexture2_constructFromStreamAndHeader(ktxTexture2* This, ktxStream* pStream, + KTX_header2* pHeader, + ktxTextureCreateFlags createFlags) +{ + ktxTexture2_private* private; + KTX_error_code result; + KTX_supplemental_info suppInfo; + ktxStream* stream; + ktx_size_t levelIndexSize; + + assert(pHeader != NULL && pStream != NULL); + + memset(This, 0, sizeof(*This)); + result = ktxTexture_constructFromStream(ktxTexture(This), pStream, + createFlags); + if (result != KTX_SUCCESS) + return result; + + result = ktxCheckHeader2_(pHeader, &suppInfo); + if (result != KTX_SUCCESS) + goto cleanup; + // ktxCheckHeader2_ has done the max(1, levelCount) on pHeader->levelCount. + result = ktxTexture2_constructCommon(This, pHeader->levelCount); + if (result != KTX_SUCCESS) + goto cleanup; + private = This->_private; + + stream = ktxTexture2_getStream(This); + + /* + * Initialize from pHeader->info. + */ + This->vkFormat = pHeader->vkFormat; + This->supercompressionScheme = pHeader->supercompressionScheme; + + This->_protected->_typeSize = pHeader->typeSize; + // Can these be done by a ktxTexture_constructFromStream? + This->numDimensions = suppInfo.textureDimension; + This->baseWidth = pHeader->pixelWidth; + assert(suppInfo.textureDimension > 0 && suppInfo.textureDimension < 4); + switch (suppInfo.textureDimension) { + case 1: + This->baseHeight = This->baseDepth = 1; + break; + case 2: + This->baseHeight = pHeader->pixelHeight; + This->baseDepth = 1; + break; + case 3: + This->baseHeight = pHeader->pixelHeight; + This->baseDepth = pHeader->pixelDepth; + break; + } + if (pHeader->layerCount > 0) { + This->numLayers = pHeader->layerCount; + This->isArray = KTX_TRUE; + } else { + This->numLayers = 1; + This->isArray = KTX_FALSE; + } + This->numFaces = pHeader->faceCount; + if (pHeader->faceCount == 6) + This->isCubemap = KTX_TRUE; + else + This->isCubemap = KTX_FALSE; + // ktxCheckHeader2_ does the max(1, levelCount) and sets + // suppInfo.generateMipmaps when it was originally 0. + This->numLevels = pHeader->levelCount; + This->generateMipmaps = suppInfo.generateMipmaps; + + // Read level index + levelIndexSize = sizeof(ktxLevelIndexEntry) * This->numLevels; + result = stream->read(stream, &private->_levelIndex, levelIndexSize); + if (result != KTX_SUCCESS) + goto cleanup; + // Rebase index to start of data and save file offset. + private->_firstLevelFileOffset + = private->_levelIndex[This->numLevels-1].byteOffset; + for (ktx_uint32_t level = 0; level < This->numLevels; level++) { + private->_levelIndex[level].byteOffset + -= private->_firstLevelFileOffset; + } + + // Read DFD + This->pDfd = + (ktx_uint32_t*)malloc(pHeader->dataFormatDescriptor.byteLength); + if (!This->pDfd) { + result = KTX_OUT_OF_MEMORY; + goto cleanup; + } + result = stream->read(stream, This->pDfd, + pHeader->dataFormatDescriptor.byteLength); + if (result != KTX_SUCCESS) + goto cleanup; + + if (!ktxFormatSize_initFromDfd(&This->_protected->_formatSize, This->pDfd)) { + result = KTX_UNSUPPORTED_TEXTURE_TYPE; + goto cleanup; + } + This->isCompressed = (This->_protected->_formatSize.flags & KTX_FORMAT_SIZE_COMPRESSED_BIT); + + if (This->supercompressionScheme == KTX_SS_BASIS_LZ + && KHR_DFDVAL(This->pDfd + 1, MODEL) != KHR_DF_MODEL_ETC1S) + { + result = KTX_FILE_DATA_ERROR; + goto cleanup; + } + + This->_private->_requiredLevelAlignment + = ktxTexture2_calcRequiredLevelAlignment(This); + + // Make an empty hash list. + ktxHashList_Construct(&This->kvDataHead); + // Load KVData. + if (pHeader->keyValueData.byteLength > 0) { + if (!(createFlags & KTX_TEXTURE_CREATE_SKIP_KVDATA_BIT)) { + ktx_uint32_t kvdLen = pHeader->keyValueData.byteLength; + ktx_uint8_t* pKvd; + + pKvd = malloc(kvdLen); + if (pKvd == NULL) { + result = KTX_OUT_OF_MEMORY; + goto cleanup; + } + + result = stream->read(stream, pKvd, kvdLen); + if (result != KTX_SUCCESS) + goto cleanup; + + if (IS_BIG_ENDIAN) { + /* Swap the counts inside the key & value data. */ + ktx_uint8_t* src = pKvd; + ktx_uint8_t* end = pKvd + kvdLen; + while (src < end) { + ktx_uint32_t keyAndValueByteSize = *((ktx_uint32_t*)src); + _ktxSwapEndian32(&keyAndValueByteSize, 1); + src += _KTX_PAD4(keyAndValueByteSize); + } + } + + if (!(createFlags & KTX_TEXTURE_CREATE_RAW_KVDATA_BIT)) { + char* orientationStr; + ktx_uint32_t orientationLen; + ktx_uint32_t animData[3]; + ktx_uint32_t animDataLen; + + result = ktxHashList_Deserialize(&This->kvDataHead, + kvdLen, pKvd); + free(pKvd); + if (result != KTX_SUCCESS) { + goto cleanup; + } + + result = ktxHashList_FindValue(&This->kvDataHead, + KTX_ORIENTATION_KEY, + &orientationLen, + (void**)&orientationStr); + assert(result != KTX_INVALID_VALUE); + if (result == KTX_SUCCESS) { + // Length includes the terminating NUL. + if (orientationLen != This->numDimensions + 1) { + // There needs to be an entry for each dimension of + // the texture. + result = KTX_FILE_DATA_ERROR; + goto cleanup; + } else { + switch (This->numDimensions) { + case 3: + This->orientation.z = orientationStr[2]; + FALLTHROUGH; + case 2: + This->orientation.y = orientationStr[1]; + FALLTHROUGH; + case 1: + This->orientation.x = orientationStr[0]; + } + } + } else { + result = KTX_SUCCESS; // Not finding orientation is okay. + } + result = ktxHashList_FindValue(&This->kvDataHead, + KTX_ANIMDATA_KEY, + &animDataLen, + (void**)animData); + assert(result != KTX_INVALID_VALUE); + if (result == KTX_SUCCESS) { + if (animDataLen != sizeof(animData)) { + result = KTX_FILE_DATA_ERROR; + goto cleanup; + } + if (This->isArray) { + This->isVideo = KTX_TRUE; + This->duration = animData[0]; + This->timescale = animData[1]; + This->loopcount = animData[2]; + } else { + // animData is only valid for array textures. + result = KTX_FILE_DATA_ERROR; + goto cleanup; + } + } else { + result = KTX_SUCCESS; // Not finding video is okay. + } + } else { + This->kvDataLen = kvdLen; + This->kvData = pKvd; + } + } else { + stream->skip(stream, pHeader->keyValueData.byteLength); + } + } + + if (pHeader->supercompressionGlobalData.byteLength > 0) { + // There could be padding here so seek to the next item. + (void)stream->setpos(stream, + pHeader->supercompressionGlobalData.byteOffset); + + // Read supercompressionGlobalData + private->_supercompressionGlobalData = + (ktx_uint8_t*)malloc(pHeader->supercompressionGlobalData.byteLength); + if (!private->_supercompressionGlobalData) { + result = KTX_OUT_OF_MEMORY; + goto cleanup; + } + private->_sgdByteLength + = pHeader->supercompressionGlobalData.byteLength; + result = stream->read(stream, private->_supercompressionGlobalData, + private->_sgdByteLength); + + if (result != KTX_SUCCESS) + goto cleanup; + } + + // Calculate size of the image data. Level 0 is the last level in the data. + This->dataSize = private->_levelIndex[0].byteOffset + + private->_levelIndex[0].byteLength; + + /* + * Load the images, if requested. + */ + if (createFlags & KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT) { + result = ktxTexture2_LoadImageData(This, NULL, 0); + } + if (result != KTX_SUCCESS) + goto cleanup; + + return result; + +cleanup: + ktxTexture2_destruct(This); + return result; +} + +/** + * @memberof ktxTexture2 @private + * @~English + * @brief Construct a ktxTexture from a ktxStream reading from a KTX source. + * + * The stream object is copied into the constructed ktxTexture2. + * + * The create flag KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT should not be set, + * if the ktxTexture is ultimately to be uploaded to OpenGL or Vulkan. This + * will minimize memory usage by allowing, for example, loading the images + * directly from the source into a Vulkan staging buffer. + * + * The create flag KTX_TEXTURE_CREATE_RAW_KVDATA_BIT should not be used. It is + * provided solely to enable implementation of the @e libktx v1 API on top of + * ktxTexture. + * + * @param[in] This pointer to a ktxTexture2-sized block of memory to + * initialize. + * @param[in] pStream pointer to the stream to read. + * @param[in] createFlags bitmask requesting specific actions during creation. + * + * @return KTX_SUCCESS on success, other KTX_* enum values on error. + * + * @exception KTX_FILE_READ_ERROR + * An error occurred while reading the source. + * + * For other exceptions see ktxTexture2_constructFromStreamAndHeader(). + */ +static KTX_error_code +ktxTexture2_constructFromStream(ktxTexture2* This, ktxStream* pStream, + ktxTextureCreateFlags createFlags) +{ + KTX_header2 header; + KTX_error_code result; + + // Read header. + result = pStream->read(pStream, &header, KTX2_HEADER_SIZE); + if (result != KTX_SUCCESS) + return result; + +#if IS_BIG_ENDIAN + // byte swap the header +#endif + return ktxTexture2_constructFromStreamAndHeader(This, pStream, + &header, createFlags); +} + +/** + * @memberof ktxTexture2 @private + * @~English + * @brief Construct a ktxTexture from a stdio stream reading from a KTX source. + * + * See ktxTextureInt_constructFromStream for details. + * + * @note Do not close the stdio stream until you are finished with the texture + * object. + * + * @param[in] This pointer to a ktxTextureInt-sized block of memory to + * initialize. + * @param[in] stdioStream a stdio FILE pointer opened on the source. + * @param[in] createFlags bitmask requesting specific actions during creation. + * + * @return KTX_SUCCESS on success, other KTX_* enum values on error. + * + * @exception KTX_INVALID_VALUE Either @p stdiostream or @p This is null. + * + * For other exceptions, see ktxTexture_constructFromStream(). + */ +static KTX_error_code +ktxTexture2_constructFromStdioStream(ktxTexture2* This, FILE* stdioStream, + ktxTextureCreateFlags createFlags) +{ + KTX_error_code result; + ktxStream stream; + + if (stdioStream == NULL || This == NULL) + return KTX_INVALID_VALUE; + + result = ktxFileStream_construct(&stream, stdioStream, KTX_FALSE); + if (result == KTX_SUCCESS) + result = ktxTexture2_constructFromStream(This, &stream, createFlags); + return result; +} + +/** + * @memberof ktxTexture2 @private + * @~English + * @brief Construct a ktxTexture from a named KTX file. + * + * See ktxTextureInt_constructFromStream for details. + * + * @param[in] This pointer to a ktxTextureInt-sized block of memory to + * initialize. + * @param[in] filename pointer to a char array containing the file name. + * @param[in] createFlags bitmask requesting specific actions during creation. + * + * @return KTX_SUCCESS on success, other KTX_* enum values on error. + * + * @exception KTX_FILE_OPEN_FAILED The file could not be opened. + * @exception KTX_INVALID_VALUE @p filename is @c NULL. + * + * For other exceptions, see ktxTexture_constructFromStream(). + */ +static KTX_error_code +ktxTexture2_constructFromNamedFile(ktxTexture2* This, + const char* const filename, + ktxTextureCreateFlags createFlags) +{ + KTX_error_code result; + ktxStream stream; + FILE* file; + + if (This == NULL || filename == NULL) + return KTX_INVALID_VALUE; + + file = fopen(filename, "rb"); + if (!file) + return KTX_FILE_OPEN_FAILED; + + result = ktxFileStream_construct(&stream, file, KTX_TRUE); + if (result == KTX_SUCCESS) + result = ktxTexture2_constructFromStream(This, &stream, createFlags); + + return result; +} + +/** + * @memberof ktxTexture2 @private + * @~English + * @brief Construct a ktxTexture from KTX-formatted data in memory. + * + * See ktxTextureInt_constructFromStream for details. + * + * @param[in] This pointer to a ktxTextureInt-sized block of memory to + * initialize. + * @param[in] bytes pointer to the memory containing the serialized KTX data. + * @param[in] size length of the KTX data in bytes. + * @param[in] createFlags bitmask requesting specific actions during creation. + * + * @return KTX_SUCCESS on success, other KTX_* enum values on error. + * + * @exception KTX_INVALID_VALUE Either @p bytes is NULL or @p size is 0. + * + * For other exceptions, see ktxTexture_constructFromStream(). + */ +static KTX_error_code +ktxTexture2_constructFromMemory(ktxTexture2* This, + const ktx_uint8_t* bytes, ktx_size_t size, + ktxTextureCreateFlags createFlags) +{ + KTX_error_code result; + ktxStream stream; + + if (bytes == NULL || size == 0) + return KTX_INVALID_VALUE; + + result = ktxMemStream_construct_ro(&stream, bytes, size); + if (result == KTX_SUCCESS) + result = ktxTexture2_constructFromStream(This, &stream, createFlags); + + return result; +} + +/** + * @memberof ktxTexture2 @private + * @~English + * @brief Destruct a ktxTexture2, freeing and internal memory. + * + * @param[in] This pointer to a ktxTexture2-sized block of memory to + * initialize. + */ +void +ktxTexture2_destruct(ktxTexture2* This) +{ + if (This->pDfd) free(This->pDfd); + if (This->_private) { + ktx_uint8_t* sgd = This->_private->_supercompressionGlobalData; + if (sgd) free(sgd); + free(This->_private); + } + ktxTexture_destruct(ktxTexture(This)); +} + +/** + * @memberof ktxTexture2 + * @ingroup writer + * @~English + * @brief Create a new empty ktxTexture2. + * + * The address of the newly created ktxTexture2 is written to the location + * pointed at by @p newTex. + * + * @param[in] createInfo pointer to a ktxTextureCreateInfo struct with + * information describing the texture. + * @param[in] storageAllocation + * enum indicating whether or not to allocate storage + * for the texture images. + * @param[in,out] newTex pointer to a location in which store the address of + * the newly created texture. + * + * @return KTX_SUCCESS on success, other KTX_* enum values on error. + * + * @exception KTX_INVALID_VALUE @c glInternalFormat in @p createInfo is not a + * valid OpenGL internal format value. + * @exception KTX_INVALID_VALUE @c numDimensions in @p createInfo is not 1, 2 + * or 3. + * @exception KTX_INVALID_VALUE One of base{Width,Height,Depth} in + * @p createInfo is 0. + * @exception KTX_INVALID_VALUE @c numFaces in @p createInfo is not 1 or 6. + * @exception KTX_INVALID_VALUE @c numLevels in @p createInfo is 0. + * @exception KTX_INVALID_OPERATION + * The base{Width,Height,Depth} specified + * in @p createInfo are inconsistent with + * @c numDimensions. + * @exception KTX_INVALID_OPERATION + * @p createInfo is requesting a 3D array or + * 3D cubemap texture. + * @exception KTX_INVALID_OPERATION + * @p createInfo is requesting a cubemap with + * non-square or non-2D images. + * @exception KTX_INVALID_OPERATION + * @p createInfo is requesting more mip levels + * than needed for the specified + * base{Width,Height,Depth}. + * @exception KTX_OUT_OF_MEMORY Not enough memory for the texture's images. + */ +KTX_error_code +ktxTexture2_Create(ktxTextureCreateInfo* createInfo, + ktxTextureCreateStorageEnum storageAllocation, + ktxTexture2** newTex) +{ + KTX_error_code result; + + if (newTex == NULL) + return KTX_INVALID_VALUE; + + ktxTexture2* tex = (ktxTexture2*)malloc(sizeof(ktxTexture2)); + if (tex == NULL) + return KTX_OUT_OF_MEMORY; + + result = ktxTexture2_construct(tex, createInfo, storageAllocation); + if (result != KTX_SUCCESS) { + free(tex); + } else { + *newTex = tex; + } + return result; +} + +/** + * @memberof ktxTexture2 + * @ingroup writer + * @~English + * @brief Create a ktxTexture2 by making a copy of a ktxTexture2. + * + * The address of the newly created ktxTexture2 is written to the location + * pointed at by @p newTex. + * + * @param[in] orig pointer to the texture to copy. + * @param[in,out] newTex pointer to a location in which store the address of + * the newly created texture. + * + * @return KTX_SUCCESS on success, other KTX_* enum values on error. + * + * @exception KTX_OUT_OF_MEMORY Not enough memory for the texture data. + */ + KTX_error_code + ktxTexture2_CreateCopy(ktxTexture2* orig, ktxTexture2** newTex) + { + KTX_error_code result; + + if (newTex == NULL) + return KTX_INVALID_VALUE; + + ktxTexture2* tex = (ktxTexture2*)malloc(sizeof(ktxTexture2)); + if (tex == NULL) + return KTX_OUT_OF_MEMORY; + + result = ktxTexture2_constructCopy(tex, orig); + if (result != KTX_SUCCESS) { + free(tex); + } else { + *newTex = tex; + } + return result; + + } + +/** + * @defgroup reader Reader + * @brief Read KTX-formatted data. + * @{ + */ + +/** + * @memberof ktxTexture2 + * @~English + * @brief Create a ktxTexture2 from a stdio stream reading from a KTX source. + * + * The address of a newly created ktxTexture2 reflecting the contents of the + * stdio stream is written to the location pointed at by @p newTex. + * + * The create flag KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT should not be set, + * if the ktxTexture is ultimately to be uploaded to OpenGL or Vulkan. This + * will minimize memory usage by allowing, for example, loading the images + * directly from the source into a Vulkan staging buffer. + * + * The create flag KTX_TEXTURE_CREATE_RAW_KVDATA_BIT should not be used. It is + * provided solely to enable implementation of the @e libktx v1 API on top of + * ktxTexture. + * + * @param[in] stdioStream stdio FILE pointer created from the desired file. + * @param[in] createFlags bitmask requesting specific actions during creation. + * @param[in,out] newTex pointer to a location in which store the address of + * the newly created texture. + * + * @return KTX_SUCCESS on success, other KTX_* enum values on error. + * + * @exception KTX_INVALID_VALUE @p newTex is @c NULL. + * @exception KTX_FILE_DATA_ERROR + * Source data is inconsistent with the KTX + * specification. + * @exception KTX_FILE_READ_ERROR + * An error occurred while reading the source. + * @exception KTX_FILE_UNEXPECTED_EOF + * Not enough data in the source. + * @exception KTX_OUT_OF_MEMORY Not enough memory to create the texture object, + * load the images or load the key-value data. + * @exception KTX_UNKNOWN_FILE_FORMAT + * The source is not in KTX format. + * @exception KTX_UNSUPPORTED_TEXTURE_TYPE + * The source describes a texture type not + * supported by OpenGL or Vulkan, e.g, a 3D array. + */ +KTX_error_code +ktxTexture2_CreateFromStdioStream(FILE* stdioStream, + ktxTextureCreateFlags createFlags, + ktxTexture2** newTex) +{ + KTX_error_code result; + if (newTex == NULL) + return KTX_INVALID_VALUE; + + ktxTexture2* tex = (ktxTexture2*)malloc(sizeof(ktxTexture2)); + if (tex == NULL) + return KTX_OUT_OF_MEMORY; + + result = ktxTexture2_constructFromStdioStream(tex, stdioStream, + createFlags); + if (result == KTX_SUCCESS) + *newTex = (ktxTexture2*)tex; + else { + free(tex); + *newTex = NULL; + } + return result; +} + +/** + * @memberof ktxTexture2 + * @~English + * @brief Create a ktxTexture2 from a named KTX file. + * + * The address of a newly created ktxTexture2 reflecting the contents of the + * file is written to the location pointed at by @p newTex. + * + * The create flag KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT should not be set, + * if the ktxTexture is ultimately to be uploaded to OpenGL or Vulkan. This + * will minimize memory usage by allowing, for example, loading the images + * directly from the source into a Vulkan staging buffer. + * + * The create flag KTX_TEXTURE_CREATE_RAW_KVDATA_BIT should not be used. It is + * provided solely to enable implementation of the @e libktx v1 API on top of + * ktxTexture. + * + * @param[in] filename pointer to a char array containing the file name. + * @param[in] createFlags bitmask requesting specific actions during creation. + * @param[in,out] newTex pointer to a location in which store the address of + * the newly created texture. + * + * @return KTX_SUCCESS on success, other KTX_* enum values on error. + + * @exception KTX_FILE_OPEN_FAILED The file could not be opened. + * @exception KTX_INVALID_VALUE @p filename is @c NULL. + * + * For other exceptions, see ktxTexture_CreateFromStdioStream(). + */ +KTX_error_code +ktxTexture2_CreateFromNamedFile(const char* const filename, + ktxTextureCreateFlags createFlags, + ktxTexture2** newTex) +{ + KTX_error_code result; + + if (newTex == NULL) + return KTX_INVALID_VALUE; + + ktxTexture2* tex = (ktxTexture2*)malloc(sizeof(ktxTexture2)); + if (tex == NULL) + return KTX_OUT_OF_MEMORY; + + result = ktxTexture2_constructFromNamedFile(tex, filename, createFlags); + if (result == KTX_SUCCESS) + *newTex = (ktxTexture2*)tex; + else { + free(tex); + *newTex = NULL; + } + return result; +} + +/** + * @memberof ktxTexture2 + * @~English + * @brief Create a ktxTexture2 from KTX-formatted data in memory. + * + * The address of a newly created ktxTexture2 reflecting the contents of the + * serialized KTX data is written to the location pointed at by @p newTex. + * + * The create flag KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT should not be set, + * if the ktxTexture is ultimately to be uploaded to OpenGL or Vulkan. This + * will minimize memory usage by allowing, for example, loading the images + * directly from the source into a Vulkan staging buffer. + * + * The create flag KTX_TEXTURE_CREATE_RAW_KVDATA_BIT should not be used. It is + * provided solely to enable implementation of the @e libktx v1 API on top of + * ktxTexture. + * + * @param[in] bytes pointer to the memory containing the serialized KTX data. + * @param[in] size length of the KTX data in bytes. + * @param[in] createFlags bitmask requesting specific actions during creation. + * @param[in,out] newTex pointer to a location in which store the address of + * the newly created texture. + * + * @return KTX_SUCCESS on success, other KTX_* enum values on error. + * + * @exception KTX_INVALID_VALUE Either @p bytes is NULL or @p size is 0. + * + * For other exceptions, see ktxTexture_CreateFromStdioStream(). + */ +KTX_error_code +ktxTexture2_CreateFromMemory(const ktx_uint8_t* bytes, ktx_size_t size, + ktxTextureCreateFlags createFlags, + ktxTexture2** newTex) +{ + KTX_error_code result; + if (newTex == NULL) + return KTX_INVALID_VALUE; + + ktxTexture2* tex = (ktxTexture2*)malloc(sizeof(ktxTexture2)); + if (tex == NULL) + return KTX_OUT_OF_MEMORY; + + result = ktxTexture2_constructFromMemory(tex, bytes, size, + createFlags); + if (result == KTX_SUCCESS) + *newTex = (ktxTexture2*)tex; + else { + free(tex); + *newTex = NULL; + } + return result; +} + +/** + * @memberof ktxTexture2 + * @~English + * @brief Create a ktxTexture2 from KTX-formatted data from a stream. + * + * The address of a newly created ktxTexture2 reflecting the contents of the + * serialized KTX data is written to the location pointed at by @p newTex. + * + * The create flag KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT should not be set, + * if the ktxTexture is ultimately to be uploaded to OpenGL or Vulkan. This + * will minimize memory usage by allowing, for example, loading the images + * directly from the source into a Vulkan staging buffer. + * + * The create flag KTX_TEXTURE_CREATE_RAW_KVDATA_BIT should not be used. It is + * provided solely to enable implementation of the @e libktx v1 API on top of + * ktxTexture. + * + * @param[in] stream pointer to the stream to read KTX data from. + * @param[in] createFlags bitmask requesting specific actions during creation. + * @param[in,out] newTex pointer to a location in which store the address of + * the newly created texture. + * + * @return KTX_SUCCESS on success, other KTX_* enum values on error. + * + * @exception KTX_INVALID_VALUE Either @p bytes is NULL or @p size is 0. + * + * For other exceptions, see ktxTexture_CreateFromStdioStream(). + */ +KTX_error_code +ktxTexture2_CreateFromStream(ktxStream* stream, + ktxTextureCreateFlags createFlags, + ktxTexture2** newTex) +{ + KTX_error_code result; + if (newTex == NULL) + return KTX_INVALID_VALUE; + + ktxTexture2* tex = (ktxTexture2*)malloc(sizeof(ktxTexture2)); + if (tex == NULL) + return KTX_OUT_OF_MEMORY; + + result = ktxTexture2_constructFromStream(tex, stream, createFlags); + if (result == KTX_SUCCESS) + *newTex = (ktxTexture2*)tex; + else { + free(tex); + *newTex = NULL; + } + return result; +} + +/** + * @memberof ktxTexture2 + * @~English + * @brief Destroy a ktxTexture2 object. + * + * This frees the memory associated with the texture contents and the memory + * of the ktxTexture2 object. This does @e not delete any OpenGL or Vulkan + * texture objects created by ktxTexture2_GLUpload or ktxTexture2_VkUpload. + * + * @param[in] This pointer to the ktxTexture2 object to destroy + */ +void +ktxTexture2_Destroy(ktxTexture2* This) +{ + ktxTexture2_destruct(This); + free(This); +} + +/** + * @memberof ktxTexture2 @private + * @~English + * @brief Calculate the size of the image data for the specified number + * of levels. + * + * The data size is the sum of the sizes of each level up to the number + * specified and includes any @c mipPadding between levels. It does + * not include initial @c mipPadding required in the file. + * + * @param[in] This pointer to the ktxTexture object of interest. + * @param[in] levels number of levels whose data size to return. + * + * @return the data size in bytes. + */ +ktx_size_t +ktxTexture2_calcDataSizeLevels(ktxTexture2* This, ktx_uint32_t levels) +{ + ktx_size_t dataSize = 0; + + assert(This != NULL); + assert(This->supercompressionScheme == KTX_SS_NONE); + assert(levels <= This->numLevels); + for (ktx_uint32_t i = levels - 1; i > 0; i--) { + ktx_size_t levelSize = ktxTexture_calcLevelSize(ktxTexture(This), i, + KTX_FORMAT_VERSION_TWO); + dataSize += _KTX_PADN(This->_private->_requiredLevelAlignment, + levelSize); + } + dataSize += ktxTexture_calcLevelSize(ktxTexture(This), 0, + KTX_FORMAT_VERSION_TWO); + return dataSize; +} + +/** + * @memberof ktxTexture2 @private + * @~English + * + * @copydoc ktxTexture::ktxTexture_doCalcFaceLodSize + */ +ktx_size_t +ktxTexture2_calcFaceLodSize(ktxTexture2* This, ktx_uint32_t level) +{ + assert(This != NULL); + assert(This->supercompressionScheme == KTX_SS_NONE); + /* + * For non-array cubemaps this is the size of a face. For everything + * else it is the size of the level. + */ + if (This->isCubemap && !This->isArray) + return ktxTexture_calcImageSize(ktxTexture(This), level, + KTX_FORMAT_VERSION_TWO); + else + return This->_private->_levelIndex[level].uncompressedByteLength; +} + +/** + * @memberof ktxTexture2 @private + * @~English + * @brief Return the offset of a level in bytes from the start of the image + * data in a ktxTexture. + * + * Since the offset is from the start of the image data, it does not include the initial + * @c mipPadding required in the file. + * + * @param[in] This pointer to the ktxTexture object of interest. + * @param[in] level level whose offset to return. + * + * @return the data size in bytes. + */ +ktx_size_t +ktxTexture2_calcLevelOffset(ktxTexture2* This, ktx_uint32_t level) +{ + assert (This != NULL); + assert(This->supercompressionScheme == KTX_SS_NONE); + assert (level < This->numLevels); + ktx_size_t levelOffset = 0; + for (ktx_uint32_t i = This->numLevels - 1; i > level; i--) { + ktx_size_t levelSize; + levelSize = ktxTexture_calcLevelSize(ktxTexture(This), i, + KTX_FORMAT_VERSION_TWO); + levelOffset += _KTX_PADN(This->_private->_requiredLevelAlignment, + levelSize); + } + return levelOffset; +} + + +/** + * @memberof ktxTexture2 @private + * @~English + * @brief Retrieve the offset of a level's first image within the KTX2 file. + * + * @param[in] This pointer to the ktxTexture object of interest. + */ +ktx_uint64_t ktxTexture2_levelFileOffset(ktxTexture2* This, ktx_uint32_t level) +{ + assert(This->_private->_firstLevelFileOffset != 0); + return This->_private->_levelIndex[level].byteOffset + + This->_private->_firstLevelFileOffset; +} + +// Recursive function to return the greatest common divisor of a and b. +static uint32_t +gcd(uint32_t a, uint32_t b) { + if (a == 0) + return b; + return gcd(b % a, a); +} + +// Function to return the least common multiple of a & 4. +uint32_t +lcm4(uint32_t a) +{ + if (!(a & 0x03)) + return a; // a is a multiple of 4. + return (a*4) / gcd(a, 4); +} + +/** + * @memberof ktxTexture2 @private + * @~English + * @brief Return the required alignment for levels of this texture. + * + * @param[in] This pointer to the ktxTexture2 object of interest. + * + * @return The required alignment for levels. + */ + ktx_uint32_t + ktxTexture2_calcRequiredLevelAlignment(ktxTexture2* This) + { + ktx_uint32_t alignment; + if (This->supercompressionScheme != KTX_SS_NONE) + alignment = 1; + else + alignment = lcm4(This->_protected->_formatSize.blockSizeInBits / 8); + return alignment; + } + +/** + * @memberof ktxTexture2 @private + * @~English + * @brief Return what the required alignment for levels of this texture will be after inflation. + * + * @param[in] This pointer to the ktxTexture2 object of interest. + * + * @return The required alignment for levels. + */ +ktx_uint32_t +ktxTexture2_calcPostInflationLevelAlignment(ktxTexture2* This) +{ + ktx_uint32_t alignment; + + // Should actually work for none supercompressed but don't want to + // encourage use of it. + assert(This->supercompressionScheme >= KTX_SS_ZSTD); + + if (This->vkFormat != VK_FORMAT_UNDEFINED) + alignment = lcm4(This->_protected->_formatSize.blockSizeInBits / 8); + else + alignment = 16; + + return alignment; +} + + +/** + * @memberof ktxTexture2 + * @~English + * @brief Return information about the components of an image in a texture. + * + * @param[in] This pointer to the ktxTexture object of interest. + * @param[in,out] pNumComponents pointer to location in which to write the + * number of components in the textures images. + * @param[in,out] pComponentByteLength + * pointer to the location in which to write + * byte length of a component. + */ +void +ktxTexture2_GetComponentInfo(ktxTexture2* This, uint32_t* pNumComponents, + uint32_t* pComponentByteLength) +{ + // FIXME Need to handle packed case. + getDFDComponentInfoUnpacked(This->pDfd, pNumComponents, + pComponentByteLength); +} + +/** + * @memberof ktxTexture2 + * @~English + * @brief Return the number of components in an image of the texture. + * + * Returns the number of components indicated by the DFD's sample information + * in accordance with the color model. For uncompressed formats it will be the actual + * number of components in the image. For block-compressed formats, it will be 1 or 2 + * according to the format's DFD color model. For Basis compressed textures, the + * function examines the ids of the channels indicated by the DFD and uses that + * information to determine and return the number of components in the image + * @e before encoding and deflation so it can be used to help choose a suitable + * transcode target format. + * + * @param[in] This pointer to the ktxTexture object of interest. + * + * @return the number of components. + */ +ktx_uint32_t +ktxTexture2_GetNumComponents(ktxTexture2* This) +{ + uint32_t* pBdb = This->pDfd + 1; + uint32_t dfdNumComponents = getDFDNumComponents(This->pDfd); + uint32_t colorModel = KHR_DFDVAL(pBdb, MODEL); + if (colorModel < KHR_DF_MODEL_DXT1A) { + return dfdNumComponents; + } else { + switch (colorModel) { + case KHR_DF_MODEL_ETC1S: + { + uint32_t channel0Id = KHR_DFDSVAL(pBdb, 0, CHANNELID); + if (dfdNumComponents == 1) { + if (channel0Id == KHR_DF_CHANNEL_ETC1S_RGB) + return 3; + else + return 1; + } else { + uint32_t channel1Id = KHR_DFDSVAL(pBdb, 1, CHANNELID); + if (channel0Id == KHR_DF_CHANNEL_ETC1S_RGB + && channel1Id == KHR_DF_CHANNEL_ETC1S_AAA) + return 4; + else { + // An invalid combination of channel Ids should never + // have been set during creation or should have been + // caught when the file was loaded. + assert(channel0Id == KHR_DF_CHANNEL_ETC1S_RRR + && channel1Id == KHR_DF_CHANNEL_ETC1S_GGG); + return 2; + } + } + break; + } + case KHR_DF_MODEL_UASTC: + switch (KHR_DFDSVAL(pBdb, 0, CHANNELID)) { + case KHR_DF_CHANNEL_UASTC_RRR: + return 1; + case KHR_DF_CHANNEL_UASTC_RRRG: + return 2; + case KHR_DF_CHANNEL_UASTC_RGB: + return 3; + case KHR_DF_CHANNEL_UASTC_RGBA: + return 4; + default: + // Same comment as for the assert in the ETC1 case. + assert(false); + return 1; + } + break; + default: + return dfdNumComponents; + } + } +} + +/** + * @memberof ktxTexture2 + * @~English + * @brief Find the offset of an image within a ktxTexture's image data. + * + * As there is no such thing as a 3D cubemap we make the 3rd location parameter + * do double duty. Only works for non-supercompressed textures as + * there is no way to tell where an image is for a supercompressed one. + * + * @param[in] This pointer to the ktxTexture object of interest. + * @param[in] level mip level of the image. + * @param[in] layer array layer of the image. + * @param[in] faceSlice cube map face or depth slice of the image. + * @param[in,out] pOffset pointer to location to store the offset. + * + * @return KTX_SUCCESS on success, other KTX_* enum values on error. + * + * @exception KTX_INVALID_OPERATION + * @p level, @p layer or @p faceSlice exceed the + * dimensions of the texture. + * @exception KTX_INVALID_OPERATION Texture is supercompressed. + * @exception KTX_INVALID_VALID @p This is NULL. + */ +KTX_error_code +ktxTexture2_GetImageOffset(ktxTexture2* This, ktx_uint32_t level, + ktx_uint32_t layer, ktx_uint32_t faceSlice, + ktx_size_t* pOffset) +{ + if (This == NULL) + return KTX_INVALID_VALUE; + + if (level >= This->numLevels || layer >= This->numLayers) + return KTX_INVALID_OPERATION; + + if (This->supercompressionScheme != KTX_SS_NONE) + return KTX_INVALID_OPERATION; + + if (This->isCubemap) { + if (faceSlice >= This->numFaces) + return KTX_INVALID_OPERATION; + } else { + ktx_uint32_t maxSlice = MAX(1, This->baseDepth >> level); + if (faceSlice >= maxSlice) + return KTX_INVALID_OPERATION; + } + + // Get the offset of the start of the level. + *pOffset = ktxTexture2_levelDataOffset(This, level); + + // All layers, faces & slices within a level are the same size. + if (layer != 0) { + ktx_size_t layerSize; + layerSize = ktxTexture_layerSize(ktxTexture(This), level, + KTX_FORMAT_VERSION_TWO); + *pOffset += layer * layerSize; + } + if (faceSlice != 0) { + ktx_size_t imageSize; + imageSize = ktxTexture2_GetImageSize(This, level); + *pOffset += faceSlice * imageSize; + } + return KTX_SUCCESS; +} + +/** + * @memberof ktxTexture2 + * @~English + * @brief Retrieve the opto-electrical transfer function of the images. + * + * @param[in] This pointer to the ktxTexture2 object of interest. + * + * @return A @c khr_df_transfer enum value specifying the OETF. + */ +khr_df_transfer_e +ktxTexture2_GetOETF_e(ktxTexture2* This) +{ + return KHR_DFDVAL(This->pDfd+1, TRANSFER); +} + +/** + * @memberof ktxTexture2 + * @~English + * @brief Retrieve the opto-electrical transfer function of the images. + * @deprecated Retained for backward compatibility. Use ktxTexture2\_GetOETF\_e() + * + * @param[in] This pointer to the ktxTexture2 object of interest. + * + * @return A @c khr_df_transfer enum value specifying the OETF, returned as + * @c ktx_uint32_t. + */ +ktx_uint32_t +ktxTexture2_GetOETF(ktxTexture2* This) +{ + return KHR_DFDVAL(This->pDfd+1, TRANSFER); +} + +/** + * @memberof ktxTexture2 + * @~English + * @brief Retrieve the DFD color model of the images. + * + * @param[in] This pointer to the ktxTexture2 object of interest. + * + * @return A @c khr_df_transfer enum value specifying the color model. + */ +khr_df_model_e +ktxTexture2_GetColorModel_e(ktxTexture2* This) +{ + return KHR_DFDVAL(This->pDfd+1, MODEL); +} + +/** + * @memberof ktxTexture2 + * @~English + * @brief Retrieve whether the RGB components have been premultiplied by the alpha component. + * + * @param[in] This pointer to the ktxTexture2 object of interest. + * + * @return KTX\_TRUE if the components are premultiplied, KTX_FALSE otherwise. + */ +ktx_bool_t +ktxTexture2_GetPremultipliedAlpha(ktxTexture2* This) +{ + return KHR_DFDVAL(This->pDfd+1, FLAGS) & KHR_DF_FLAG_ALPHA_PREMULTIPLIED; +} + +/** + * @memberof ktxTexture2 + * @~English + * @brief Query if the images are in a transcodable format. + * + * @param[in] This pointer to the ktxTexture2 object of interest. + */ +ktx_bool_t +ktxTexture2_NeedsTranscoding(ktxTexture2* This) +{ + if (KHR_DFDVAL(This->pDfd + 1, MODEL) == KHR_DF_MODEL_ETC1S) + return true; + else if (KHR_DFDVAL(This->pDfd + 1, MODEL) == KHR_DF_MODEL_UASTC) + return true; + else + return false; +} + +/** + * @memberof ktxTexture2 + * @~English + * @brief Return the total size in bytes of the uncompressed data of a ktxTexture2. + * + * If supercompressionScheme == KTX_SS_NONE or + * KTX_SS_BASIS_LZ, returns the value of @c This->dataSize + * else if supercompressionScheme == KTX_SS_ZSTD, it returns the + * sum of the uncompressed sizes of each mip level plus space for the level padding. With no + * supercompression the data size and uncompressed data size are the same. For Basis + * supercompression the uncompressed size cannot be known until the data is transcoded + * so the compressed size is returned. + * + * @param[in] This pointer to the ktxTexture1 object of interest. + */ +ktx_size_t +ktxTexture2_GetDataSizeUncompressed(ktxTexture2* This) +{ + switch (This->supercompressionScheme) { + case KTX_SS_BASIS_LZ: + case KTX_SS_NONE: + return This->dataSize; + case KTX_SS_ZSTD: + { + ktx_size_t uncompressedSize = 0; + ktx_uint32_t uncompressedLevelAlignment; + ktxLevelIndexEntry* levelIndex = This->_private->_levelIndex; + + uncompressedLevelAlignment = + ktxTexture2_calcPostInflationLevelAlignment(This); + + for (ktx_int32_t level = This->numLevels - 1; level >= 1; level--) { + ktx_size_t uncompressedLevelSize; + uncompressedLevelSize = levelIndex[level].uncompressedByteLength; + uncompressedLevelSize = _KTX_PADN(uncompressedLevelAlignment, + uncompressedLevelSize); + uncompressedSize += uncompressedLevelSize; + } + uncompressedSize += levelIndex[0].uncompressedByteLength; + return uncompressedSize; + } + case KTX_SS_BEGIN_VENDOR_RANGE: + case KTX_SS_END_VENDOR_RANGE: + case KTX_SS_BEGIN_RESERVED: + default: + return 0; + } +} + +/** + * @memberof ktxTexture2 + * @~English + * @brief Calculate & return the size in bytes of an image at the specified + * mip level. + * + * For arrays, this is the size of a layer, for cubemaps, the size of a face + * and for 3D textures, the size of a depth slice. + * + * The size reflects the padding of each row to KTX_GL_UNPACK_ALIGNMENT. + * + * @param[in] This pointer to the ktxTexture2 object of interest. + * @param[in] level level of interest. * + */ +ktx_size_t +ktxTexture2_GetImageSize(ktxTexture2* This, ktx_uint32_t level) +{ + return ktxTexture_calcImageSize(ktxTexture(This), level, + KTX_FORMAT_VERSION_TWO); +} + +/** + * @memberof ktxTexture2 + * @~English + * @brief Iterate over the mip levels in a ktxTexture2 object. + * + * This is almost identical to ktxTexture_IterateLevelFaces(). The difference is + * that the blocks of image data for non-array cube maps include all faces of + * a mip level. + * + * This function works even if @p This->pData == 0 so it can be used to + * obtain offsets and sizes for each level by callers who have loaded the data + * externally. + * + * Intended for use only when supercompressionScheme == SUPERCOMPRESSION_NONE. + * + * @param[in] This handle of the ktxTexture opened on the data. + * @param[in,out] iterCb the address of a callback function which is called + * with the data for each image block. + * @param[in,out] userdata the address of application-specific data which is + * passed to the callback along with the image data. + * + * @return KTX_SUCCESS on success, other KTX_* enum values on error. The + * following are returned directly by this function. @p iterCb may + * return these for other causes or may return additional errors. + * + * @exception KTX_FILE_DATA_ERROR Mip level sizes are increasing not + * decreasing + * @exception KTX_INVALID_OPERATION supercompressionScheme != SUPERCOMPRESSION_NONE. + * @exception KTX_INVALID_VALUE @p This is @c NULL or @p iterCb is @c NULL. + * + */ +KTX_error_code +ktxTexture2_IterateLevels(ktxTexture2* This, PFNKTXITERCB iterCb, void* userdata) +{ + KTX_error_code result = KTX_SUCCESS; + //ZSTD_DCtx* dctx; + //ktx_uint8_t* decompBuf; + ktxLevelIndexEntry* levelIndex = This->_private->_levelIndex; + + if (This == NULL) + return KTX_INVALID_VALUE; + + if (iterCb == NULL) + return KTX_INVALID_VALUE; + + if (This->supercompressionScheme != KTX_SS_NONE) + return KTX_INVALID_OPERATION; + + for (ktx_int32_t level = This->numLevels - 1; level >= 0; level--) + { + ktx_uint32_t width, height, depth; + ktx_uint64_t levelSize; + ktx_uint64_t offset; + + /* Array textures have the same number of layers at each mip level. */ + width = MAX(1, This->baseWidth >> level); + height = MAX(1, This->baseHeight >> level); + depth = MAX(1, This->baseDepth >> level); + + levelSize = levelIndex[level].uncompressedByteLength; + offset = ktxTexture2_levelDataOffset(This, level); + + /* All array layers are passed in a group because that is how + * GL & Vulkan need them. Hence no + * for (layer = 0; layer < This->numLayers) + */ + result = iterCb(level, 0, width, height, depth, + levelSize, This->pData + offset, userdata); + if (result != KTX_SUCCESS) + break; + } + + return result; +} + +/** + * @memberof ktxTexture2 + * @~English + * @brief Iterate over the images in a ktxTexture2 object while loading the + * image data. + * + * This operates similarly to ktxTexture_IterateLevelFaces() except that it + * loads the images from the ktxTexture2's source to a temporary buffer + * while iterating. If supercompressionScheme == KTX_SS_ZSTD, + * it will inflate the data before passing it to the callback. The callback function + * must copy the image data if it wishes to preserve it as the temporary buffer + * is reused for each level and is freed when this function exits. + * + * This function is helpful for reducing memory usage when uploading the data + * to a graphics API. + * + * Intended for use only when supercompressionScheme == SUPERCOMPRESSION_NONE + * or SUPERCOMPRESSION_ZSTD. As there is no access to the ktxTexture's data on + * conclusion of this function, destroying the texture on completion is recommended. + * + * @param[in] This pointer to the ktxTexture2 object of interest. + * @param[in,out] iterCb the address of a callback function which is called + * with the data for each image. + * @param[in,out] userdata the address of application-specific data which is + * passed to the callback along with the image data. + * + * @return KTX_SUCCESS on success, other KTX_* enum values on error. The + * following are returned directly by this function. @p iterCb may + * return these for other causes or may return additional errors. + * + * @exception KTX_FILE_DATA_ERROR mip level sizes are increasing not + * decreasing + * @exception KTX_INVALID_OPERATION the ktxTexture2 was not created from a + * stream, i.e there is no data to load, or + * this ktxTexture2's images have already + * been loaded. + * @exception KTX_INVALID_OPERATION + * supercompressionScheme != SUPERCOMPRESSION_NONE. + * and supercompressionScheme != SUPERCOMPRESSION_ZSTD. + * @exception KTX_INVALID_VALUE @p This is @c NULL or @p iterCb is @c NULL. + * @exception KTX_OUT_OF_MEMORY not enough memory to allocate a block to + * hold the base level image. + */ +KTX_error_code +ktxTexture2_IterateLoadLevelFaces(ktxTexture2* This, PFNKTXITERCB iterCb, + void* userdata) +{ + DECLARE_PROTECTED(ktxTexture); + ktxStream* stream = (ktxStream *)&prtctd->_stream; + ktxLevelIndexEntry* levelIndex; + ktx_size_t dataSize = 0, uncompressedDataSize = 0; + KTX_error_code result = KTX_SUCCESS; + ktx_uint8_t* dataBuf = NULL; + ktx_uint8_t* uncompressedDataBuf = NULL; + ktx_uint8_t* pData; + ZSTD_DCtx* dctx = NULL; + + if (This == NULL) + return KTX_INVALID_VALUE; + + if (This->classId != ktxTexture2_c) + return KTX_INVALID_OPERATION; + + if (This->supercompressionScheme != KTX_SS_NONE && + This->supercompressionScheme != KTX_SS_ZSTD) + return KTX_INVALID_OPERATION; + + if (iterCb == NULL) + return KTX_INVALID_VALUE; + + if (prtctd->_stream.data.file == NULL) + // This Texture not created from a stream or images are already loaded. + return KTX_INVALID_OPERATION; + + levelIndex = This->_private->_levelIndex; + + // Allocate memory sufficient for the base level + dataSize = levelIndex[0].byteLength; + dataBuf = malloc(dataSize); + if (!dataBuf) + return KTX_OUT_OF_MEMORY; + if (This->supercompressionScheme == KTX_SS_ZSTD) { + uncompressedDataSize = levelIndex[0].uncompressedByteLength; + uncompressedDataBuf = malloc(uncompressedDataSize); + if (!uncompressedDataBuf) { + result = KTX_OUT_OF_MEMORY; + goto cleanup; + } + dctx = ZSTD_createDCtx(); + pData = uncompressedDataBuf; + } else { + pData = dataBuf; + } + + for (ktx_int32_t level = This->numLevels - 1; level >= 0; --level) + { + ktx_size_t levelSize; + GLsizei width, height, depth; + + // Array textures have the same number of layers at each mip level. + width = MAX(1, This->baseWidth >> level); + height = MAX(1, This->baseHeight >> level); + depth = MAX(1, This->baseDepth >> level); + + levelSize = levelIndex[level].byteLength; + if (dataSize < levelSize) { + // Levels cannot be larger than the base level + result = KTX_FILE_DATA_ERROR; + goto cleanup; + } + + // Use setpos so we skip any padding. + result = stream->setpos(stream, + ktxTexture2_levelFileOffset(This, level)); + if (result != KTX_SUCCESS) + goto cleanup; + + result = stream->read(stream, dataBuf, levelSize); + if (result != KTX_SUCCESS) + goto cleanup; + + if (This->supercompressionScheme == KTX_SS_ZSTD) { + levelSize = + ZSTD_decompressDCtx(dctx, uncompressedDataBuf, + uncompressedDataSize, + dataBuf, + levelSize); + if (ZSTD_isError(levelSize)) { + ZSTD_ErrorCode error = ZSTD_getErrorCode(levelSize); + switch(error) { + case ZSTD_error_dstSize_tooSmall: + return KTX_INVALID_VALUE; // inflatedDataCapacity too small. + case ZSTD_error_memory_allocation: + return KTX_OUT_OF_MEMORY; + default: + return KTX_FILE_DATA_ERROR; + } + } + // We don't fix up the texture's dataSize, levelIndex or + // _requiredAlignment because after this function completes there + // is no way to get at the texture's data. + //nindex[level].byteOffset = levelOffset; + //nindex[level].uncompressedByteLength = nindex[level].byteLength = + //levelByteLength; + } + +#if IS_BIG_ENDIAN + switch (prtctd->_typeSize) { + case 2: + _ktxSwapEndian16((ktx_uint16_t*)pData, levelSize / 2); + break; + case 4: + _ktxSwapEndian32((ktx_uint32_t*)pDest, levelSize / 4); + break; + case 8: + _ktxSwapEndian64((ktx_uint64_t*)pDest, levelSize / 8); + break; + } +#endif + + // With the exception of non-array cubemaps the entire level + // is passed at once because that is how OpenGL and Vulkan need them. + // Vulkan could take all the faces at once too but we iterate + // them separately for OpenGL. + if (This->isCubemap && !This->isArray) { + ktx_uint8_t* pFace = pData; + struct blockCount { + ktx_uint32_t x, y; + } blockCount; + ktx_size_t faceSize; + + blockCount.x + = (uint32_t)ceilf((float)width / prtctd->_formatSize.blockWidth); + blockCount.y + = (uint32_t)ceilf((float)height / prtctd->_formatSize.blockHeight); + blockCount.x = MAX(prtctd->_formatSize.minBlocksX, blockCount.x); + blockCount.y = MAX(prtctd->_formatSize.minBlocksX, blockCount.y); + faceSize = blockCount.x * blockCount.y + * prtctd->_formatSize.blockSizeInBits / 8; + + for (ktx_uint32_t face = 0; face < This->numFaces; ++face) { + result = iterCb(level, face, + width, height, depth, + (ktx_uint32_t)faceSize, pFace, userdata); + pFace += faceSize; + if (result != KTX_SUCCESS) + goto cleanup; + } + } else { + result = iterCb(level, 0, + width, height, depth, + (ktx_uint32_t)levelSize, pData, userdata); + if (result != KTX_SUCCESS) + goto cleanup; + } + } + + // No further need for this. + stream->destruct(stream); + This->_private->_firstLevelFileOffset = 0; +cleanup: + free(dataBuf); + if (uncompressedDataBuf) free(uncompressedDataBuf); + if (dctx) ZSTD_freeDCtx(dctx); + + return result; +} + +KTX_error_code +ktxTexture2_inflateZstdInt(ktxTexture2* This, ktx_uint8_t* pDeflatedData, + ktx_uint8_t* pInflatedData, + ktx_size_t inflatedDataCapacity); +/** + * @memberof ktxTexture2 + * @~English + * @brief Load all the image data from the ktxTexture2's source. + * + * The data will be inflated if supercompressionScheme == SUPERCOMPRESSION_ZSTD. + * The data is loaded into the provided buffer or to an internally allocated + * buffer, if @p pBuffer is @c NULL. Callers providing their own buffer must + * ensure the buffer large enough to hold the inflated data for files deflated + * with Zstd. See ktxTexture2_GetDataSizeUncompressed(). + * + * The texture's levelIndex, dataSize, DFD and supercompressionScheme will + * all be updated after successful inflation to reflect the inflated data. + * + * @param[in] This pointer to the ktxTexture object of interest. + * @param[in] pBuffer pointer to the buffer in which to load the image data. + * @param[in] bufSize size of the buffer pointed at by @p pBuffer. + * + * @return KTX_SUCCESS on success, other KTX_* enum values on error. + * + * @exception KTX_INVALID_VALUE @p This is NULL. + * @exception KTX_INVALID_VALUE @p bufSize is less than the the image data size. + * @exception KTX_INVALID_OPERATION + * The data has already been loaded or the + * ktxTexture was not created from a KTX source. + * @exception KTX_OUT_OF_MEMORY Insufficient memory for the image data. + */ +KTX_error_code +ktxTexture2_LoadImageData(ktxTexture2* This, + ktx_uint8_t* pBuffer, ktx_size_t bufSize) +{ + DECLARE_PROTECTED(ktxTexture); + DECLARE_PRIVATE(ktxTexture2); + ktx_uint8_t* pDest; + ktx_uint8_t* pDeflatedData = 0; + ktx_uint8_t* pReadBuf; + KTX_error_code result = KTX_SUCCESS; + ktx_size_t inflatedDataCapacity = ktxTexture2_GetDataSizeUncompressed(This); + + if (This == NULL) + return KTX_INVALID_VALUE; + + if (This->pData != NULL) + return KTX_INVALID_OPERATION; // Data already loaded. + + if (prtctd->_stream.data.file == NULL) + // This Texture not created from a stream or images already loaded; + return KTX_INVALID_OPERATION; + + if (pBuffer == NULL) { + This->pData = malloc(inflatedDataCapacity); + if (This->pData == NULL) + return KTX_OUT_OF_MEMORY; + pDest = This->pData; + } else if (bufSize < inflatedDataCapacity) { + return KTX_INVALID_VALUE; + } else { + pDest = pBuffer; + } + + if (This->supercompressionScheme == KTX_SS_ZSTD) { + // Create buffer to hold deflated data. + pDeflatedData = malloc(This->dataSize); + if (pDeflatedData == NULL) + return KTX_OUT_OF_MEMORY; + pReadBuf = pDeflatedData; + } else { + pReadBuf = pDest; + } + + // Seek to data for first level as there may be padding between the + // metadata/sgd and the image data. + + result = prtctd->_stream.setpos(&prtctd->_stream, + private->_firstLevelFileOffset); + if (result != KTX_SUCCESS) + return result; + + result = prtctd->_stream.read(&prtctd->_stream, pReadBuf, + This->dataSize); + if (result != KTX_SUCCESS) + return result; + + if (This->supercompressionScheme == KTX_SS_ZSTD) { + assert(pDeflatedData != NULL); + result = ktxTexture2_inflateZstdInt(This, pDeflatedData, pDest, + inflatedDataCapacity); + free(pDeflatedData); + if (result != KTX_SUCCESS) { + if (pBuffer == NULL) { + free(This->pData); + This->pData = 0; + } + return result; + } + } + + if (IS_BIG_ENDIAN) { + // Perform endianness conversion on texture data. + // To avoid mip padding, need to convert each level individually. + for (ktx_uint32_t level = 0; level < This->numLevels; ++level) + { + ktx_size_t levelOffset; + ktx_size_t levelByteLength; + + levelByteLength = private->_levelIndex[level].byteLength; + levelOffset = ktxTexture2_levelDataOffset(This, level); + pDest = This->pData + levelOffset; + switch (prtctd->_typeSize) { + case 2: + _ktxSwapEndian16((ktx_uint16_t*)pDest, levelByteLength / 2); + break; + case 4: + _ktxSwapEndian32((ktx_uint32_t*)pDest, levelByteLength / 4); + break; + case 8: + _ktxSwapEndian64((ktx_uint64_t*)pDest, levelByteLength / 8); + break; + } + } + } + + // No further need for stream or file offset. + prtctd->_stream.destruct(&prtctd->_stream); + private->_firstLevelFileOffset = 0; + return result; +} + +/** + * @memberof ktxTexture2 @private + * @~English + * @brief Retrieve the offset of a level's first image within the ktxTexture2's + * image data. + * + * @param[in] This pointer to the ktxTexture2 object of interest. + */ +ktx_uint64_t ktxTexture2_levelDataOffset(ktxTexture2* This, ktx_uint32_t level) +{ + return This->_private->_levelIndex[level].byteOffset; +} + +/** + * @memberof ktxTexture2 @private + * @~English + * @brief Inflate the data in a ktxTexture2 object using Zstandard. + * + * The texture's levelIndex, dataSize, DFD and supercompressionScheme will + * all be updated after successful inflation to reflect the inflated data. + * + * @param[in] This pointer to the ktxTexture2 object of interest. + * @param[in] pDeflatedData pointer to a buffer containing the deflated data + * of the entire texture. + * @param[in,out] pInflatedData pointer to a buffer in which to write the inflated + * data. + * @param[in] inflatedDataCapacity capacity of the buffer pointed at by + * @p pInflatedData. + */ +KTX_error_code +ktxTexture2_inflateZstdInt(ktxTexture2* This, ktx_uint8_t* pDeflatedData, + ktx_uint8_t* pInflatedData, + ktx_size_t inflatedDataCapacity) +{ + DECLARE_PROTECTED(ktxTexture); + ktx_uint32_t levelIndexByteLength = + This->numLevels * sizeof(ktxLevelIndexEntry); + uint64_t levelOffset = 0; + ktxLevelIndexEntry* cindex = This->_private->_levelIndex; + ktxLevelIndexEntry* nindex; + ktx_uint32_t uncompressedLevelAlignment; + + ZSTD_DCtx* dctx; + + if (pDeflatedData == NULL) + return KTX_INVALID_VALUE; + + if (pInflatedData == NULL) + return KTX_INVALID_VALUE; + + if (This->supercompressionScheme != KTX_SS_ZSTD) + return KTX_INVALID_OPERATION; + + nindex = malloc(levelIndexByteLength); + if (nindex == NULL) + return KTX_OUT_OF_MEMORY; + + uncompressedLevelAlignment = + ktxTexture2_calcPostInflationLevelAlignment(This); + + ktx_size_t inflatedByteLength = 0; + dctx = ZSTD_createDCtx(); + for (int32_t level = This->numLevels - 1; level >= 0; level--) { + size_t levelByteLength = + ZSTD_decompressDCtx(dctx, pInflatedData + levelOffset, + inflatedDataCapacity, + &pDeflatedData[cindex[level].byteOffset], + cindex[level].byteLength); + if (ZSTD_isError(levelByteLength)) { + ZSTD_ErrorCode error = ZSTD_getErrorCode(levelByteLength); + switch(error) { + case ZSTD_error_dstSize_tooSmall: + return KTX_INVALID_VALUE; // inflatedDataCapacity too small. + case ZSTD_error_memory_allocation: + return KTX_OUT_OF_MEMORY; + default: + return KTX_FILE_DATA_ERROR; + } + } + nindex[level].byteOffset = levelOffset; + nindex[level].uncompressedByteLength = nindex[level].byteLength = + levelByteLength; + ktx_size_t paddedLevelByteLength + = _KTX_PADN(uncompressedLevelAlignment, levelByteLength); + inflatedByteLength += paddedLevelByteLength; + levelOffset += paddedLevelByteLength; + inflatedDataCapacity -= paddedLevelByteLength; + } + ZSTD_freeDCtx(dctx); + + // Now modify the texture. + + This->dataSize = inflatedByteLength; + This->supercompressionScheme = KTX_SS_NONE; + memcpy(cindex, nindex, levelIndexByteLength); // Update level index + free(nindex); + This->_private->_requiredLevelAlignment = uncompressedLevelAlignment; + // Set bytesPlane as we're now sized. + uint32_t* bdb = This->pDfd + 1; + // blockSizeInBits was set to the inflated size on file load. + bdb[KHR_DF_WORD_BYTESPLANE0] = prtctd->_formatSize.blockSizeInBits / 8; + + return KTX_SUCCESS; +} + +#if !KTX_FEATURE_WRITE + +/* + * Stubs for writer functions that return a proper error code + */ + +KTX_error_code +ktxTexture2_SetImageFromMemory(ktxTexture2* This, ktx_uint32_t level, + ktx_uint32_t layer, ktx_uint32_t faceSlice, + const ktx_uint8_t* src, ktx_size_t srcSize) +{ + UNUSED(This); + UNUSED(level); + UNUSED(layer); + UNUSED(faceSlice); + UNUSED(src); + UNUSED(srcSize); + return KTX_INVALID_OPERATION; +} + +KTX_error_code +ktxTexture2_SetImageFromStdioStream(ktxTexture2* This, ktx_uint32_t level, + ktx_uint32_t layer, ktx_uint32_t faceSlice, + FILE* src, ktx_size_t srcSize) +{ + UNUSED(This); + UNUSED(level); + UNUSED(layer); + UNUSED(faceSlice); + UNUSED(src); + UNUSED(srcSize); + return KTX_INVALID_OPERATION; +} + +KTX_error_code +ktxTexture2_WriteToStdioStream(ktxTexture2* This, FILE* dstsstr) +{ + UNUSED(This); + UNUSED(dstsstr); + return KTX_INVALID_OPERATION; +} + +KTX_error_code +ktxTexture2_WriteToNamedFile(ktxTexture2* This, const char* const dstname) +{ + UNUSED(This); + UNUSED(dstname); + return KTX_INVALID_OPERATION; +} + +KTX_error_code +ktxTexture2_WriteToMemory(ktxTexture2* This, + ktx_uint8_t** ppDstBytes, ktx_size_t* pSize) +{ + UNUSED(This); + UNUSED(ppDstBytes); + UNUSED(pSize); + return KTX_INVALID_OPERATION; +} + +KTX_error_code +ktxTexture2_WriteToStream(ktxTexture2* This, + ktxStream* dststr) +{ + UNUSED(This); + UNUSED(dststr); + return KTX_INVALID_OPERATION; +} + +#endif + +/* + * Initialized here at the end to avoid the need for multiple declarations of + * the virtual functions. + */ + +struct ktxTexture_vtblInt ktxTexture2_vtblInt = { + (PFNCALCDATASIZELEVELS)ktxTexture2_calcDataSizeLevels, + (PFNCALCFACELODSIZE)ktxTexture2_calcFaceLodSize, + (PFNCALCLEVELOFFSET)ktxTexture2_calcLevelOffset +}; + +struct ktxTexture_vtbl ktxTexture2_vtbl = { + (PFNKTEXDESTROY)ktxTexture2_Destroy, + (PFNKTEXGETIMAGEOFFSET)ktxTexture2_GetImageOffset, + (PFNKTEXGETDATASIZEUNCOMPRESSED)ktxTexture2_GetDataSizeUncompressed, + (PFNKTEXGETIMAGESIZE)ktxTexture2_GetImageSize, + (PFNKTEXITERATELEVELS)ktxTexture2_IterateLevels, + (PFNKTEXITERATELOADLEVELFACES)ktxTexture2_IterateLoadLevelFaces, + (PFNKTEXNEEDSTRANSCODING)ktxTexture2_NeedsTranscoding, + (PFNKTEXLOADIMAGEDATA)ktxTexture2_LoadImageData, + (PFNKTEXSETIMAGEFROMMEMORY)ktxTexture2_SetImageFromMemory, + (PFNKTEXSETIMAGEFROMSTDIOSTREAM)ktxTexture2_SetImageFromStdioStream, + (PFNKTEXWRITETOSTDIOSTREAM)ktxTexture2_WriteToStdioStream, + (PFNKTEXWRITETONAMEDFILE)ktxTexture2_WriteToNamedFile, + (PFNKTEXWRITETOMEMORY)ktxTexture2_WriteToMemory, + (PFNKTEXWRITETOSTREAM)ktxTexture2_WriteToStream, +}; + +/** @} */ + diff --git a/thirdparty/libktx/lib/texture2.h b/thirdparty/libktx/lib/texture2.h new file mode 100644 index 000000000000..14e4115ecf76 --- /dev/null +++ b/thirdparty/libktx/lib/texture2.h @@ -0,0 +1,68 @@ +/* -*- tab-width: 4; -*- */ +/* vi: set sw=2 ts=4 expandtab textwidth=70: */ + +/* + * Copyright 2019-2020 The Khronos Group Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @internal + * @file texture2.h + * @~English + * + * @brief Declare internal ktxTexture2 functions for sharing between + * compilation units. + * + * These functions are private and should not be used outside the library. + */ + +#ifndef _TEXTURE2_H_ +#define _TEXTURE2_H_ + +#include "texture.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define CLASS ktxTexture2 +#include "texture_funcs.inl" +#undef CLASS + +typedef struct ktxTexture2_private { + ktx_uint8_t* _supercompressionGlobalData; + ktx_uint32_t _requiredLevelAlignment; + ktx_uint64_t _sgdByteLength; + ktx_uint64_t _firstLevelFileOffset; /*!< Always 0, unless the texture was + created from a stream and the image + data is not yet loaded. */ + // Must be last so it can grow. + ktxLevelIndexEntry _levelIndex[1]; /*!< Offsets in this index are from the + start of the image data. Use + ktxTexture_levelStreamOffset() and + ktxTexture_levelDataOffset(). The former + will add the above file offset to the + index offset. */ +} ktxTexture2_private; + +KTX_error_code +ktxTexture2_LoadImageData(ktxTexture2* This, + ktx_uint8_t* pBuffer, ktx_size_t bufSize); + +KTX_error_code +ktxTexture2_constructFromStreamAndHeader(ktxTexture2* This, ktxStream* pStream, + KTX_header2* pHeader, + ktxTextureCreateFlags createFlags); + +ktx_uint64_t ktxTexture2_calcDataSizeTexture(ktxTexture2* This); +ktx_size_t ktxTexture2_calcLevelOffset(ktxTexture2* This, ktx_uint32_t level); +ktx_uint32_t ktxTexture2_calcRequiredLevelAlignment(ktxTexture2* This); +ktx_uint64_t ktxTexture2_levelFileOffset(ktxTexture2* This, ktx_uint32_t level); +ktx_uint64_t ktxTexture2_levelDataOffset(ktxTexture2* This, ktx_uint32_t level); + +#ifdef __cplusplus +} +#endif + +#endif /* _TEXTURE2_H_ */ diff --git a/thirdparty/libktx/lib/texture_funcs.inl b/thirdparty/libktx/lib/texture_funcs.inl new file mode 100644 index 000000000000..5de16a396b99 --- /dev/null +++ b/thirdparty/libktx/lib/texture_funcs.inl @@ -0,0 +1,76 @@ +/* -*- tab-width: 4; -*- */ +/* vi: set sw=2 ts=4 expandtab textwidth=70: */ + +/* + * Copyright 2019-2020 The Khronos Group Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @internal + * @file texture_funcs.h + * @~English + * + * @brief Templates for functions common to base & derived ktxTexture classes. + * + * Define CLASS before including this file. + */ + +#define CAT(c, n) PRIMITIVE_CAT(c, n) +#define PRIMITIVE_CAT(c, n) c ## _ ## n + +#define CLASS_FUNC(name) CAT(CLASS, name) + +/* + ====================================== + Virtual ktxTexture functions + ====================================== +*/ + + +void CLASS_FUNC(Destroy)(CLASS* This); +KTX_error_code CLASS_FUNC(GetImageOffset)(CLASS* This, ktx_uint32_t level, + ktx_uint32_t layer, + ktx_uint32_t faceSlice, + ktx_size_t* pOffset); +ktx_size_t CLASS_FUNC(GetImageSize)(CLASS* This, ktx_uint32_t level); +KTX_error_code CLASS_FUNC(GLUpload)(CLASS* This, GLuint* pTexture, + GLenum* pTarget, GLenum* pGlerror); +KTX_error_code CLASS_FUNC(IterateLevels)(CLASS* This, + PFNKTXITERCB iterCb, + void* userdata); +KTX_error_code CLASS_FUNC(IterateLevelFaces)(CLASS* This, + PFNKTXITERCB iterCb, + void* userdata); +KTX_error_code CLASS_FUNC(IterateLoadLevelFaces)(CLASS* This, + PFNKTXITERCB iterCb, + void* userdata); +KTX_error_code CLASS_FUNC(LoadImageData)(CLASS* This, + ktx_uint8_t* pBuffer, + ktx_size_t bufSize); +KTX_error_code CLASS_FUNC(SetImageFromStdioStream)(CLASS* This, + ktx_uint32_t level,ktx_uint32_t layer, + ktx_uint32_t faceSlice, + FILE* src, ktx_size_t srcSize); +KTX_error_code CLASS_FUNC(SetImageFromMemory)(CLASS* This, + ktx_uint32_t level, ktx_uint32_t layer, + ktx_uint32_t faceSlice, + const ktx_uint8_t* src, ktx_size_t srcSize); + +KTX_error_code CLASS_FUNC(WriteToStdioStream)(CLASS* This, FILE* dstsstr); +KTX_error_code CLASS_FUNC(WriteToNamedFile)(CLASS* This, + const char* const dstname); +KTX_error_code CLASS_FUNC(WriteToMemory)(CLASS* This, + ktx_uint8_t** ppDstBytes, ktx_size_t* pSize); +KTX_error_code CLASS_FUNC(WriteToStream)(CLASS* This, + ktxStream* dststr); + +/* + ====================================== + Internal ktxTexture functions + ====================================== +*/ + + +void CLASS_FUNC(destruct)(CLASS* This); + diff --git a/thirdparty/libktx/lib/uthash.h b/thirdparty/libktx/lib/uthash.h new file mode 100644 index 000000000000..aa4729027cbd --- /dev/null +++ b/thirdparty/libktx/lib/uthash.h @@ -0,0 +1,942 @@ +/* +Copyright (c) 2003-2010, Troy D. Hanson http://uthash.sourceforge.net All rights reserved. +SPDX-License-Identifier: BSD-1-Clause +*/ + +#ifndef UTHASH_H +#define UTHASH_H + +#include /* memcmp,strlen */ +#include /* ptrdiff_t */ + +/* These macros use decltype or the earlier __typeof GNU extension. + As decltype is only available in newer compilers (VS2010 or gcc 4.3+ + when compiling c++ source) this code uses whatever method is needed + or, for VS2008 where neither is available, uses casting workarounds. */ +#ifdef _MSC_VER /* MS compiler */ +#if _MSC_VER >= 1600 && __cplusplus /* VS2010 or newer in C++ mode */ +#define DECLTYPE(x) (decltype(x)) +#else /* VS2008 or older (or VS2010 in C mode) */ +#define NO_DECLTYPE +#define DECLTYPE(x) +#endif +#else /* GNU, Sun and other compilers */ +#define DECLTYPE(x) (__typeof(x)) +#endif + +#ifdef NO_DECLTYPE +#define DECLTYPE_ASSIGN(dst,src) \ +do { \ + char **_da_dst = (char**)(&(dst)); \ + *_da_dst = (char*)(src); \ +} while(0) +#else +#define DECLTYPE_ASSIGN(dst,src) \ +do { \ + (dst) = DECLTYPE(dst)(src); \ +} while(0) +#endif + +/* a number of the hash function use uint32_t which isn't defined on win32 */ +#ifdef _MSC_VER +typedef unsigned int uint32_t; +#else +#include /* uint32_t */ +#endif + +#define UTHASH_VERSION 1.9.1 + +#define uthash_fatal(msg) exit(-1) /* fatal error (out of memory,etc) */ +#define uthash_malloc(sz) malloc(sz) /* malloc fcn */ +#define uthash_free(ptr) free(ptr) /* free fcn */ + +#define uthash_noexpand_fyi(tbl) /* can be defined to log noexpand */ +#define uthash_expand_fyi(tbl) /* can be defined to log expands */ + +/* initial number of buckets */ +#define HASH_INITIAL_NUM_BUCKETS 32 /* initial number of buckets */ +#define HASH_INITIAL_NUM_BUCKETS_LOG2 5 /* lg2 of initial number of buckets */ +#define HASH_BKT_CAPACITY_THRESH 10 /* expand when bucket count reaches */ + +/* calculate the element whose hash handle address is hhe */ +#define ELMT_FROM_HH(tbl,hhp) ((void*)(((char*)(hhp)) - ((tbl)->hho))) + +#define HASH_FIND(hh,head,keyptr,keylen,out) \ +do { \ + unsigned _hf_bkt,_hf_hashv; \ + out=NULL; \ + if (head) { \ + HASH_FCN(keyptr,keylen, (head)->hh.tbl->num_buckets, _hf_hashv, _hf_bkt); \ + if (HASH_BLOOM_TEST((head)->hh.tbl, _hf_hashv)) { \ + HASH_FIND_IN_BKT((head)->hh.tbl, hh, (head)->hh.tbl->buckets[ _hf_bkt ], \ + keyptr,keylen,out); \ + } \ + } \ +} while (0) + +#ifdef HASH_BLOOM +#define HASH_BLOOM_BITLEN (1ULL << HASH_BLOOM) +#define HASH_BLOOM_BYTELEN (HASH_BLOOM_BITLEN/8) + ((HASH_BLOOM_BITLEN%8) ? 1:0) +#define HASH_BLOOM_MAKE(tbl) \ +do { \ + (tbl)->bloom_nbits = HASH_BLOOM; \ + (tbl)->bloom_bv = (uint8_t*)uthash_malloc(HASH_BLOOM_BYTELEN); \ + if (!((tbl)->bloom_bv)) { uthash_fatal( "out of memory"); } \ + memset((tbl)->bloom_bv, 0, HASH_BLOOM_BYTELEN); \ + (tbl)->bloom_sig = HASH_BLOOM_SIGNATURE; \ +} while (0); + +#define HASH_BLOOM_FREE(tbl) \ +do { \ + uthash_free((tbl)->bloom_bv); \ +} while (0); + +#define HASH_BLOOM_BITSET(bv,idx) (bv[(idx)/8] |= (1U << ((idx)%8))) +#define HASH_BLOOM_BITTEST(bv,idx) (bv[(idx)/8] & (1U << ((idx)%8))) + +#define HASH_BLOOM_ADD(tbl,hashv) \ + HASH_BLOOM_BITSET((tbl)->bloom_bv, (hashv & (uint32_t)((1ULL << (tbl)->bloom_nbits) - 1))) + +#define HASH_BLOOM_TEST(tbl,hashv) \ + HASH_BLOOM_BITTEST((tbl)->bloom_bv, (hashv & (uint32_t)((1ULL << (tbl)->bloom_nbits) - 1))) + +#else +#define HASH_BLOOM_MAKE(tbl) +#define HASH_BLOOM_FREE(tbl) +#define HASH_BLOOM_ADD(tbl,hashv) +#define HASH_BLOOM_TEST(tbl,hashv) (1) +#endif + +#define HASH_MAKE_TABLE(hh,head) \ +do { \ + (head)->hh.tbl = (UT_hash_table*)uthash_malloc( \ + sizeof(UT_hash_table)); \ + if (!((head)->hh.tbl)) { uthash_fatal( "out of memory"); } \ + memset((head)->hh.tbl, 0, sizeof(UT_hash_table)); \ + (head)->hh.tbl->tail = &((head)->hh); \ + (head)->hh.tbl->num_buckets = HASH_INITIAL_NUM_BUCKETS; \ + (head)->hh.tbl->log2_num_buckets = HASH_INITIAL_NUM_BUCKETS_LOG2; \ + (head)->hh.tbl->hho = (char*)(&(head)->hh) - (char*)(head); \ + (head)->hh.tbl->buckets = (UT_hash_bucket*)uthash_malloc( \ + HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \ + if (! (head)->hh.tbl->buckets) { uthash_fatal( "out of memory"); } \ + memset((head)->hh.tbl->buckets, 0, \ + HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \ + HASH_BLOOM_MAKE((head)->hh.tbl); \ + (head)->hh.tbl->signature = HASH_SIGNATURE; \ +} while(0) + +#define HASH_ADD(hh,head,fieldname,keylen_in,add) \ + HASH_ADD_KEYPTR(hh,head,&add->fieldname,keylen_in,add) + +#define HASH_ADD_KEYPTR(hh,head,keyptr,keylen_in,add) \ +do { \ + unsigned _ha_bkt; \ + (add)->hh.next = NULL; \ + (add)->hh.key = (char*)keyptr; \ + (add)->hh.keylen = keylen_in; \ + if (!(head)) { \ + head = (add); \ + (head)->hh.prev = NULL; \ + HASH_MAKE_TABLE(hh,head); \ + } else { \ + (head)->hh.tbl->tail->next = (add); \ + (add)->hh.prev = ELMT_FROM_HH((head)->hh.tbl, (head)->hh.tbl->tail); \ + (head)->hh.tbl->tail = &((add)->hh); \ + } \ + (head)->hh.tbl->num_items++; \ + (add)->hh.tbl = (head)->hh.tbl; \ + HASH_FCN(keyptr,keylen_in, (head)->hh.tbl->num_buckets, \ + (add)->hh.hashv, _ha_bkt); \ + HASH_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt],&(add)->hh); \ + HASH_BLOOM_ADD((head)->hh.tbl,(add)->hh.hashv); \ + HASH_EMIT_KEY(hh,head,keyptr,keylen_in); \ + HASH_FSCK(hh,head); \ +} while(0) + +#define HASH_TO_BKT( hashv, num_bkts, bkt ) \ +do { \ + bkt = ((hashv) & ((num_bkts) - 1)); \ +} while(0) + +/* delete "delptr" from the hash table. + * "the usual" patch-up process for the app-order doubly-linked-list. + * The use of _hd_hh_del below deserves special explanation. + * These used to be expressed using (delptr) but that led to a bug + * if someone used the same symbol for the head and deletee, like + * HASH_DELETE(hh,users,users); + * We want that to work, but by changing the head (users) below + * we were forfeiting our ability to further refer to the deletee (users) + * in the patch-up process. Solution: use scratch space to + * copy the deletee pointer, then the latter references are via that + * scratch pointer rather than through the repointed (users) symbol. + */ +#define HASH_DELETE(hh,head,delptr) \ +do { \ + unsigned _hd_bkt; \ + struct UT_hash_handle *_hd_hh_del; \ + if ( ((delptr)->hh.prev == NULL) && ((delptr)->hh.next == NULL) ) { \ + uthash_free((head)->hh.tbl->buckets ); \ + HASH_BLOOM_FREE((head)->hh.tbl); \ + uthash_free((head)->hh.tbl); \ + head = NULL; \ + } else { \ + _hd_hh_del = &((delptr)->hh); \ + if ((delptr) == ELMT_FROM_HH((head)->hh.tbl,(head)->hh.tbl->tail)) { \ + (head)->hh.tbl->tail = \ + (UT_hash_handle*)((char*)((delptr)->hh.prev) + \ + (head)->hh.tbl->hho); \ + } \ + if ((delptr)->hh.prev) { \ + ((UT_hash_handle*)((char*)((delptr)->hh.prev) + \ + (head)->hh.tbl->hho))->next = (delptr)->hh.next; \ + } else { \ + DECLTYPE_ASSIGN(head,(delptr)->hh.next); \ + } \ + if (_hd_hh_del->next) { \ + ((UT_hash_handle*)((char*)_hd_hh_del->next + \ + (head)->hh.tbl->hho))->prev = \ + _hd_hh_del->prev; \ + } \ + HASH_TO_BKT( _hd_hh_del->hashv, (head)->hh.tbl->num_buckets, _hd_bkt); \ + HASH_DEL_IN_BKT(hh,(head)->hh.tbl->buckets[_hd_bkt], _hd_hh_del); \ + (head)->hh.tbl->num_items--; \ + } \ + HASH_FSCK(hh,head); \ +} while (0) + + +/* convenience forms of HASH_FIND/HASH_ADD/HASH_DEL */ +#define HASH_FIND_STR(head,findstr,out) \ + HASH_FIND(hh,head,findstr,strlen(findstr),out) +#define HASH_ADD_STR(head,strfield,add) \ + HASH_ADD(hh,head,strfield,strlen(add->strfield),add) +#define HASH_FIND_INT(head,findint,out) \ + HASH_FIND(hh,head,findint,sizeof(int),out) +#define HASH_ADD_INT(head,intfield,add) \ + HASH_ADD(hh,head,intfield,sizeof(int),add) +#define HASH_FIND_PTR(head,findptr,out) \ + HASH_FIND(hh,head,findptr,sizeof(void *),out) +#define HASH_ADD_PTR(head,ptrfield,add) \ + HASH_ADD(hh,head,ptrfield,sizeof(void *),add) +#define HASH_DEL(head,delptr) \ + HASH_DELETE(hh,head,delptr) + +/* HASH_FSCK checks hash integrity on every add/delete when HASH_DEBUG is defined. + * This is for uthash developer only; it compiles away if HASH_DEBUG isn't defined. + */ +#ifdef HASH_DEBUG +#define HASH_OOPS(...) do { fprintf(stderr,__VA_ARGS__); exit(-1); } while (0) +#define HASH_FSCK(hh,head) \ +do { \ + unsigned _bkt_i; \ + unsigned _count, _bkt_count; \ + char *_prev; \ + struct UT_hash_handle *_thh; \ + if (head) { \ + _count = 0; \ + for( _bkt_i = 0; _bkt_i < (head)->hh.tbl->num_buckets; _bkt_i++) { \ + _bkt_count = 0; \ + _thh = (head)->hh.tbl->buckets[_bkt_i].hh_head; \ + _prev = NULL; \ + while (_thh) { \ + if (_prev != (char*)(_thh->hh_prev)) { \ + HASH_OOPS("invalid hh_prev %p, actual %p\n", \ + _thh->hh_prev, _prev ); \ + } \ + _bkt_count++; \ + _prev = (char*)(_thh); \ + _thh = _thh->hh_next; \ + } \ + _count += _bkt_count; \ + if ((head)->hh.tbl->buckets[_bkt_i].count != _bkt_count) { \ + HASH_OOPS("invalid bucket count %d, actual %d\n", \ + (head)->hh.tbl->buckets[_bkt_i].count, _bkt_count); \ + } \ + } \ + if (_count != (head)->hh.tbl->num_items) { \ + HASH_OOPS("invalid hh item count %d, actual %d\n", \ + (head)->hh.tbl->num_items, _count ); \ + } \ + /* traverse hh in app order; check next/prev integrity, count */ \ + _count = 0; \ + _prev = NULL; \ + _thh = &(head)->hh; \ + while (_thh) { \ + _count++; \ + if (_prev !=(char*)(_thh->prev)) { \ + HASH_OOPS("invalid prev %p, actual %p\n", \ + _thh->prev, _prev ); \ + } \ + _prev = (char*)ELMT_FROM_HH((head)->hh.tbl, _thh); \ + _thh = ( _thh->next ? (UT_hash_handle*)((char*)(_thh->next) + \ + (head)->hh.tbl->hho) : NULL ); \ + } \ + if (_count != (head)->hh.tbl->num_items) { \ + HASH_OOPS("invalid app item count %d, actual %d\n", \ + (head)->hh.tbl->num_items, _count ); \ + } \ + } \ +} while (0) +#else +#define HASH_FSCK(hh,head) +#endif + +/* When compiled with -DHASH_EMIT_KEYS, length-prefixed keys are emitted to + * the descriptor to which this macro is defined for tuning the hash function. + * The app can #include to get the prototype for write(2). */ +#ifdef HASH_EMIT_KEYS +#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) \ +do { \ + unsigned _klen = fieldlen; \ + write(HASH_EMIT_KEYS, &_klen, sizeof(_klen)); \ + write(HASH_EMIT_KEYS, keyptr, fieldlen); \ +} while (0) +#else +#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) +#endif + +/* default to Jenkin's hash unless overridden e.g. DHASH_FUNCTION=HASH_SAX */ +#ifdef HASH_FUNCTION +#define HASH_FCN HASH_FUNCTION +#else +#define HASH_FCN HASH_JEN +#endif + +/* The Bernstein hash function, used in Perl prior to v5.6 */ +#define HASH_BER(key,keylen,num_bkts,hashv,bkt) \ +do { \ + unsigned _hb_keylen=keylen; \ + char *_hb_key=(char*)key; \ + (hashv) = 0; \ + while (_hb_keylen--) { (hashv) = ((hashv) * 33) + *_hb_key++; } \ + bkt = (hashv) & (num_bkts-1); \ +} while (0) + + +/* SAX/FNV/OAT/JEN hash functions are macro variants of those listed at + * http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx */ +#define HASH_SAX(key,keylen,num_bkts,hashv,bkt) \ +do { \ + unsigned _sx_i; \ + char *_hs_key=(char*)key; \ + hashv = 0; \ + for(_sx_i=0; _sx_i < keylen; _sx_i++) \ + hashv ^= (hashv << 5) + (hashv >> 2) + _hs_key[_sx_i]; \ + bkt = hashv & (num_bkts-1); \ +} while (0) + +#define HASH_FNV(key,keylen,num_bkts,hashv,bkt) \ +do { \ + unsigned _fn_i; \ + char *_hf_key=(char*)key; \ + hashv = 2166136261UL; \ + for(_fn_i=0; _fn_i < keylen; _fn_i++) \ + hashv = (hashv * 16777619) ^ _hf_key[_fn_i]; \ + bkt = hashv & (num_bkts-1); \ +} while(0); + +#define HASH_OAT(key,keylen,num_bkts,hashv,bkt) \ +do { \ + unsigned _ho_i; \ + char *_ho_key=(char*)key; \ + hashv = 0; \ + for(_ho_i=0; _ho_i < keylen; _ho_i++) { \ + hashv += _ho_key[_ho_i]; \ + hashv += (hashv << 10); \ + hashv ^= (hashv >> 6); \ + } \ + hashv += (hashv << 3); \ + hashv ^= (hashv >> 11); \ + hashv += (hashv << 15); \ + bkt = hashv & (num_bkts-1); \ +} while(0) + +#define HASH_JEN_MIX(a,b,c) \ +do { \ + a -= b; a -= c; a ^= ( c >> 13 ); \ + b -= c; b -= a; b ^= ( a << 8 ); \ + c -= a; c -= b; c ^= ( b >> 13 ); \ + a -= b; a -= c; a ^= ( c >> 12 ); \ + b -= c; b -= a; b ^= ( a << 16 ); \ + c -= a; c -= b; c ^= ( b >> 5 ); \ + a -= b; a -= c; a ^= ( c >> 3 ); \ + b -= c; b -= a; b ^= ( a << 10 ); \ + c -= a; c -= b; c ^= ( b >> 15 ); \ +} while (0) + +#define HASH_JEN(key,keylen,num_bkts,hashv,bkt) \ +do { \ + unsigned _hj_i,_hj_j,_hj_k; \ + char *_hj_key=(char*)key; \ + hashv = 0xfeedbeef; \ + _hj_i = _hj_j = 0x9e3779b9; \ + _hj_k = keylen; \ + while (_hj_k >= 12) { \ + _hj_i += (_hj_key[0] + ( (unsigned)_hj_key[1] << 8 ) \ + + ( (unsigned)_hj_key[2] << 16 ) \ + + ( (unsigned)_hj_key[3] << 24 ) ); \ + _hj_j += (_hj_key[4] + ( (unsigned)_hj_key[5] << 8 ) \ + + ( (unsigned)_hj_key[6] << 16 ) \ + + ( (unsigned)_hj_key[7] << 24 ) ); \ + hashv += (_hj_key[8] + ( (unsigned)_hj_key[9] << 8 ) \ + + ( (unsigned)_hj_key[10] << 16 ) \ + + ( (unsigned)_hj_key[11] << 24 ) ); \ + \ + HASH_JEN_MIX(_hj_i, _hj_j, hashv); \ + \ + _hj_key += 12; \ + _hj_k -= 12; \ + } \ + hashv += keylen; \ + switch ( _hj_k ) { \ + case 11: hashv += ( (unsigned)_hj_key[10] << 24 ); \ + case 10: hashv += ( (unsigned)_hj_key[9] << 16 ); \ + case 9: hashv += ( (unsigned)_hj_key[8] << 8 ); \ + case 8: _hj_j += ( (unsigned)_hj_key[7] << 24 ); \ + case 7: _hj_j += ( (unsigned)_hj_key[6] << 16 ); \ + case 6: _hj_j += ( (unsigned)_hj_key[5] << 8 ); \ + case 5: _hj_j += _hj_key[4]; \ + case 4: _hj_i += ( (unsigned)_hj_key[3] << 24 ); \ + case 3: _hj_i += ( (unsigned)_hj_key[2] << 16 ); \ + case 2: _hj_i += ( (unsigned)_hj_key[1] << 8 ); \ + case 1: _hj_i += _hj_key[0]; \ + } \ + HASH_JEN_MIX(_hj_i, _hj_j, hashv); \ + bkt = hashv & (num_bkts-1); \ +} while(0) + +/* The Paul Hsieh hash function */ +#undef get16bits +#if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \ + || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__) +#define get16bits(d) (*((const uint16_t *) (d))) +#endif + +#if !defined (get16bits) +#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8) \ + +(uint32_t)(((const uint8_t *)(d))[0]) ) +#endif +#define HASH_SFH(key,keylen,num_bkts,hashv,bkt) \ +do { \ + char *_sfh_key=(char*)key; \ + uint32_t _sfh_tmp, _sfh_len = keylen; \ + \ + int _sfh_rem = _sfh_len & 3; \ + _sfh_len >>= 2; \ + hashv = 0xcafebabe; \ + \ + /* Main loop */ \ + for (;_sfh_len > 0; _sfh_len--) { \ + hashv += get16bits (_sfh_key); \ + _sfh_tmp = (get16bits (_sfh_key+2) << 11) ^ hashv; \ + hashv = (hashv << 16) ^ _sfh_tmp; \ + _sfh_key += 2*sizeof (uint16_t); \ + hashv += hashv >> 11; \ + } \ + \ + /* Handle end cases */ \ + switch (_sfh_rem) { \ + case 3: hashv += get16bits (_sfh_key); \ + hashv ^= hashv << 16; \ + hashv ^= _sfh_key[sizeof (uint16_t)] << 18; \ + hashv += hashv >> 11; \ + break; \ + case 2: hashv += get16bits (_sfh_key); \ + hashv ^= hashv << 11; \ + hashv += hashv >> 17; \ + break; \ + case 1: hashv += *_sfh_key; \ + hashv ^= hashv << 10; \ + hashv += hashv >> 1; \ + } \ + \ + /* Force "avalanching" of final 127 bits */ \ + hashv ^= hashv << 3; \ + hashv += hashv >> 5; \ + hashv ^= hashv << 4; \ + hashv += hashv >> 17; \ + hashv ^= hashv << 25; \ + hashv += hashv >> 6; \ + bkt = hashv & (num_bkts-1); \ +} while(0); + +#ifdef HASH_USING_NO_STRICT_ALIASING +/* The MurmurHash exploits some CPU's (e.g. x86) tolerance for unaligned reads. + * For other types of CPU's (e.g. Sparc) an unaligned read causes a bus error. + * So MurmurHash comes in two versions, the faster unaligned one and the slower + * aligned one. We only use the faster one on CPU's where we know it's safe. + * + * Note the preprocessor built-in defines can be emitted using: + * + * gcc -m64 -dM -E - < /dev/null (on gcc) + * cc -## a.c (where a.c is a simple test file) (Sun Studio) + */ +#if (defined(__i386__) || defined(__x86_64__)) +#define HASH_MUR HASH_MUR_UNALIGNED +#else +#define HASH_MUR HASH_MUR_ALIGNED +#endif + +/* Appleby's MurmurHash fast version for unaligned-tolerant archs like i386 */ +#define HASH_MUR_UNALIGNED(key,keylen,num_bkts,hashv,bkt) \ +do { \ + const unsigned int _mur_m = 0x5bd1e995; \ + const int _mur_r = 24; \ + hashv = 0xcafebabe ^ keylen; \ + char *_mur_key = (char *)key; \ + uint32_t _mur_tmp, _mur_len = keylen; \ + \ + for (;_mur_len >= 4; _mur_len-=4) { \ + _mur_tmp = *(uint32_t *)_mur_key; \ + _mur_tmp *= _mur_m; \ + _mur_tmp ^= _mur_tmp >> _mur_r; \ + _mur_tmp *= _mur_m; \ + hashv *= _mur_m; \ + hashv ^= _mur_tmp; \ + _mur_key += 4; \ + } \ + \ + switch(_mur_len) \ + { \ + case 3: hashv ^= _mur_key[2] << 16; \ + case 2: hashv ^= _mur_key[1] << 8; \ + case 1: hashv ^= _mur_key[0]; \ + hashv *= _mur_m; \ + }; \ + \ + hashv ^= hashv >> 13; \ + hashv *= _mur_m; \ + hashv ^= hashv >> 15; \ + \ + bkt = hashv & (num_bkts-1); \ +} while(0) + +/* Appleby's MurmurHash version for alignment-sensitive archs like Sparc */ +#define HASH_MUR_ALIGNED(key,keylen,num_bkts,hashv,bkt) \ +do { \ + const unsigned int _mur_m = 0x5bd1e995; \ + const int _mur_r = 24; \ + hashv = 0xcafebabe ^ keylen; \ + char *_mur_key = (char *)key; \ + uint32_t _mur_len = keylen; \ + int _mur_align = (int)_mur_key & 3; \ + \ + if (_mur_align && (_mur_len >= 4)) { \ + unsigned _mur_t = 0, _mur_d = 0; \ + switch(_mur_align) { \ + case 1: _mur_t |= _mur_key[2] << 16; \ + case 2: _mur_t |= _mur_key[1] << 8; \ + case 3: _mur_t |= _mur_key[0]; \ + } \ + _mur_t <<= (8 * _mur_align); \ + _mur_key += 4-_mur_align; \ + _mur_len -= 4-_mur_align; \ + int _mur_sl = 8 * (4-_mur_align); \ + int _mur_sr = 8 * _mur_align; \ + \ + for (;_mur_len >= 4; _mur_len-=4) { \ + _mur_d = *(unsigned *)_mur_key; \ + _mur_t = (_mur_t >> _mur_sr) | (_mur_d << _mur_sl); \ + unsigned _mur_k = _mur_t; \ + _mur_k *= _mur_m; \ + _mur_k ^= _mur_k >> _mur_r; \ + _mur_k *= _mur_m; \ + hashv *= _mur_m; \ + hashv ^= _mur_k; \ + _mur_t = _mur_d; \ + _mur_key += 4; \ + } \ + _mur_d = 0; \ + if(_mur_len >= _mur_align) { \ + switch(_mur_align) { \ + case 3: _mur_d |= _mur_key[2] << 16; \ + case 2: _mur_d |= _mur_key[1] << 8; \ + case 1: _mur_d |= _mur_key[0]; \ + } \ + unsigned _mur_k = (_mur_t >> _mur_sr) | (_mur_d << _mur_sl); \ + _mur_k *= _mur_m; \ + _mur_k ^= _mur_k >> _mur_r; \ + _mur_k *= _mur_m; \ + hashv *= _mur_m; \ + hashv ^= _mur_k; \ + _mur_k += _mur_align; \ + _mur_len -= _mur_align; \ + \ + switch(_mur_len) \ + { \ + case 3: hashv ^= _mur_key[2] << 16; \ + case 2: hashv ^= _mur_key[1] << 8; \ + case 1: hashv ^= _mur_key[0]; \ + hashv *= _mur_m; \ + } \ + } else { \ + switch(_mur_len) \ + { \ + case 3: _mur_d ^= _mur_key[2] << 16; \ + case 2: _mur_d ^= _mur_key[1] << 8; \ + case 1: _mur_d ^= _mur_key[0]; \ + case 0: hashv ^= (_mur_t >> _mur_sr) | (_mur_d << _mur_sl); \ + hashv *= _mur_m; \ + } \ + } \ + \ + hashv ^= hashv >> 13; \ + hashv *= _mur_m; \ + hashv ^= hashv >> 15; \ + } else { \ + for (;_mur_len >= 4; _mur_len-=4) { \ + unsigned _mur_k = *(unsigned*)_mur_key; \ + _mur_k *= _mur_m; \ + _mur_k ^= _mur_k >> _mur_r; \ + _mur_k *= _mur_m; \ + hashv *= _mur_m; \ + hashv ^= _mur_k; \ + _mur_key += 4; \ + } \ + switch(_mur_len) \ + { \ + case 3: hashv ^= _mur_key[2] << 16; \ + case 2: hashv ^= _mur_key[1] << 8; \ + case 1: hashv ^= _mur_key[0]; \ + hashv *= _mur_m; \ + } \ + \ + hashv ^= hashv >> 13; \ + hashv *= _mur_m; \ + hashv ^= hashv >> 15; \ + } \ + bkt = hashv & (num_bkts-1); \ +} while(0) +#endif /* HASH_USING_NO_STRICT_ALIASING */ + +/* key comparison function; return 0 if keys equal */ +#define HASH_KEYCMP(a,b,len) memcmp(a,b,len) + +/* iterate over items in a known bucket to find desired item */ +#define HASH_FIND_IN_BKT(tbl,hh,head,keyptr,keylen_in,out) \ +do { \ + if (head.hh_head) DECLTYPE_ASSIGN(out,ELMT_FROM_HH(tbl,head.hh_head)); \ + else out=NULL; \ + while (out) { \ + if (out->hh.keylen == keylen_in) { \ + if ((HASH_KEYCMP(out->hh.key,keyptr,keylen_in)) == 0) break; \ + } \ + if (out->hh.hh_next) DECLTYPE_ASSIGN(out,ELMT_FROM_HH(tbl,out->hh.hh_next)); \ + else out = NULL; \ + } \ +} while(0) + +/* add an item to a bucket */ +#define HASH_ADD_TO_BKT(head,addhh) \ +do { \ + head.count++; \ + (addhh)->hh_next = head.hh_head; \ + (addhh)->hh_prev = NULL; \ + if (head.hh_head) { (head).hh_head->hh_prev = (addhh); } \ + (head).hh_head=addhh; \ + if (head.count >= ((head.expand_mult+1) * HASH_BKT_CAPACITY_THRESH) \ + && (addhh)->tbl->noexpand != 1) { \ + HASH_EXPAND_BUCKETS((addhh)->tbl); \ + } \ +} while(0) + +/* remove an item from a given bucket */ +#define HASH_DEL_IN_BKT(hh,head,hh_del) \ + (head).count--; \ + if ((head).hh_head == hh_del) { \ + (head).hh_head = hh_del->hh_next; \ + } \ + if (hh_del->hh_prev) { \ + hh_del->hh_prev->hh_next = hh_del->hh_next; \ + } \ + if (hh_del->hh_next) { \ + hh_del->hh_next->hh_prev = hh_del->hh_prev; \ + } + +/* Bucket expansion has the effect of doubling the number of buckets + * and redistributing the items into the new buckets. Ideally the + * items will distribute more or less evenly into the new buckets + * (the extent to which this is true is a measure of the quality of + * the hash function as it applies to the key domain). + * + * With the items distributed into more buckets, the chain length + * (item count) in each bucket is reduced. Thus by expanding buckets + * the hash keeps a bound on the chain length. This bounded chain + * length is the essence of how a hash provides constant time lookup. + * + * The calculation of tbl->ideal_chain_maxlen below deserves some + * explanation. First, keep in mind that we're calculating the ideal + * maximum chain length based on the *new* (doubled) bucket count. + * In fractions this is just n/b (n=number of items,b=new num buckets). + * Since the ideal chain length is an integer, we want to calculate + * ceil(n/b). We don't depend on floating point arithmetic in this + * hash, so to calculate ceil(n/b) with integers we could write + * + * ceil(n/b) = (n/b) + ((n%b)?1:0) + * + * and in fact a previous version of this hash did just that. + * But now we have improved things a bit by recognizing that b is + * always a power of two. We keep its base 2 log handy (call it lb), + * so now we can write this with a bit shift and logical AND: + * + * ceil(n/b) = (n>>lb) + ( (n & (b-1)) ? 1:0) + * + */ +#define HASH_EXPAND_BUCKETS(tbl) \ +do { \ + unsigned _he_bkt; \ + unsigned _he_bkt_i; \ + struct UT_hash_handle *_he_thh, *_he_hh_nxt; \ + UT_hash_bucket *_he_new_buckets, *_he_newbkt; \ + _he_new_buckets = (UT_hash_bucket*)uthash_malloc( \ + 2 * tbl->num_buckets * sizeof(struct UT_hash_bucket)); \ + if (!_he_new_buckets) { uthash_fatal( "out of memory"); } \ + memset(_he_new_buckets, 0, \ + 2 * tbl->num_buckets * sizeof(struct UT_hash_bucket)); \ + tbl->ideal_chain_maxlen = \ + (tbl->num_items >> (tbl->log2_num_buckets+1)) + \ + ((tbl->num_items & ((tbl->num_buckets*2)-1)) ? 1 : 0); \ + tbl->nonideal_items = 0; \ + for(_he_bkt_i = 0; _he_bkt_i < tbl->num_buckets; _he_bkt_i++) \ + { \ + _he_thh = tbl->buckets[ _he_bkt_i ].hh_head; \ + while (_he_thh) { \ + _he_hh_nxt = _he_thh->hh_next; \ + HASH_TO_BKT( _he_thh->hashv, tbl->num_buckets*2, _he_bkt); \ + _he_newbkt = &(_he_new_buckets[ _he_bkt ]); \ + if (++(_he_newbkt->count) > tbl->ideal_chain_maxlen) { \ + tbl->nonideal_items++; \ + _he_newbkt->expand_mult = _he_newbkt->count / \ + tbl->ideal_chain_maxlen; \ + } \ + _he_thh->hh_prev = NULL; \ + _he_thh->hh_next = _he_newbkt->hh_head; \ + if (_he_newbkt->hh_head) _he_newbkt->hh_head->hh_prev = \ + _he_thh; \ + _he_newbkt->hh_head = _he_thh; \ + _he_thh = _he_hh_nxt; \ + } \ + } \ + tbl->num_buckets *= 2; \ + tbl->log2_num_buckets++; \ + uthash_free( tbl->buckets ); \ + tbl->buckets = _he_new_buckets; \ + tbl->ineff_expands = (tbl->nonideal_items > (tbl->num_items >> 1)) ? \ + (tbl->ineff_expands+1) : 0; \ + if (tbl->ineff_expands > 1) { \ + tbl->noexpand=1; \ + uthash_noexpand_fyi(tbl); \ + } \ + uthash_expand_fyi(tbl); \ +} while(0) + + +/* This is an adaptation of Simon Tatham's O(n log(n)) mergesort */ +/* Note that HASH_SORT assumes the hash handle name to be hh. + * HASH_SRT was added to allow the hash handle name to be passed in. */ +#define HASH_SORT(head,cmpfcn) HASH_SRT(hh,head,cmpfcn) +#define HASH_SRT(hh,head,cmpfcn) \ +do { \ + unsigned _hs_i; \ + unsigned _hs_looping,_hs_nmerges,_hs_insize,_hs_psize,_hs_qsize; \ + struct UT_hash_handle *_hs_p, *_hs_q, *_hs_e, *_hs_list, *_hs_tail; \ + if (head) { \ + _hs_insize = 1; \ + _hs_looping = 1; \ + _hs_list = &((head)->hh); \ + while (_hs_looping) { \ + _hs_p = _hs_list; \ + _hs_list = NULL; \ + _hs_tail = NULL; \ + _hs_nmerges = 0; \ + while (_hs_p) { \ + _hs_nmerges++; \ + _hs_q = _hs_p; \ + _hs_psize = 0; \ + for ( _hs_i = 0; _hs_i < _hs_insize; _hs_i++ ) { \ + _hs_psize++; \ + _hs_q = (UT_hash_handle*)((_hs_q->next) ? \ + ((void*)((char*)(_hs_q->next) + \ + (head)->hh.tbl->hho)) : NULL); \ + if (! (_hs_q) ) break; \ + } \ + _hs_qsize = _hs_insize; \ + while ((_hs_psize > 0) || ((_hs_qsize > 0) && _hs_q )) { \ + if (_hs_psize == 0) { \ + _hs_e = _hs_q; \ + _hs_q = (UT_hash_handle*)((_hs_q->next) ? \ + ((void*)((char*)(_hs_q->next) + \ + (head)->hh.tbl->hho)) : NULL); \ + _hs_qsize--; \ + } else if ( (_hs_qsize == 0) || !(_hs_q) ) { \ + _hs_e = _hs_p; \ + _hs_p = (UT_hash_handle*)((_hs_p->next) ? \ + ((void*)((char*)(_hs_p->next) + \ + (head)->hh.tbl->hho)) : NULL); \ + _hs_psize--; \ + } else if (( \ + cmpfcn(DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl,_hs_p)), \ + DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl,_hs_q))) \ + ) <= 0) { \ + _hs_e = _hs_p; \ + _hs_p = (UT_hash_handle*)((_hs_p->next) ? \ + ((void*)((char*)(_hs_p->next) + \ + (head)->hh.tbl->hho)) : NULL); \ + _hs_psize--; \ + } else { \ + _hs_e = _hs_q; \ + _hs_q = (UT_hash_handle*)((_hs_q->next) ? \ + ((void*)((char*)(_hs_q->next) + \ + (head)->hh.tbl->hho)) : NULL); \ + _hs_qsize--; \ + } \ + if ( _hs_tail ) { \ + _hs_tail->next = ((_hs_e) ? \ + ELMT_FROM_HH((head)->hh.tbl,_hs_e) : NULL); \ + } else { \ + _hs_list = _hs_e; \ + } \ + _hs_e->prev = ((_hs_tail) ? \ + ELMT_FROM_HH((head)->hh.tbl,_hs_tail) : NULL); \ + _hs_tail = _hs_e; \ + } \ + _hs_p = _hs_q; \ + } \ + _hs_tail->next = NULL; \ + if ( _hs_nmerges <= 1 ) { \ + _hs_looping=0; \ + (head)->hh.tbl->tail = _hs_tail; \ + DECLTYPE_ASSIGN(head,ELMT_FROM_HH((head)->hh.tbl, _hs_list)); \ + } \ + _hs_insize *= 2; \ + } \ + HASH_FSCK(hh,head); \ + } \ +} while (0) + +/* This function selects items from one hash into another hash. + * The end result is that the selected items have dual presence + * in both hashes. There is no copy of the items made; rather + * they are added into the new hash through a secondary hash + * hash handle that must be present in the structure. */ +#define HASH_SELECT(hh_dst, dst, hh_src, src, cond) \ +do { \ + unsigned _src_bkt, _dst_bkt; \ + void *_last_elt=NULL, *_elt; \ + UT_hash_handle *_src_hh, *_dst_hh, *_last_elt_hh=NULL; \ + ptrdiff_t _dst_hho = ((char*)(&(dst)->hh_dst) - (char*)(dst)); \ + if (src) { \ + for(_src_bkt=0; _src_bkt < (src)->hh_src.tbl->num_buckets; _src_bkt++) { \ + for(_src_hh = (src)->hh_src.tbl->buckets[_src_bkt].hh_head; \ + _src_hh; \ + _src_hh = _src_hh->hh_next) { \ + _elt = ELMT_FROM_HH((src)->hh_src.tbl, _src_hh); \ + if (cond(_elt)) { \ + _dst_hh = (UT_hash_handle*)(((char*)_elt) + _dst_hho); \ + _dst_hh->key = _src_hh->key; \ + _dst_hh->keylen = _src_hh->keylen; \ + _dst_hh->hashv = _src_hh->hashv; \ + _dst_hh->prev = _last_elt; \ + _dst_hh->next = NULL; \ + if (_last_elt_hh) { _last_elt_hh->next = _elt; } \ + if (!dst) { \ + DECLTYPE_ASSIGN(dst,_elt); \ + HASH_MAKE_TABLE(hh_dst,dst); \ + } else { \ + _dst_hh->tbl = (dst)->hh_dst.tbl; \ + } \ + HASH_TO_BKT(_dst_hh->hashv, _dst_hh->tbl->num_buckets, _dst_bkt); \ + HASH_ADD_TO_BKT(_dst_hh->tbl->buckets[_dst_bkt],_dst_hh); \ + (dst)->hh_dst.tbl->num_items++; \ + _last_elt = _elt; \ + _last_elt_hh = _dst_hh; \ + } \ + } \ + } \ + } \ + HASH_FSCK(hh_dst,dst); \ +} while (0) + +#define HASH_CLEAR(hh,head) \ +do { \ + if (head) { \ + uthash_free((head)->hh.tbl->buckets ); \ + uthash_free((head)->hh.tbl); \ + (head)=NULL; \ + } \ +} while(0) + +/* obtain a count of items in the hash */ +#define HASH_COUNT(head) HASH_CNT(hh,head) +#define HASH_CNT(hh,head) (head?(head->hh.tbl->num_items):0) + +typedef struct UT_hash_bucket { + struct UT_hash_handle *hh_head; + unsigned count; + + /* expand_mult is normally set to 0. In this situation, the max chain length + * threshold is enforced at its default value, HASH_BKT_CAPACITY_THRESH. (If + * the bucket's chain exceeds this length, bucket expansion is triggered). + * However, setting expand_mult to a non-zero value delays bucket expansion + * (that would be triggered by additions to this particular bucket) + * until its chain length reaches a *multiple* of HASH_BKT_CAPACITY_THRESH. + * (The multiplier is simply expand_mult+1). The whole idea of this + * multiplier is to reduce bucket expansions, since they are expensive, in + * situations where we know that a particular bucket tends to be overused. + * It is better to let its chain length grow to a longer yet-still-bounded + * value, than to do an O(n) bucket expansion too often. + */ + unsigned expand_mult; + +} UT_hash_bucket; + +/* random signature used only to find hash tables in external analysis */ +#define HASH_SIGNATURE 0xa0111fe1 +#define HASH_BLOOM_SIGNATURE 0xb12220f2 + +typedef struct UT_hash_table { + UT_hash_bucket *buckets; + unsigned num_buckets, log2_num_buckets; + unsigned num_items; + struct UT_hash_handle *tail; /* tail hh in app order, for fast append */ + ptrdiff_t hho; /* hash handle offset (byte pos of hash handle in element */ + + /* in an ideal situation (all buckets used equally), no bucket would have + * more than ceil(#items/#buckets) items. that's the ideal chain length. */ + unsigned ideal_chain_maxlen; + + /* nonideal_items is the number of items in the hash whose chain position + * exceeds the ideal chain maxlen. these items pay the penalty for an uneven + * hash distribution; reaching them in a chain traversal takes >ideal steps */ + unsigned nonideal_items; + + /* ineffective expands occur when a bucket doubling was performed, but + * afterward, more than half the items in the hash had nonideal chain + * positions. If this happens on two consecutive expansions we inhibit any + * further expansion, as it's not helping; this happens when the hash + * function isn't a good fit for the key domain. When expansion is inhibited + * the hash will still work, albeit no longer in constant time. */ + unsigned ineff_expands, noexpand; + + uint32_t signature; /* used only to find hash tables in external analysis */ +#ifdef HASH_BLOOM + uint32_t bloom_sig; /* used only to test bloom exists in external analysis */ + uint8_t *bloom_bv; + char bloom_nbits; +#endif + +} UT_hash_table; + +typedef struct UT_hash_handle { + struct UT_hash_table *tbl; + void *prev; /* prev element in app order */ + void *next; /* next element in app order */ + struct UT_hash_handle *hh_prev; /* previous hh in bucket order */ + struct UT_hash_handle *hh_next; /* next hh in bucket order */ + void *key; /* ptr to enclosing struct's key */ + unsigned keylen; /* enclosing struct's key len */ + unsigned hashv; /* result of hash-fcn(key) */ +} UT_hash_handle; + +#endif /* UTHASH_H */ diff --git a/thirdparty/libktx/lib/vk_format.h b/thirdparty/libktx/lib/vk_format.h new file mode 100644 index 000000000000..18adf33b595f --- /dev/null +++ b/thirdparty/libktx/lib/vk_format.h @@ -0,0 +1,1388 @@ +/* +================================================================================================ + +Description : Vulkan format properties and conversion from OpenGL. +Author : J.M.P. van Waveren +Date : 07/17/2016 +Language : C99 +Format : Real tabs with the tab size equal to 4 spaces. +Copyright : Copyright (c) 2016 Oculus VR, LLC. All Rights reserved. + + +LICENSE +======= + +Copyright 2016 Oculus VR, LLC. +SPDX-License-Identifier: Apache-2.0 + + +DESCRIPTION +=========== + +This header implements several support routines to convert OpenGL formats/types +to Vulkan formats. These routines are particularly useful for loading file +formats that store OpenGL formats/types such as KTX and glTF. + +The functions in this header file convert the format, internalFormat and type +that are used as parameters to the following OpenGL functions: + +void glTexImage2D( GLenum target, GLint level, GLint internalFormat, + GLsizei width, GLsizei height, GLint border, + GLenum format, GLenum type, const GLvoid * data ); +void glTexImage3D( GLenum target, GLint level, GLint internalFormat, + GLsizei width, GLsizei height, GLsizei depth, GLint border, + GLenum format, GLenum type, const GLvoid * data ); +void glCompressedTexImage2D( GLenum target, GLint level, GLenum internalformat, + GLsizei width, GLsizei height, GLint border, + GLsizei imageSize, const GLvoid * data ); +void glCompressedTexImage3D( GLenum target, GLint level, GLenum internalformat, + GLsizei width, GLsizei height, GLsizei depth, GLint border, + GLsizei imageSize, const GLvoid * data ); +void glTexStorage2D( GLenum target, GLsizei levels, GLenum internalformat, + GLsizei width, GLsizei height ); +void glTexStorage3D( GLenum target, GLsizei levels, GLenum internalformat, + GLsizei width, GLsizei height, GLsizei depth ); +void glVertexAttribPointer( GLuint index, GLint size, GLenum type, GLboolean normalized, + GLsizei stride, const GLvoid * pointer); + + +IMPLEMENTATION +============== + +This file does not include OpenGL / OpenGL ES headers because: + + 1. Including OpenGL / OpenGL ES headers is platform dependent and + may require a separate installation of an OpenGL SDK. + 2. The OpenGL format/type constants are the same between extensions and core. + 3. The OpenGL format/type constants are the same between OpenGL and OpenGL ES. + 4. File formats like KTX and glTF may use OpenGL formats and types that + are not supported by the OpenGL implementation on the platform but are + supported by the Vulkan implementation. + + +ENTRY POINTS +============ + +static inline VkFormat vkGetFormatFromOpenGLFormat( const GLenum format, const GLenum type ); +static inline VkFormat vkGetFormatFromOpenGLType( const GLenum type, const GLuint numComponents, const GLboolean normalized ); +static inline VkFormat vkGetFormatFromOpenGLInternalFormat( const GLenum internalFormat ); +static inline void vkGetFormatSize( const VkFormat format, VkFormatSize * pFormatSize ); + +MODIFICATIONS for use in libktx +=============================== + +2019.5.30 Use common ktxFormatSize to return results. Mark Callow, Edgewise Consulting. +2019.6.12 Add mapping of PVRTC formats. " + +================================================================================================ +*/ + +#if !defined( VK_FORMAT_H ) +#define VK_FORMAT_H + +#include "gl_format.h" + +static inline VkFormat vkGetFormatFromOpenGLFormat( const GLenum format, const GLenum type ) +{ + switch ( type ) + { + // + // 8 bits per component + // + case GL_UNSIGNED_BYTE: + { + switch ( format ) + { + case GL_RED: return VK_FORMAT_R8_UNORM; + case GL_RG: return VK_FORMAT_R8G8_UNORM; + case GL_RGB: return VK_FORMAT_R8G8B8_UNORM; + case GL_BGR: return VK_FORMAT_B8G8R8_UNORM; + case GL_RGBA: return VK_FORMAT_R8G8B8A8_UNORM; + case GL_BGRA: return VK_FORMAT_B8G8R8A8_UNORM; + case GL_RED_INTEGER: return VK_FORMAT_R8_UINT; + case GL_RG_INTEGER: return VK_FORMAT_R8G8_UINT; + case GL_RGB_INTEGER: return VK_FORMAT_R8G8B8_UINT; + case GL_BGR_INTEGER: return VK_FORMAT_B8G8R8_UINT; + case GL_RGBA_INTEGER: return VK_FORMAT_R8G8B8A8_UINT; + case GL_BGRA_INTEGER: return VK_FORMAT_B8G8R8A8_UINT; + case GL_STENCIL_INDEX: return VK_FORMAT_S8_UINT; + case GL_DEPTH_COMPONENT: return VK_FORMAT_UNDEFINED; + case GL_DEPTH_STENCIL: return VK_FORMAT_UNDEFINED; + } + break; + } + case GL_BYTE: + { + switch ( format ) + { + case GL_RED: return VK_FORMAT_R8_SNORM; + case GL_RG: return VK_FORMAT_R8G8_SNORM; + case GL_RGB: return VK_FORMAT_R8G8B8_SNORM; + case GL_BGR: return VK_FORMAT_B8G8R8_SNORM; + case GL_RGBA: return VK_FORMAT_R8G8B8A8_SNORM; + case GL_BGRA: return VK_FORMAT_B8G8R8A8_SNORM; + case GL_RED_INTEGER: return VK_FORMAT_R8_SINT; + case GL_RG_INTEGER: return VK_FORMAT_R8G8_SINT; + case GL_RGB_INTEGER: return VK_FORMAT_R8G8B8_SINT; + case GL_BGR_INTEGER: return VK_FORMAT_B8G8R8_SINT; + case GL_RGBA_INTEGER: return VK_FORMAT_R8G8B8A8_SINT; + case GL_BGRA_INTEGER: return VK_FORMAT_B8G8R8A8_SINT; + case GL_STENCIL_INDEX: return VK_FORMAT_UNDEFINED; + case GL_DEPTH_COMPONENT: return VK_FORMAT_UNDEFINED; + case GL_DEPTH_STENCIL: return VK_FORMAT_UNDEFINED; + } + break; + } + + // + // 16 bits per component + // + case GL_UNSIGNED_SHORT: + { + switch ( format ) + { + case GL_RED: return VK_FORMAT_R16_UNORM; + case GL_RG: return VK_FORMAT_R16G16_UNORM; + case GL_RGB: return VK_FORMAT_R16G16B16_UNORM; + case GL_BGR: return VK_FORMAT_UNDEFINED; + case GL_RGBA: return VK_FORMAT_R16G16B16A16_UNORM; + case GL_BGRA: return VK_FORMAT_UNDEFINED; + case GL_RED_INTEGER: return VK_FORMAT_R16_UINT; + case GL_RG_INTEGER: return VK_FORMAT_R16G16_UINT; + case GL_RGB_INTEGER: return VK_FORMAT_R16G16B16_UINT; + case GL_BGR_INTEGER: return VK_FORMAT_UNDEFINED; + case GL_RGBA_INTEGER: return VK_FORMAT_R16G16B16A16_UINT; + case GL_BGRA_INTEGER: return VK_FORMAT_UNDEFINED; + case GL_STENCIL_INDEX: return VK_FORMAT_UNDEFINED; + case GL_DEPTH_COMPONENT: return VK_FORMAT_D16_UNORM; + case GL_DEPTH_STENCIL: return VK_FORMAT_D16_UNORM_S8_UINT; + } + break; + } + case GL_SHORT: + { + switch ( format ) + { + case GL_RED: return VK_FORMAT_R16_SNORM; + case GL_RG: return VK_FORMAT_R16G16_SNORM; + case GL_RGB: return VK_FORMAT_R16G16B16_SNORM; + case GL_BGR: return VK_FORMAT_UNDEFINED; + case GL_RGBA: return VK_FORMAT_R16G16B16A16_SNORM; + case GL_BGRA: return VK_FORMAT_UNDEFINED; + case GL_RED_INTEGER: return VK_FORMAT_R16_SINT; + case GL_RG_INTEGER: return VK_FORMAT_R16G16_SINT; + case GL_RGB_INTEGER: return VK_FORMAT_R16G16B16_SINT; + case GL_BGR_INTEGER: return VK_FORMAT_UNDEFINED; + case GL_RGBA_INTEGER: return VK_FORMAT_R16G16B16A16_SINT; + case GL_BGRA_INTEGER: return VK_FORMAT_UNDEFINED; + case GL_STENCIL_INDEX: return VK_FORMAT_UNDEFINED; + case GL_DEPTH_COMPONENT: return VK_FORMAT_UNDEFINED; + case GL_DEPTH_STENCIL: return VK_FORMAT_UNDEFINED; + } + break; + } + case GL_HALF_FLOAT: + case GL_HALF_FLOAT_OES: + { + switch ( format ) + { + case GL_RED: return VK_FORMAT_R16_SFLOAT; + case GL_RG: return VK_FORMAT_R16G16_SFLOAT; + case GL_RGB: return VK_FORMAT_R16G16B16_SFLOAT; + case GL_BGR: return VK_FORMAT_UNDEFINED; + case GL_RGBA: return VK_FORMAT_R16G16B16A16_SFLOAT; + case GL_BGRA: return VK_FORMAT_UNDEFINED; + case GL_RED_INTEGER: return VK_FORMAT_UNDEFINED; + case GL_RG_INTEGER: return VK_FORMAT_UNDEFINED; + case GL_RGB_INTEGER: return VK_FORMAT_UNDEFINED; + case GL_BGR_INTEGER: return VK_FORMAT_UNDEFINED; + case GL_RGBA_INTEGER: return VK_FORMAT_UNDEFINED; + case GL_BGRA_INTEGER: return VK_FORMAT_UNDEFINED; + case GL_STENCIL_INDEX: return VK_FORMAT_UNDEFINED; + case GL_DEPTH_COMPONENT: return VK_FORMAT_UNDEFINED; + case GL_DEPTH_STENCIL: return VK_FORMAT_UNDEFINED; + } + break; + } + + // + // 32 bits per component + // + case GL_UNSIGNED_INT: + { + switch ( format ) + { + case GL_RED: return VK_FORMAT_R32_UINT; + case GL_RG: return VK_FORMAT_R32G32_UINT; + case GL_RGB: return VK_FORMAT_R32G32B32_UINT; + case GL_BGR: return VK_FORMAT_UNDEFINED; + case GL_RGBA: return VK_FORMAT_R32G32B32A32_UINT; + case GL_BGRA: return VK_FORMAT_UNDEFINED; + case GL_RED_INTEGER: return VK_FORMAT_R32_UINT; + case GL_RG_INTEGER: return VK_FORMAT_R32G32_UINT; + case GL_RGB_INTEGER: return VK_FORMAT_R32G32B32_UINT; + case GL_BGR_INTEGER: return VK_FORMAT_UNDEFINED; + case GL_RGBA_INTEGER: return VK_FORMAT_R32G32B32A32_UINT; + case GL_BGRA_INTEGER: return VK_FORMAT_UNDEFINED; + case GL_STENCIL_INDEX: return VK_FORMAT_UNDEFINED; + case GL_DEPTH_COMPONENT: return VK_FORMAT_X8_D24_UNORM_PACK32; + case GL_DEPTH_STENCIL: return VK_FORMAT_D24_UNORM_S8_UINT; + } + break; + } + case GL_INT: + { + switch ( format ) + { + case GL_RED: return VK_FORMAT_R32_SINT; + case GL_RG: return VK_FORMAT_R32G32_SINT; + case GL_RGB: return VK_FORMAT_R32G32B32_SINT; + case GL_BGR: return VK_FORMAT_UNDEFINED; + case GL_RGBA: return VK_FORMAT_R32G32B32A32_SINT; + case GL_BGRA: return VK_FORMAT_UNDEFINED; + case GL_RED_INTEGER: return VK_FORMAT_R32_SINT; + case GL_RG_INTEGER: return VK_FORMAT_R32G32_SINT; + case GL_RGB_INTEGER: return VK_FORMAT_R32G32B32_SINT; + case GL_BGR_INTEGER: return VK_FORMAT_UNDEFINED; + case GL_RGBA_INTEGER: return VK_FORMAT_R32G32B32A32_SINT; + case GL_BGRA_INTEGER: return VK_FORMAT_UNDEFINED; + case GL_STENCIL_INDEX: return VK_FORMAT_UNDEFINED; + case GL_DEPTH_COMPONENT: return VK_FORMAT_UNDEFINED; + case GL_DEPTH_STENCIL: return VK_FORMAT_UNDEFINED; + } + break; + } + case GL_FLOAT: + { + switch ( format ) + { + case GL_RED: return VK_FORMAT_R32_SFLOAT; + case GL_RG: return VK_FORMAT_R32G32_SFLOAT; + case GL_RGB: return VK_FORMAT_R32G32B32_SFLOAT; + case GL_BGR: return VK_FORMAT_UNDEFINED; + case GL_RGBA: return VK_FORMAT_R32G32B32A32_SFLOAT; + case GL_BGRA: return VK_FORMAT_UNDEFINED; + case GL_RED_INTEGER: return VK_FORMAT_UNDEFINED; + case GL_RG_INTEGER: return VK_FORMAT_UNDEFINED; + case GL_RGB_INTEGER: return VK_FORMAT_UNDEFINED; + case GL_BGR_INTEGER: return VK_FORMAT_UNDEFINED; + case GL_RGBA_INTEGER: return VK_FORMAT_UNDEFINED; + case GL_BGRA_INTEGER: return VK_FORMAT_UNDEFINED; + case GL_STENCIL_INDEX: return VK_FORMAT_UNDEFINED; + case GL_DEPTH_COMPONENT: return VK_FORMAT_D32_SFLOAT; + case GL_DEPTH_STENCIL: return VK_FORMAT_D32_SFLOAT_S8_UINT; + } + break; + } + + // + // 64 bits per component + // + case GL_UNSIGNED_INT64: + { + switch ( format ) + { + case GL_RED: return VK_FORMAT_R64_UINT; + case GL_RG: return VK_FORMAT_R64G64_UINT; + case GL_RGB: return VK_FORMAT_R64G64B64_UINT; + case GL_BGR: return VK_FORMAT_UNDEFINED; + case GL_RGBA: return VK_FORMAT_R64G64B64A64_UINT; + case GL_BGRA: return VK_FORMAT_UNDEFINED; + case GL_RED_INTEGER: return VK_FORMAT_UNDEFINED; + case GL_RG_INTEGER: return VK_FORMAT_UNDEFINED; + case GL_RGB_INTEGER: return VK_FORMAT_UNDEFINED; + case GL_BGR_INTEGER: return VK_FORMAT_UNDEFINED; + case GL_RGBA_INTEGER: return VK_FORMAT_UNDEFINED; + case GL_BGRA_INTEGER: return VK_FORMAT_UNDEFINED; + case GL_STENCIL_INDEX: return VK_FORMAT_UNDEFINED; + case GL_DEPTH_COMPONENT: return VK_FORMAT_UNDEFINED; + case GL_DEPTH_STENCIL: return VK_FORMAT_UNDEFINED; + } + break; + } + case GL_INT64: + { + switch ( format ) + { + case GL_RED: return VK_FORMAT_R64_SINT; + case GL_RG: return VK_FORMAT_R64G64_SINT; + case GL_RGB: return VK_FORMAT_R64G64B64_SINT; + case GL_BGR: return VK_FORMAT_UNDEFINED; + case GL_RGBA: return VK_FORMAT_R64G64B64A64_SINT; + case GL_BGRA: return VK_FORMAT_UNDEFINED; + case GL_RED_INTEGER: return VK_FORMAT_R64_SINT; + case GL_RG_INTEGER: return VK_FORMAT_R64G64_SINT; + case GL_RGB_INTEGER: return VK_FORMAT_R64G64B64_SINT; + case GL_BGR_INTEGER: return VK_FORMAT_UNDEFINED; + case GL_RGBA_INTEGER: return VK_FORMAT_R64G64B64A64_SINT; + case GL_BGRA_INTEGER: return VK_FORMAT_UNDEFINED; + case GL_STENCIL_INDEX: return VK_FORMAT_UNDEFINED; + case GL_DEPTH_COMPONENT: return VK_FORMAT_UNDEFINED; + case GL_DEPTH_STENCIL: return VK_FORMAT_UNDEFINED; + } + break; + } + case GL_DOUBLE: + { + switch ( format ) + { + case GL_RED: return VK_FORMAT_R64_SFLOAT; + case GL_RG: return VK_FORMAT_R64G64_SFLOAT; + case GL_RGB: return VK_FORMAT_R64G64B64_SFLOAT; + case GL_BGR: return VK_FORMAT_UNDEFINED; + case GL_RGBA: return VK_FORMAT_R64G64B64A64_SFLOAT; + case GL_BGRA: return VK_FORMAT_UNDEFINED; + case GL_RED_INTEGER: return VK_FORMAT_R64_SFLOAT; + case GL_RG_INTEGER: return VK_FORMAT_R64G64_SFLOAT; + case GL_RGB_INTEGER: return VK_FORMAT_R64G64B64_SFLOAT; + case GL_BGR_INTEGER: return VK_FORMAT_UNDEFINED; + case GL_RGBA_INTEGER: return VK_FORMAT_R64G64B64A64_SFLOAT; + case GL_BGRA_INTEGER: return VK_FORMAT_UNDEFINED; + case GL_STENCIL_INDEX: return VK_FORMAT_UNDEFINED; + case GL_DEPTH_COMPONENT: return VK_FORMAT_UNDEFINED; + case GL_DEPTH_STENCIL: return VK_FORMAT_UNDEFINED; + } + break; + } + + // + // Packed + // + case GL_UNSIGNED_BYTE_3_3_2: + assert( format == GL_RGB || format == GL_RGB_INTEGER ); + return VK_FORMAT_UNDEFINED; + case GL_UNSIGNED_BYTE_2_3_3_REV: + assert( format == GL_BGR || format == GL_BGR_INTEGER ); + return VK_FORMAT_UNDEFINED; + case GL_UNSIGNED_SHORT_5_6_5: + assert( format == GL_RGB || format == GL_RGB_INTEGER ); + return VK_FORMAT_R5G6B5_UNORM_PACK16; + case GL_UNSIGNED_SHORT_5_6_5_REV: + assert( format == GL_BGR || format == GL_BGR_INTEGER ); + return VK_FORMAT_B5G6R5_UNORM_PACK16; + case GL_UNSIGNED_SHORT_4_4_4_4: + assert( format == GL_RGB || format == GL_BGRA || format == GL_RGB_INTEGER || format == GL_BGRA_INTEGER ); + return VK_FORMAT_R4G4B4A4_UNORM_PACK16; + case GL_UNSIGNED_SHORT_4_4_4_4_REV: + assert( format == GL_RGB || format == GL_BGRA || format == GL_RGB_INTEGER || format == GL_BGRA_INTEGER ); + return VK_FORMAT_B4G4R4A4_UNORM_PACK16; + case GL_UNSIGNED_SHORT_5_5_5_1: + assert( format == GL_RGB || format == GL_BGRA || format == GL_RGB_INTEGER || format == GL_BGRA_INTEGER ); + return VK_FORMAT_R5G5B5A1_UNORM_PACK16; + case GL_UNSIGNED_SHORT_1_5_5_5_REV: + assert( format == GL_RGB || format == GL_BGRA || format == GL_RGB_INTEGER || format == GL_BGRA_INTEGER ); + return VK_FORMAT_A1R5G5B5_UNORM_PACK16; + case GL_UNSIGNED_INT_8_8_8_8: + assert( format == GL_RGB || format == GL_BGRA || format == GL_RGB_INTEGER || format == GL_BGRA_INTEGER ); + return ( format == GL_RGB_INTEGER || format == GL_BGRA_INTEGER ) ? VK_FORMAT_R8G8B8A8_UINT : VK_FORMAT_R8G8B8A8_UNORM; + case GL_UNSIGNED_INT_8_8_8_8_REV: + assert( format == GL_RGB || format == GL_BGRA || format == GL_RGB_INTEGER || format == GL_BGRA_INTEGER ); + return ( format == GL_RGB_INTEGER || format == GL_BGRA_INTEGER ) ? VK_FORMAT_A8B8G8R8_UINT_PACK32 : VK_FORMAT_A8B8G8R8_UNORM_PACK32; + case GL_UNSIGNED_INT_10_10_10_2: + assert( format == GL_RGB || format == GL_BGRA || format == GL_RGB_INTEGER || format == GL_BGRA_INTEGER ); + return ( format == GL_RGB_INTEGER || format == GL_BGRA_INTEGER ) ? VK_FORMAT_A2R10G10B10_UINT_PACK32 : VK_FORMAT_A2R10G10B10_UNORM_PACK32; + case GL_UNSIGNED_INT_2_10_10_10_REV: + assert( format == GL_RGB || format == GL_BGRA || format == GL_RGB_INTEGER || format == GL_BGRA_INTEGER ); + return ( format == GL_RGB_INTEGER || format == GL_BGRA_INTEGER ) ? VK_FORMAT_A2B10G10R10_UINT_PACK32 : VK_FORMAT_A2B10G10R10_UNORM_PACK32; + case GL_UNSIGNED_INT_10F_11F_11F_REV: + assert( format == GL_RGB || format == GL_BGR ); + return VK_FORMAT_B10G11R11_UFLOAT_PACK32; + case GL_UNSIGNED_INT_5_9_9_9_REV: + assert( format == GL_RGB || format == GL_BGR ); + return VK_FORMAT_E5B9G9R9_UFLOAT_PACK32; + case GL_UNSIGNED_INT_24_8: + assert( format == GL_DEPTH_STENCIL ); + return VK_FORMAT_D24_UNORM_S8_UINT; + case GL_FLOAT_32_UNSIGNED_INT_24_8_REV: + assert( format == GL_DEPTH_STENCIL ); + return VK_FORMAT_D32_SFLOAT_S8_UINT; + } + + return VK_FORMAT_UNDEFINED; +} + +static inline VkFormat vkGetFormatFromOpenGLType( const GLenum type, const GLuint numComponents, const GLboolean normalized ) +{ + switch ( type ) + { + // + // 8 bits per component + // + case GL_UNSIGNED_BYTE: + { + switch ( numComponents ) + { + case 1: return normalized ? VK_FORMAT_R8_UNORM : VK_FORMAT_R8_UINT; + case 2: return normalized ? VK_FORMAT_R8G8_UNORM : VK_FORMAT_R8G8_UINT; + case 3: return normalized ? VK_FORMAT_R8G8B8_UNORM : VK_FORMAT_R8G8B8_UINT; + case 4: return normalized ? VK_FORMAT_R8G8B8A8_UNORM : VK_FORMAT_R8G8B8A8_UINT; + } + break; + } + case GL_BYTE: + { + switch ( numComponents ) + { + case 1: return normalized ? VK_FORMAT_R8_SNORM : VK_FORMAT_R8_SINT; + case 2: return normalized ? VK_FORMAT_R8G8_SNORM : VK_FORMAT_R8G8_SINT; + case 3: return normalized ? VK_FORMAT_R8G8B8_SNORM : VK_FORMAT_R8G8B8_SINT; + case 4: return normalized ? VK_FORMAT_R8G8B8A8_SNORM : VK_FORMAT_R8G8B8A8_SINT; + } + break; + } + + // + // 16 bits per component + // + case GL_UNSIGNED_SHORT: + { + switch ( numComponents ) + { + case 1: return normalized ? VK_FORMAT_R16_UNORM : VK_FORMAT_R16_UINT; + case 2: return normalized ? VK_FORMAT_R16G16_UNORM : VK_FORMAT_R16G16_UINT; + case 3: return normalized ? VK_FORMAT_R16G16B16_UNORM : VK_FORMAT_R16G16B16_UINT; + case 4: return normalized ? VK_FORMAT_R16G16B16A16_UNORM : VK_FORMAT_R16G16B16A16_UINT; + } + break; + } + case GL_SHORT: + { + switch ( numComponents ) + { + case 1: return normalized ? VK_FORMAT_R16_SNORM : VK_FORMAT_R16_SINT; + case 2: return normalized ? VK_FORMAT_R16G16_SNORM : VK_FORMAT_R16G16_SINT; + case 3: return normalized ? VK_FORMAT_R16G16B16_SNORM : VK_FORMAT_R16G16B16_SINT; + case 4: return normalized ? VK_FORMAT_R16G16B16A16_SNORM : VK_FORMAT_R16G16B16A16_SINT; + } + break; + } + case GL_HALF_FLOAT: + case GL_HALF_FLOAT_OES: + { + switch ( numComponents ) + { + case 1: return VK_FORMAT_R16_SFLOAT; + case 2: return VK_FORMAT_R16G16_SFLOAT; + case 3: return VK_FORMAT_R16G16B16_SFLOAT; + case 4: return VK_FORMAT_R16G16B16A16_SFLOAT; + } + break; + } + + // + // 32 bits per component + // + case GL_UNSIGNED_INT: + { + switch ( numComponents ) + { + case 1: return VK_FORMAT_R32_UINT; + case 2: return VK_FORMAT_R32G32_UINT; + case 3: return VK_FORMAT_R32G32B32_UINT; + case 4: return VK_FORMAT_R32G32B32A32_UINT; + } + break; + } + case GL_INT: + { + switch ( numComponents ) + { + case 1: return VK_FORMAT_R32_SINT; + case 2: return VK_FORMAT_R32G32_SINT; + case 3: return VK_FORMAT_R32G32B32_SINT; + case 4: return VK_FORMAT_R32G32B32A32_SINT; + } + break; + } + case GL_FLOAT: + { + switch ( numComponents ) + { + case 1: return VK_FORMAT_R32_SFLOAT; + case 2: return VK_FORMAT_R32G32_SFLOAT; + case 3: return VK_FORMAT_R32G32B32_SFLOAT; + case 4: return VK_FORMAT_R32G32B32A32_SFLOAT; + } + break; + } + + // + // 64 bits per component + // + case GL_UNSIGNED_INT64: + { + switch ( numComponents ) + { + case 1: return VK_FORMAT_R64_UINT; + case 2: return VK_FORMAT_R64G64_UINT; + case 3: return VK_FORMAT_R64G64B64_UINT; + case 4: return VK_FORMAT_R64G64B64A64_UINT; + } + break; + } + case GL_INT64: + { + switch ( numComponents ) + { + case 1: return VK_FORMAT_R64_SINT; + case 2: return VK_FORMAT_R64G64_SINT; + case 3: return VK_FORMAT_R64G64B64_SINT; + case 4: return VK_FORMAT_R64G64B64A64_SINT; + } + break; + } + case GL_DOUBLE: + { + switch ( numComponents ) + { + case 1: return VK_FORMAT_R64_SFLOAT; + case 2: return VK_FORMAT_R64G64_SFLOAT; + case 3: return VK_FORMAT_R64G64B64_SFLOAT; + case 4: return VK_FORMAT_R64G64B64A64_SFLOAT; + } + break; + } + + // + // Packed + // + case GL_UNSIGNED_BYTE_3_3_2: return VK_FORMAT_UNDEFINED; + case GL_UNSIGNED_BYTE_2_3_3_REV: return VK_FORMAT_UNDEFINED; + case GL_UNSIGNED_SHORT_5_6_5: return VK_FORMAT_R5G6B5_UNORM_PACK16; + case GL_UNSIGNED_SHORT_5_6_5_REV: return VK_FORMAT_B5G6R5_UNORM_PACK16; + case GL_UNSIGNED_SHORT_4_4_4_4: return VK_FORMAT_R4G4B4A4_UNORM_PACK16; + case GL_UNSIGNED_SHORT_4_4_4_4_REV: return VK_FORMAT_B4G4R4A4_UNORM_PACK16; + case GL_UNSIGNED_SHORT_5_5_5_1: return VK_FORMAT_R5G5B5A1_UNORM_PACK16; + case GL_UNSIGNED_SHORT_1_5_5_5_REV: return VK_FORMAT_A1R5G5B5_UNORM_PACK16; + case GL_UNSIGNED_INT_8_8_8_8: return normalized ? VK_FORMAT_R8G8B8A8_UNORM : VK_FORMAT_R8G8B8A8_UINT; + case GL_UNSIGNED_INT_8_8_8_8_REV: return normalized ? VK_FORMAT_A8B8G8R8_UNORM_PACK32 : VK_FORMAT_A8B8G8R8_UINT_PACK32; + case GL_UNSIGNED_INT_10_10_10_2: return normalized ? VK_FORMAT_A2R10G10B10_UNORM_PACK32 : VK_FORMAT_A2R10G10B10_UINT_PACK32; + case GL_UNSIGNED_INT_2_10_10_10_REV: return normalized ? VK_FORMAT_A2B10G10R10_UNORM_PACK32 : VK_FORMAT_A2B10G10R10_UINT_PACK32; + case GL_UNSIGNED_INT_10F_11F_11F_REV: return VK_FORMAT_B10G11R11_UFLOAT_PACK32; + case GL_UNSIGNED_INT_5_9_9_9_REV: return VK_FORMAT_E5B9G9R9_UFLOAT_PACK32; + case GL_UNSIGNED_INT_24_8: return VK_FORMAT_D24_UNORM_S8_UINT; + case GL_FLOAT_32_UNSIGNED_INT_24_8_REV: return VK_FORMAT_D32_SFLOAT_S8_UINT; + } + + return VK_FORMAT_UNDEFINED; +} + +static inline VkFormat vkGetFormatFromOpenGLInternalFormat( const GLenum internalFormat ) +{ + switch ( internalFormat ) + { + // + // 8 bits per component + // + case GL_R8: return VK_FORMAT_R8_UNORM; // 1-component, 8-bit unsigned normalized + case GL_RG8: return VK_FORMAT_R8G8_UNORM; // 2-component, 8-bit unsigned normalized + case GL_RGB8: return VK_FORMAT_R8G8B8_UNORM; // 3-component, 8-bit unsigned normalized + case GL_RGBA8: return VK_FORMAT_R8G8B8A8_UNORM; // 4-component, 8-bit unsigned normalized + + case GL_R8_SNORM: return VK_FORMAT_R8_SNORM; // 1-component, 8-bit signed normalized + case GL_RG8_SNORM: return VK_FORMAT_R8G8_SNORM; // 2-component, 8-bit signed normalized + case GL_RGB8_SNORM: return VK_FORMAT_R8G8B8_SNORM; // 3-component, 8-bit signed normalized + case GL_RGBA8_SNORM: return VK_FORMAT_R8G8B8A8_SNORM; // 4-component, 8-bit signed normalized + + case GL_R8UI: return VK_FORMAT_R8_UINT; // 1-component, 8-bit unsigned integer + case GL_RG8UI: return VK_FORMAT_R8G8_UINT; // 2-component, 8-bit unsigned integer + case GL_RGB8UI: return VK_FORMAT_R8G8B8_UINT; // 3-component, 8-bit unsigned integer + case GL_RGBA8UI: return VK_FORMAT_R8G8B8A8_UINT; // 4-component, 8-bit unsigned integer + + case GL_R8I: return VK_FORMAT_R8_SINT; // 1-component, 8-bit signed integer + case GL_RG8I: return VK_FORMAT_R8G8_SINT; // 2-component, 8-bit signed integer + case GL_RGB8I: return VK_FORMAT_R8G8B8_SINT; // 3-component, 8-bit signed integer + case GL_RGBA8I: return VK_FORMAT_R8G8B8A8_SINT; // 4-component, 8-bit signed integer + + case GL_SR8: return VK_FORMAT_R8_SRGB; // 1-component, 8-bit sRGB + case GL_SRG8: return VK_FORMAT_R8G8_SRGB; // 2-component, 8-bit sRGB + case GL_SRGB8: return VK_FORMAT_R8G8B8_SRGB; // 3-component, 8-bit sRGB + case GL_SRGB8_ALPHA8: return VK_FORMAT_R8G8B8A8_SRGB; // 4-component, 8-bit sRGB + + // + // 16 bits per component + // + case GL_R16: return VK_FORMAT_R16_UNORM; // 1-component, 16-bit unsigned normalized + case GL_RG16: return VK_FORMAT_R16G16_UNORM; // 2-component, 16-bit unsigned normalized + case GL_RGB16: return VK_FORMAT_R16G16B16_UNORM; // 3-component, 16-bit unsigned normalized + case GL_RGBA16: return VK_FORMAT_R16G16B16A16_UNORM; // 4-component, 16-bit unsigned normalized + + case GL_R16_SNORM: return VK_FORMAT_R16_SNORM; // 1-component, 16-bit signed normalized + case GL_RG16_SNORM: return VK_FORMAT_R16G16_SNORM; // 2-component, 16-bit signed normalized + case GL_RGB16_SNORM: return VK_FORMAT_R16G16B16_SNORM; // 3-component, 16-bit signed normalized + case GL_RGBA16_SNORM: return VK_FORMAT_R16G16B16A16_SNORM; // 4-component, 16-bit signed normalized + + case GL_R16UI: return VK_FORMAT_R16_UINT; // 1-component, 16-bit unsigned integer + case GL_RG16UI: return VK_FORMAT_R16G16_UINT; // 2-component, 16-bit unsigned integer + case GL_RGB16UI: return VK_FORMAT_R16G16B16_UINT; // 3-component, 16-bit unsigned integer + case GL_RGBA16UI: return VK_FORMAT_R16G16B16A16_UINT; // 4-component, 16-bit unsigned integer + + case GL_R16I: return VK_FORMAT_R16_SINT; // 1-component, 16-bit signed integer + case GL_RG16I: return VK_FORMAT_R16G16_SINT; // 2-component, 16-bit signed integer + case GL_RGB16I: return VK_FORMAT_R16G16B16_SINT; // 3-component, 16-bit signed integer + case GL_RGBA16I: return VK_FORMAT_R16G16B16A16_SINT; // 4-component, 16-bit signed integer + + case GL_R16F: return VK_FORMAT_R16_SFLOAT; // 1-component, 16-bit floating-point + case GL_RG16F: return VK_FORMAT_R16G16_SFLOAT; // 2-component, 16-bit floating-point + case GL_RGB16F: return VK_FORMAT_R16G16B16_SFLOAT; // 3-component, 16-bit floating-point + case GL_RGBA16F: return VK_FORMAT_R16G16B16A16_SFLOAT; // 4-component, 16-bit floating-point + + // + // 32 bits per component + // + case GL_R32UI: return VK_FORMAT_R32_UINT; // 1-component, 32-bit unsigned integer + case GL_RG32UI: return VK_FORMAT_R32G32_UINT; // 2-component, 32-bit unsigned integer + case GL_RGB32UI: return VK_FORMAT_R32G32B32_UINT; // 3-component, 32-bit unsigned integer + case GL_RGBA32UI: return VK_FORMAT_R32G32B32A32_UINT; // 4-component, 32-bit unsigned integer + + case GL_R32I: return VK_FORMAT_R32_SINT; // 1-component, 32-bit signed integer + case GL_RG32I: return VK_FORMAT_R32G32_SINT; // 2-component, 32-bit signed integer + case GL_RGB32I: return VK_FORMAT_R32G32B32_SINT; // 3-component, 32-bit signed integer + case GL_RGBA32I: return VK_FORMAT_R32G32B32A32_SINT; // 4-component, 32-bit signed integer + + case GL_R32F: return VK_FORMAT_R32_SFLOAT; // 1-component, 32-bit floating-point + case GL_RG32F: return VK_FORMAT_R32G32_SFLOAT; // 2-component, 32-bit floating-point + case GL_RGB32F: return VK_FORMAT_R32G32B32_SFLOAT; // 3-component, 32-bit floating-point + case GL_RGBA32F: return VK_FORMAT_R32G32B32A32_SFLOAT; // 4-component, 32-bit floating-point + + // + // Packed + // + case GL_R3_G3_B2: return VK_FORMAT_UNDEFINED; // 3-component 3:3:2, unsigned normalized + case GL_RGB4: return VK_FORMAT_UNDEFINED; // 3-component 4:4:4, unsigned normalized + case GL_RGB5: return VK_FORMAT_R5G5B5A1_UNORM_PACK16; // 3-component 5:5:5, unsigned normalized + case GL_RGB565: return VK_FORMAT_R5G6B5_UNORM_PACK16; // 3-component 5:6:5, unsigned normalized + case GL_RGB10: return VK_FORMAT_A2R10G10B10_UNORM_PACK32; // 3-component 10:10:10, unsigned normalized + case GL_RGB12: return VK_FORMAT_UNDEFINED; // 3-component 12:12:12, unsigned normalized + case GL_RGBA2: return VK_FORMAT_UNDEFINED; // 4-component 2:2:2:2, unsigned normalized + case GL_RGBA4: return VK_FORMAT_R4G4B4A4_UNORM_PACK16; // 4-component 4:4:4:4, unsigned normalized + case GL_RGBA12: return VK_FORMAT_UNDEFINED; // 4-component 12:12:12:12, unsigned normalized + case GL_RGB5_A1: return VK_FORMAT_A1R5G5B5_UNORM_PACK16; // 4-component 5:5:5:1, unsigned normalized + case GL_RGB10_A2: return VK_FORMAT_A2R10G10B10_UNORM_PACK32; // 4-component 10:10:10:2, unsigned normalized + case GL_RGB10_A2UI: return VK_FORMAT_A2R10G10B10_UINT_PACK32; // 4-component 10:10:10:2, unsigned integer + case GL_R11F_G11F_B10F: return VK_FORMAT_B10G11R11_UFLOAT_PACK32; // 3-component 11:11:10, floating-point + case GL_RGB9_E5: return VK_FORMAT_E5B9G9R9_UFLOAT_PACK32; // 3-component/exp 9:9:9/5, floating-point + + // + // S3TC/DXT/BC + // + + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: return VK_FORMAT_BC1_RGB_UNORM_BLOCK; // line through 3D space, 4x4 blocks, unsigned normalized + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: return VK_FORMAT_BC1_RGBA_UNORM_BLOCK; // line through 3D space plus 1-bit alpha, 4x4 blocks, unsigned normalized + case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: return VK_FORMAT_BC2_UNORM_BLOCK; // line through 3D space plus line through 1D space, 4x4 blocks, unsigned normalized + case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: return VK_FORMAT_BC3_UNORM_BLOCK; // line through 3D space plus 4-bit alpha, 4x4 blocks, unsigned normalized + + case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT: return VK_FORMAT_BC1_RGB_SRGB_BLOCK; // line through 3D space, 4x4 blocks, sRGB + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT: return VK_FORMAT_BC1_RGBA_SRGB_BLOCK; // line through 3D space plus 1-bit alpha, 4x4 blocks, sRGB + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT: return VK_FORMAT_BC2_SRGB_BLOCK; // line through 3D space plus line through 1D space, 4x4 blocks, sRGB + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: return VK_FORMAT_BC3_SRGB_BLOCK; // line through 3D space plus 4-bit alpha, 4x4 blocks, sRGB + + case GL_COMPRESSED_LUMINANCE_LATC1_EXT: return VK_FORMAT_BC4_UNORM_BLOCK; // line through 1D space, 4x4 blocks, unsigned normalized + case GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT: return VK_FORMAT_BC5_UNORM_BLOCK; // two lines through 1D space, 4x4 blocks, unsigned normalized + case GL_COMPRESSED_SIGNED_LUMINANCE_LATC1_EXT: return VK_FORMAT_BC4_SNORM_BLOCK; // line through 1D space, 4x4 blocks, signed normalized + case GL_COMPRESSED_SIGNED_LUMINANCE_ALPHA_LATC2_EXT: return VK_FORMAT_BC5_SNORM_BLOCK; // two lines through 1D space, 4x4 blocks, signed normalized + + case GL_COMPRESSED_RED_RGTC1: return VK_FORMAT_BC4_UNORM_BLOCK; // line through 1D space, 4x4 blocks, unsigned normalized + case GL_COMPRESSED_RG_RGTC2: return VK_FORMAT_BC5_UNORM_BLOCK; // two lines through 1D space, 4x4 blocks, unsigned normalized + case GL_COMPRESSED_SIGNED_RED_RGTC1: return VK_FORMAT_BC4_SNORM_BLOCK; // line through 1D space, 4x4 blocks, signed normalized + case GL_COMPRESSED_SIGNED_RG_RGTC2: return VK_FORMAT_BC5_SNORM_BLOCK; // two lines through 1D space, 4x4 blocks, signed normalized + + case GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT: return VK_FORMAT_BC6H_UFLOAT_BLOCK; // 3-component, 4x4 blocks, unsigned floating-point + case GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT: return VK_FORMAT_BC6H_SFLOAT_BLOCK; // 3-component, 4x4 blocks, signed floating-point + case GL_COMPRESSED_RGBA_BPTC_UNORM: return VK_FORMAT_BC7_UNORM_BLOCK; // 4-component, 4x4 blocks, unsigned normalized + case GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM: return VK_FORMAT_BC7_SRGB_BLOCK; // 4-component, 4x4 blocks, sRGB + + // + // ETC + // + case GL_ETC1_RGB8_OES: return VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK; // 3-component ETC1, 4x4 blocks, unsigned normalized + + case GL_COMPRESSED_RGB8_ETC2: return VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK; // 3-component ETC2, 4x4 blocks, unsigned normalized + case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2: return VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK; // 4-component ETC2 with 1-bit alpha, 4x4 blocks, unsigned normalized + case GL_COMPRESSED_RGBA8_ETC2_EAC: return VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK; // 4-component ETC2, 4x4 blocks, unsigned normalized + + case GL_COMPRESSED_SRGB8_ETC2: return VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK; // 3-component ETC2, 4x4 blocks, sRGB + case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2: return VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK; // 4-component ETC2 with 1-bit alpha, 4x4 blocks, sRGB + case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC: return VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK; // 4-component ETC2, 4x4 blocks, sRGB + + case GL_COMPRESSED_R11_EAC: return VK_FORMAT_EAC_R11_UNORM_BLOCK; // 1-component ETC, 4x4 blocks, unsigned normalized + case GL_COMPRESSED_RG11_EAC: return VK_FORMAT_EAC_R11G11_UNORM_BLOCK; // 2-component ETC, 4x4 blocks, unsigned normalized + case GL_COMPRESSED_SIGNED_R11_EAC: return VK_FORMAT_EAC_R11_SNORM_BLOCK; // 1-component ETC, 4x4 blocks, signed normalized + case GL_COMPRESSED_SIGNED_RG11_EAC: return VK_FORMAT_EAC_R11G11_SNORM_BLOCK; // 2-component ETC, 4x4 blocks, signed normalized + + // + // PVRTC + // + case GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG: return VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG; // 3-component PVRTC, 16x8 blocks, unsigned normalized + case GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG: return VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG; // 3-component PVRTC, 8x8 blocks, unsigned normalized + case GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG: return VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG; // 4-component PVRTC, 16x8 blocks, unsigned normalized + case GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG: return VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG; // 4-component PVRTC, 8x8 blocks, unsigned normalized + case GL_COMPRESSED_RGBA_PVRTC_2BPPV2_IMG: return VK_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG; // 4-component PVRTC, 8x4 blocks, unsigned normalized + case GL_COMPRESSED_RGBA_PVRTC_4BPPV2_IMG: return VK_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG; // 4-component PVRTC, 4x4 blocks, unsigned normalized + + case GL_COMPRESSED_SRGB_PVRTC_2BPPV1_EXT: return VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG; // 3-component PVRTC, 16x8 blocks, sRGB + case GL_COMPRESSED_SRGB_PVRTC_4BPPV1_EXT: return VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG; // 3-component PVRTC, 8x8 blocks, sRGB + case GL_COMPRESSED_SRGB_ALPHA_PVRTC_2BPPV1_EXT: return VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG; // 4-component PVRTC, 16x8 blocks, sRGB + case GL_COMPRESSED_SRGB_ALPHA_PVRTC_4BPPV1_EXT: return VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG; // 4-component PVRTC, 8x8 blocks, sRGB + case GL_COMPRESSED_SRGB_ALPHA_PVRTC_2BPPV2_IMG: return VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG; // 4-component PVRTC, 8x4 blocks, sRGB + case GL_COMPRESSED_SRGB_ALPHA_PVRTC_4BPPV2_IMG: return VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG; // 4-component PVRTC, 4x4 blocks, sRGB + + // + // ASTC + // + case GL_COMPRESSED_RGBA_ASTC_4x4_KHR: return VK_FORMAT_ASTC_4x4_UNORM_BLOCK; // 4-component ASTC, 4x4 blocks, unsigned normalized + case GL_COMPRESSED_RGBA_ASTC_5x4_KHR: return VK_FORMAT_ASTC_5x4_UNORM_BLOCK; // 4-component ASTC, 5x4 blocks, unsigned normalized + case GL_COMPRESSED_RGBA_ASTC_5x5_KHR: return VK_FORMAT_ASTC_5x5_UNORM_BLOCK; // 4-component ASTC, 5x5 blocks, unsigned normalized + case GL_COMPRESSED_RGBA_ASTC_6x5_KHR: return VK_FORMAT_ASTC_6x5_UNORM_BLOCK; // 4-component ASTC, 6x5 blocks, unsigned normalized + case GL_COMPRESSED_RGBA_ASTC_6x6_KHR: return VK_FORMAT_ASTC_6x6_UNORM_BLOCK; // 4-component ASTC, 6x6 blocks, unsigned normalized + case GL_COMPRESSED_RGBA_ASTC_8x5_KHR: return VK_FORMAT_ASTC_8x5_UNORM_BLOCK; // 4-component ASTC, 8x5 blocks, unsigned normalized + case GL_COMPRESSED_RGBA_ASTC_8x6_KHR: return VK_FORMAT_ASTC_8x6_UNORM_BLOCK; // 4-component ASTC, 8x6 blocks, unsigned normalized + case GL_COMPRESSED_RGBA_ASTC_8x8_KHR: return VK_FORMAT_ASTC_8x8_UNORM_BLOCK; // 4-component ASTC, 8x8 blocks, unsigned normalized + case GL_COMPRESSED_RGBA_ASTC_10x5_KHR: return VK_FORMAT_ASTC_10x5_UNORM_BLOCK; // 4-component ASTC, 10x5 blocks, unsigned normalized + case GL_COMPRESSED_RGBA_ASTC_10x6_KHR: return VK_FORMAT_ASTC_10x6_UNORM_BLOCK; // 4-component ASTC, 10x6 blocks, unsigned normalized + case GL_COMPRESSED_RGBA_ASTC_10x8_KHR: return VK_FORMAT_ASTC_10x8_UNORM_BLOCK; // 4-component ASTC, 10x8 blocks, unsigned normalized + case GL_COMPRESSED_RGBA_ASTC_10x10_KHR: return VK_FORMAT_ASTC_10x10_UNORM_BLOCK; // 4-component ASTC, 10x10 blocks, unsigned normalized + case GL_COMPRESSED_RGBA_ASTC_12x10_KHR: return VK_FORMAT_ASTC_12x10_UNORM_BLOCK; // 4-component ASTC, 12x10 blocks, unsigned normalized + case GL_COMPRESSED_RGBA_ASTC_12x12_KHR: return VK_FORMAT_ASTC_12x12_UNORM_BLOCK; // 4-component ASTC, 12x12 blocks, unsigned normalized + + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR: return VK_FORMAT_ASTC_4x4_SRGB_BLOCK; // 4-component ASTC, 4x4 blocks, sRGB + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR: return VK_FORMAT_ASTC_5x4_SRGB_BLOCK; // 4-component ASTC, 5x4 blocks, sRGB + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR: return VK_FORMAT_ASTC_5x5_SRGB_BLOCK; // 4-component ASTC, 5x5 blocks, sRGB + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR: return VK_FORMAT_ASTC_6x5_SRGB_BLOCK; // 4-component ASTC, 6x5 blocks, sRGB + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR: return VK_FORMAT_ASTC_6x6_SRGB_BLOCK; // 4-component ASTC, 6x6 blocks, sRGB + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR: return VK_FORMAT_ASTC_8x5_SRGB_BLOCK; // 4-component ASTC, 8x5 blocks, sRGB + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR: return VK_FORMAT_ASTC_8x6_SRGB_BLOCK; // 4-component ASTC, 8x6 blocks, sRGB + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR: return VK_FORMAT_ASTC_8x8_SRGB_BLOCK; // 4-component ASTC, 8x8 blocks, sRGB + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR: return VK_FORMAT_ASTC_10x5_SRGB_BLOCK; // 4-component ASTC, 10x5 blocks, sRGB + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR: return VK_FORMAT_ASTC_10x6_SRGB_BLOCK; // 4-component ASTC, 10x6 blocks, sRGB + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR: return VK_FORMAT_ASTC_10x8_SRGB_BLOCK; // 4-component ASTC, 10x8 blocks, sRGB + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR: return VK_FORMAT_ASTC_10x10_SRGB_BLOCK; // 4-component ASTC, 10x10 blocks, sRGB + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR: return VK_FORMAT_ASTC_12x10_SRGB_BLOCK; // 4-component ASTC, 12x10 blocks, sRGB + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR: return VK_FORMAT_ASTC_12x12_SRGB_BLOCK; // 4-component ASTC, 12x12 blocks, sRGB + + case GL_COMPRESSED_RGBA_ASTC_3x3x3_OES: return VK_FORMAT_UNDEFINED; // 4-component ASTC, 3x3x3 blocks, unsigned normalized + case GL_COMPRESSED_RGBA_ASTC_4x3x3_OES: return VK_FORMAT_UNDEFINED; // 4-component ASTC, 4x3x3 blocks, unsigned normalized + case GL_COMPRESSED_RGBA_ASTC_4x4x3_OES: return VK_FORMAT_UNDEFINED; // 4-component ASTC, 4x4x3 blocks, unsigned normalized + case GL_COMPRESSED_RGBA_ASTC_4x4x4_OES: return VK_FORMAT_UNDEFINED; // 4-component ASTC, 4x4x4 blocks, unsigned normalized + case GL_COMPRESSED_RGBA_ASTC_5x4x4_OES: return VK_FORMAT_UNDEFINED; // 4-component ASTC, 5x4x4 blocks, unsigned normalized + case GL_COMPRESSED_RGBA_ASTC_5x5x4_OES: return VK_FORMAT_UNDEFINED; // 4-component ASTC, 5x5x4 blocks, unsigned normalized + case GL_COMPRESSED_RGBA_ASTC_5x5x5_OES: return VK_FORMAT_UNDEFINED; // 4-component ASTC, 5x5x5 blocks, unsigned normalized + case GL_COMPRESSED_RGBA_ASTC_6x5x5_OES: return VK_FORMAT_UNDEFINED; // 4-component ASTC, 6x5x5 blocks, unsigned normalized + case GL_COMPRESSED_RGBA_ASTC_6x6x5_OES: return VK_FORMAT_UNDEFINED; // 4-component ASTC, 6x6x5 blocks, unsigned normalized + case GL_COMPRESSED_RGBA_ASTC_6x6x6_OES: return VK_FORMAT_UNDEFINED; // 4-component ASTC, 6x6x6 blocks, unsigned normalized + + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_3x3x3_OES: return VK_FORMAT_UNDEFINED; // 4-component ASTC, 3x3x3 blocks, sRGB + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x3x3_OES: return VK_FORMAT_UNDEFINED; // 4-component ASTC, 4x3x3 blocks, sRGB + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4x3_OES: return VK_FORMAT_UNDEFINED; // 4-component ASTC, 4x4x3 blocks, sRGB + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4x4_OES: return VK_FORMAT_UNDEFINED; // 4-component ASTC, 4x4x4 blocks, sRGB + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4x4_OES: return VK_FORMAT_UNDEFINED; // 4-component ASTC, 5x4x4 blocks, sRGB + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5x4_OES: return VK_FORMAT_UNDEFINED; // 4-component ASTC, 5x5x4 blocks, sRGB + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5x5_OES: return VK_FORMAT_UNDEFINED; // 4-component ASTC, 5x5x5 blocks, sRGB + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5x5_OES: return VK_FORMAT_UNDEFINED; // 4-component ASTC, 6x5x5 blocks, sRGB + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6x5_OES: return VK_FORMAT_UNDEFINED; // 4-component ASTC, 6x6x5 blocks, sRGB + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6x6_OES: return VK_FORMAT_UNDEFINED; // 4-component ASTC, 6x6x6 blocks, sRGB + + // + // ATC + // + case GL_ATC_RGB_AMD: return VK_FORMAT_UNDEFINED; // 3-component, 4x4 blocks, unsigned normalized + case GL_ATC_RGBA_EXPLICIT_ALPHA_AMD: return VK_FORMAT_UNDEFINED; // 4-component, 4x4 blocks, unsigned normalized + case GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD: return VK_FORMAT_UNDEFINED; // 4-component, 4x4 blocks, unsigned normalized + + // + // Palletized + // + case GL_PALETTE4_RGB8_OES: return VK_FORMAT_UNDEFINED; // 3-component 8:8:8, 4-bit palette, unsigned normalized + case GL_PALETTE4_RGBA8_OES: return VK_FORMAT_UNDEFINED; // 4-component 8:8:8:8, 4-bit palette, unsigned normalized + case GL_PALETTE4_R5_G6_B5_OES: return VK_FORMAT_UNDEFINED; // 3-component 5:6:5, 4-bit palette, unsigned normalized + case GL_PALETTE4_RGBA4_OES: return VK_FORMAT_UNDEFINED; // 4-component 4:4:4:4, 4-bit palette, unsigned normalized + case GL_PALETTE4_RGB5_A1_OES: return VK_FORMAT_UNDEFINED; // 4-component 5:5:5:1, 4-bit palette, unsigned normalized + case GL_PALETTE8_RGB8_OES: return VK_FORMAT_UNDEFINED; // 3-component 8:8:8, 8-bit palette, unsigned normalized + case GL_PALETTE8_RGBA8_OES: return VK_FORMAT_UNDEFINED; // 4-component 8:8:8:8, 8-bit palette, unsigned normalized + case GL_PALETTE8_R5_G6_B5_OES: return VK_FORMAT_UNDEFINED; // 3-component 5:6:5, 8-bit palette, unsigned normalized + case GL_PALETTE8_RGBA4_OES: return VK_FORMAT_UNDEFINED; // 4-component 4:4:4:4, 8-bit palette, unsigned normalized + case GL_PALETTE8_RGB5_A1_OES: return VK_FORMAT_UNDEFINED; // 4-component 5:5:5:1, 8-bit palette, unsigned normalized + + // + // Depth/stencil + // + case GL_DEPTH_COMPONENT16: return VK_FORMAT_D16_UNORM; + case GL_DEPTH_COMPONENT24: return VK_FORMAT_X8_D24_UNORM_PACK32; + case GL_DEPTH_COMPONENT32: return VK_FORMAT_UNDEFINED; + case GL_DEPTH_COMPONENT32F: return VK_FORMAT_D32_SFLOAT; + case GL_DEPTH_COMPONENT32F_NV: return VK_FORMAT_D32_SFLOAT; + case GL_STENCIL_INDEX1: return VK_FORMAT_UNDEFINED; + case GL_STENCIL_INDEX4: return VK_FORMAT_UNDEFINED; + case GL_STENCIL_INDEX8: return VK_FORMAT_S8_UINT; + case GL_STENCIL_INDEX16: return VK_FORMAT_UNDEFINED; + case GL_DEPTH24_STENCIL8: return VK_FORMAT_D24_UNORM_S8_UINT; + case GL_DEPTH32F_STENCIL8: return VK_FORMAT_D32_SFLOAT_S8_UINT; + case GL_DEPTH32F_STENCIL8_NV: return VK_FORMAT_D32_SFLOAT_S8_UINT; + + default: return VK_FORMAT_UNDEFINED; + } +} + +static inline void vkGetFormatSize( const VkFormat format, ktxFormatSize * pFormatSize ) +{ + pFormatSize->minBlocksX = pFormatSize->minBlocksY = 1; + switch ( format ) + { + case VK_FORMAT_R4G4_UNORM_PACK8: + pFormatSize->flags = KTX_FORMAT_SIZE_PACKED_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 1 * 8; + pFormatSize->blockWidth = 1; + pFormatSize->blockHeight = 1; + pFormatSize->blockDepth = 1; + break; + case VK_FORMAT_R4G4B4A4_UNORM_PACK16: + case VK_FORMAT_B4G4R4A4_UNORM_PACK16: + case VK_FORMAT_R5G6B5_UNORM_PACK16: + case VK_FORMAT_B5G6R5_UNORM_PACK16: + case VK_FORMAT_R5G5B5A1_UNORM_PACK16: + case VK_FORMAT_B5G5R5A1_UNORM_PACK16: + case VK_FORMAT_A1R5G5B5_UNORM_PACK16: + pFormatSize->flags = KTX_FORMAT_SIZE_PACKED_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 2 * 8; + pFormatSize->blockWidth = 1; + pFormatSize->blockHeight = 1; + pFormatSize->blockDepth = 1; + break; + case VK_FORMAT_R8_UNORM: + case VK_FORMAT_R8_SNORM: + case VK_FORMAT_R8_USCALED: + case VK_FORMAT_R8_SSCALED: + case VK_FORMAT_R8_UINT: + case VK_FORMAT_R8_SINT: + case VK_FORMAT_R8_SRGB: + pFormatSize->flags = 0; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 1 * 8; + pFormatSize->blockWidth = 1; + pFormatSize->blockHeight = 1; + pFormatSize->blockDepth = 1; + break; + case VK_FORMAT_R8G8_UNORM: + case VK_FORMAT_R8G8_SNORM: + case VK_FORMAT_R8G8_USCALED: + case VK_FORMAT_R8G8_SSCALED: + case VK_FORMAT_R8G8_UINT: + case VK_FORMAT_R8G8_SINT: + case VK_FORMAT_R8G8_SRGB: + pFormatSize->flags = 0; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 2 * 8; + pFormatSize->blockWidth = 1; + pFormatSize->blockHeight = 1; + pFormatSize->blockDepth = 1; + break; + case VK_FORMAT_R8G8B8_UNORM: + case VK_FORMAT_R8G8B8_SNORM: + case VK_FORMAT_R8G8B8_USCALED: + case VK_FORMAT_R8G8B8_SSCALED: + case VK_FORMAT_R8G8B8_UINT: + case VK_FORMAT_R8G8B8_SINT: + case VK_FORMAT_R8G8B8_SRGB: + case VK_FORMAT_B8G8R8_UNORM: + case VK_FORMAT_B8G8R8_SNORM: + case VK_FORMAT_B8G8R8_USCALED: + case VK_FORMAT_B8G8R8_SSCALED: + case VK_FORMAT_B8G8R8_UINT: + case VK_FORMAT_B8G8R8_SINT: + case VK_FORMAT_B8G8R8_SRGB: + pFormatSize->flags = 0; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 3 * 8; + pFormatSize->blockWidth = 1; + pFormatSize->blockHeight = 1; + pFormatSize->blockDepth = 1; + break; + case VK_FORMAT_R8G8B8A8_UNORM: + case VK_FORMAT_R8G8B8A8_SNORM: + case VK_FORMAT_R8G8B8A8_USCALED: + case VK_FORMAT_R8G8B8A8_SSCALED: + case VK_FORMAT_R8G8B8A8_UINT: + case VK_FORMAT_R8G8B8A8_SINT: + case VK_FORMAT_R8G8B8A8_SRGB: + case VK_FORMAT_B8G8R8A8_UNORM: + case VK_FORMAT_B8G8R8A8_SNORM: + case VK_FORMAT_B8G8R8A8_USCALED: + case VK_FORMAT_B8G8R8A8_SSCALED: + case VK_FORMAT_B8G8R8A8_UINT: + case VK_FORMAT_B8G8R8A8_SINT: + case VK_FORMAT_B8G8R8A8_SRGB: + pFormatSize->flags = 0; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 4 * 8; + pFormatSize->blockWidth = 1; + pFormatSize->blockHeight = 1; + pFormatSize->blockDepth = 1; + break; + case VK_FORMAT_A8B8G8R8_UNORM_PACK32: + case VK_FORMAT_A8B8G8R8_SNORM_PACK32: + case VK_FORMAT_A8B8G8R8_USCALED_PACK32: + case VK_FORMAT_A8B8G8R8_SSCALED_PACK32: + case VK_FORMAT_A8B8G8R8_UINT_PACK32: + case VK_FORMAT_A8B8G8R8_SINT_PACK32: + case VK_FORMAT_A8B8G8R8_SRGB_PACK32: + pFormatSize->flags = KTX_FORMAT_SIZE_PACKED_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 4 * 8; + pFormatSize->blockWidth = 1; + pFormatSize->blockHeight = 1; + pFormatSize->blockDepth = 1; + break; + case VK_FORMAT_A2R10G10B10_UNORM_PACK32: + case VK_FORMAT_A2R10G10B10_SNORM_PACK32: + case VK_FORMAT_A2R10G10B10_USCALED_PACK32: + case VK_FORMAT_A2R10G10B10_SSCALED_PACK32: + case VK_FORMAT_A2R10G10B10_UINT_PACK32: + case VK_FORMAT_A2R10G10B10_SINT_PACK32: + case VK_FORMAT_A2B10G10R10_UNORM_PACK32: + case VK_FORMAT_A2B10G10R10_SNORM_PACK32: + case VK_FORMAT_A2B10G10R10_USCALED_PACK32: + case VK_FORMAT_A2B10G10R10_SSCALED_PACK32: + case VK_FORMAT_A2B10G10R10_UINT_PACK32: + case VK_FORMAT_A2B10G10R10_SINT_PACK32: + pFormatSize->flags = KTX_FORMAT_SIZE_PACKED_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 4 * 8; + pFormatSize->blockWidth = 1; + pFormatSize->blockHeight = 1; + pFormatSize->blockDepth = 1; + break; + case VK_FORMAT_R16_UNORM: + case VK_FORMAT_R16_SNORM: + case VK_FORMAT_R16_USCALED: + case VK_FORMAT_R16_SSCALED: + case VK_FORMAT_R16_UINT: + case VK_FORMAT_R16_SINT: + case VK_FORMAT_R16_SFLOAT: + pFormatSize->flags = 0; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 2 * 8; + pFormatSize->blockWidth = 1; + pFormatSize->blockHeight = 1; + pFormatSize->blockDepth = 1; + break; + case VK_FORMAT_R16G16_UNORM: + case VK_FORMAT_R16G16_SNORM: + case VK_FORMAT_R16G16_USCALED: + case VK_FORMAT_R16G16_SSCALED: + case VK_FORMAT_R16G16_UINT: + case VK_FORMAT_R16G16_SINT: + case VK_FORMAT_R16G16_SFLOAT: + pFormatSize->flags = 0; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 4 * 8; + pFormatSize->blockWidth = 1; + pFormatSize->blockHeight = 1; + pFormatSize->blockDepth = 1; + break; + case VK_FORMAT_R16G16B16_UNORM: + case VK_FORMAT_R16G16B16_SNORM: + case VK_FORMAT_R16G16B16_USCALED: + case VK_FORMAT_R16G16B16_SSCALED: + case VK_FORMAT_R16G16B16_UINT: + case VK_FORMAT_R16G16B16_SINT: + case VK_FORMAT_R16G16B16_SFLOAT: + pFormatSize->flags = 0; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 6 * 8; + pFormatSize->blockWidth = 1; + pFormatSize->blockHeight = 1; + pFormatSize->blockDepth = 1; + break; + case VK_FORMAT_R16G16B16A16_UNORM: + case VK_FORMAT_R16G16B16A16_SNORM: + case VK_FORMAT_R16G16B16A16_USCALED: + case VK_FORMAT_R16G16B16A16_SSCALED: + case VK_FORMAT_R16G16B16A16_UINT: + case VK_FORMAT_R16G16B16A16_SINT: + case VK_FORMAT_R16G16B16A16_SFLOAT: + pFormatSize->flags = 0; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 8 * 8; + pFormatSize->blockWidth = 1; + pFormatSize->blockHeight = 1; + pFormatSize->blockDepth = 1; + break; + case VK_FORMAT_R32_UINT: + case VK_FORMAT_R32_SINT: + case VK_FORMAT_R32_SFLOAT: + pFormatSize->flags = 0; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 4 * 8; + pFormatSize->blockWidth = 1; + pFormatSize->blockHeight = 1; + pFormatSize->blockDepth = 1; + break; + case VK_FORMAT_R32G32_UINT: + case VK_FORMAT_R32G32_SINT: + case VK_FORMAT_R32G32_SFLOAT: + pFormatSize->flags = 0; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 8 * 8; + pFormatSize->blockWidth = 1; + pFormatSize->blockHeight = 1; + pFormatSize->blockDepth = 1; + break; + case VK_FORMAT_R32G32B32_UINT: + case VK_FORMAT_R32G32B32_SINT: + case VK_FORMAT_R32G32B32_SFLOAT: + pFormatSize->flags = 0; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 12 * 8; + pFormatSize->blockWidth = 1; + pFormatSize->blockHeight = 1; + pFormatSize->blockDepth = 1; + break; + case VK_FORMAT_R32G32B32A32_UINT: + case VK_FORMAT_R32G32B32A32_SINT: + case VK_FORMAT_R32G32B32A32_SFLOAT: + pFormatSize->flags = 0; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 16 * 8; + pFormatSize->blockWidth = 1; + pFormatSize->blockHeight = 1; + pFormatSize->blockDepth = 1; + break; + case VK_FORMAT_R64_UINT: + case VK_FORMAT_R64_SINT: + case VK_FORMAT_R64_SFLOAT: + pFormatSize->flags = 0; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 8 * 8; + pFormatSize->blockWidth = 1; + pFormatSize->blockHeight = 1; + pFormatSize->blockDepth = 1; + break; + case VK_FORMAT_R64G64_UINT: + case VK_FORMAT_R64G64_SINT: + case VK_FORMAT_R64G64_SFLOAT: + pFormatSize->flags = 0; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 16 * 8; + pFormatSize->blockWidth = 1; + pFormatSize->blockHeight = 1; + pFormatSize->blockDepth = 1; + break; + case VK_FORMAT_R64G64B64_UINT: + case VK_FORMAT_R64G64B64_SINT: + case VK_FORMAT_R64G64B64_SFLOAT: + pFormatSize->flags = 0; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 24 * 8; + pFormatSize->blockWidth = 1; + pFormatSize->blockHeight = 1; + pFormatSize->blockDepth = 1; + break; + case VK_FORMAT_R64G64B64A64_UINT: + case VK_FORMAT_R64G64B64A64_SINT: + case VK_FORMAT_R64G64B64A64_SFLOAT: + pFormatSize->flags = 0; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 32 * 8; + pFormatSize->blockWidth = 1; + pFormatSize->blockHeight = 1; + pFormatSize->blockDepth = 1; + break; + case VK_FORMAT_B10G11R11_UFLOAT_PACK32: + case VK_FORMAT_E5B9G9R9_UFLOAT_PACK32: + pFormatSize->flags = KTX_FORMAT_SIZE_PACKED_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 4 * 8; + pFormatSize->blockWidth = 1; + pFormatSize->blockHeight = 1; + pFormatSize->blockDepth = 1; + break; + case VK_FORMAT_D16_UNORM: + pFormatSize->flags = KTX_FORMAT_SIZE_DEPTH_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 2 * 8; + pFormatSize->blockWidth = 1; + pFormatSize->blockHeight = 1; + pFormatSize->blockDepth = 1; + break; + case VK_FORMAT_X8_D24_UNORM_PACK32: + pFormatSize->flags = KTX_FORMAT_SIZE_PACKED_BIT | KTX_FORMAT_SIZE_DEPTH_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 4 * 8; + pFormatSize->blockWidth = 1; + pFormatSize->blockHeight = 1; + pFormatSize->blockDepth = 1; + break; + case VK_FORMAT_D32_SFLOAT: + pFormatSize->flags = KTX_FORMAT_SIZE_DEPTH_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 4 * 8; + pFormatSize->blockWidth = 1; + pFormatSize->blockHeight = 1; + pFormatSize->blockDepth = 1; + break; + case VK_FORMAT_S8_UINT: + pFormatSize->flags = KTX_FORMAT_SIZE_STENCIL_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 1 * 8; + pFormatSize->blockWidth = 1; + pFormatSize->blockHeight = 1; + pFormatSize->blockDepth = 1; + break; + case VK_FORMAT_D16_UNORM_S8_UINT: + pFormatSize->flags = KTX_FORMAT_SIZE_DEPTH_BIT | KTX_FORMAT_SIZE_STENCIL_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 3 * 8; + pFormatSize->blockWidth = 1; + pFormatSize->blockHeight = 1; + pFormatSize->blockDepth = 1; + break; + case VK_FORMAT_D24_UNORM_S8_UINT: + pFormatSize->flags = KTX_FORMAT_SIZE_DEPTH_BIT | KTX_FORMAT_SIZE_STENCIL_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 4 * 8; + pFormatSize->blockWidth = 1; + pFormatSize->blockHeight = 1; + pFormatSize->blockDepth = 1; + break; + case VK_FORMAT_D32_SFLOAT_S8_UINT: + pFormatSize->flags = KTX_FORMAT_SIZE_DEPTH_BIT | KTX_FORMAT_SIZE_STENCIL_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 8 * 8; + pFormatSize->blockWidth = 1; + pFormatSize->blockHeight = 1; + pFormatSize->blockDepth = 1; + break; + case VK_FORMAT_BC1_RGB_UNORM_BLOCK: + case VK_FORMAT_BC1_RGB_SRGB_BLOCK: + case VK_FORMAT_BC1_RGBA_UNORM_BLOCK: + case VK_FORMAT_BC1_RGBA_SRGB_BLOCK: + case VK_FORMAT_BC4_UNORM_BLOCK: + case VK_FORMAT_BC4_SNORM_BLOCK: + pFormatSize->flags = KTX_FORMAT_SIZE_COMPRESSED_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 8 * 8; + pFormatSize->blockWidth = 4; + pFormatSize->blockHeight = 4; + pFormatSize->blockDepth = 1; + break; + case VK_FORMAT_BC2_UNORM_BLOCK: + case VK_FORMAT_BC2_SRGB_BLOCK: + case VK_FORMAT_BC3_UNORM_BLOCK: + case VK_FORMAT_BC3_SRGB_BLOCK: + case VK_FORMAT_BC5_UNORM_BLOCK: + case VK_FORMAT_BC5_SNORM_BLOCK: + case VK_FORMAT_BC6H_UFLOAT_BLOCK: + case VK_FORMAT_BC6H_SFLOAT_BLOCK: + case VK_FORMAT_BC7_UNORM_BLOCK: + case VK_FORMAT_BC7_SRGB_BLOCK: + pFormatSize->flags = KTX_FORMAT_SIZE_COMPRESSED_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 16 * 8; + pFormatSize->blockWidth = 4; + pFormatSize->blockHeight = 4; + pFormatSize->blockDepth = 1; + break; + case VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK: + case VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK: + case VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK: + case VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK: + pFormatSize->flags = KTX_FORMAT_SIZE_COMPRESSED_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 8 * 8; + pFormatSize->blockWidth = 4; + pFormatSize->blockHeight = 4; + pFormatSize->blockDepth = 1; + break; + case VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK: + case VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK: + case VK_FORMAT_EAC_R11_UNORM_BLOCK: + case VK_FORMAT_EAC_R11_SNORM_BLOCK: + case VK_FORMAT_EAC_R11G11_UNORM_BLOCK: + case VK_FORMAT_EAC_R11G11_SNORM_BLOCK: + pFormatSize->flags = KTX_FORMAT_SIZE_COMPRESSED_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 16 * 8; + pFormatSize->blockWidth = 4; + pFormatSize->blockHeight = 4; + pFormatSize->blockDepth = 1; + break; + case VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG: + case VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG: + pFormatSize->flags = KTX_FORMAT_SIZE_COMPRESSED_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 8 * 8; + pFormatSize->blockWidth = 8; + pFormatSize->blockHeight = 4; + pFormatSize->blockDepth = 1; + pFormatSize->minBlocksX = 2; + pFormatSize->minBlocksY = 2; + break; + case VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG: + case VK_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG: + pFormatSize->flags = KTX_FORMAT_SIZE_COMPRESSED_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 8 * 8; + pFormatSize->blockWidth = 8; + pFormatSize->blockHeight = 4; + pFormatSize->blockDepth = 1; + break; + case VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG: + case VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG: + pFormatSize->flags = KTX_FORMAT_SIZE_COMPRESSED_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 8 * 8; + pFormatSize->blockWidth = 4; + pFormatSize->blockHeight = 4; + pFormatSize->blockDepth = 1; + pFormatSize->minBlocksX = 2; + pFormatSize->minBlocksY = 2; + break; + case VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG: + case VK_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG: + pFormatSize->flags = KTX_FORMAT_SIZE_COMPRESSED_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 8 * 8; + pFormatSize->blockWidth = 4; + pFormatSize->blockHeight = 4; + pFormatSize->blockDepth = 1; + break; + case VK_FORMAT_ASTC_4x4_UNORM_BLOCK: + case VK_FORMAT_ASTC_4x4_SRGB_BLOCK: + pFormatSize->flags = KTX_FORMAT_SIZE_COMPRESSED_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 16 * 8; + pFormatSize->blockWidth = 4; + pFormatSize->blockHeight = 4; + pFormatSize->blockDepth = 1; + break; + case VK_FORMAT_ASTC_5x4_UNORM_BLOCK: + case VK_FORMAT_ASTC_5x4_SRGB_BLOCK: + pFormatSize->flags = KTX_FORMAT_SIZE_COMPRESSED_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 16 * 8; + pFormatSize->blockWidth = 5; + pFormatSize->blockHeight = 4; + pFormatSize->blockDepth = 1; + break; + case VK_FORMAT_ASTC_5x5_UNORM_BLOCK: + case VK_FORMAT_ASTC_5x5_SRGB_BLOCK: + pFormatSize->flags = KTX_FORMAT_SIZE_COMPRESSED_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 16 * 8; + pFormatSize->blockWidth = 5; + pFormatSize->blockHeight = 5; + pFormatSize->blockDepth = 1; + break; + case VK_FORMAT_ASTC_6x5_UNORM_BLOCK: + case VK_FORMAT_ASTC_6x5_SRGB_BLOCK: + pFormatSize->flags = KTX_FORMAT_SIZE_COMPRESSED_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 16 * 8; + pFormatSize->blockWidth = 6; + pFormatSize->blockHeight = 5; + pFormatSize->blockDepth = 1; + break; + case VK_FORMAT_ASTC_6x6_UNORM_BLOCK: + case VK_FORMAT_ASTC_6x6_SRGB_BLOCK: + pFormatSize->flags = KTX_FORMAT_SIZE_COMPRESSED_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 16 * 8; + pFormatSize->blockWidth = 6; + pFormatSize->blockHeight = 6; + pFormatSize->blockDepth = 1; + break; + case VK_FORMAT_ASTC_8x5_UNORM_BLOCK: + case VK_FORMAT_ASTC_8x5_SRGB_BLOCK: + pFormatSize->flags = KTX_FORMAT_SIZE_COMPRESSED_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 16 * 8; + pFormatSize->blockWidth = 8; + pFormatSize->blockHeight = 5; + pFormatSize->blockDepth = 1; + break; + case VK_FORMAT_ASTC_8x6_UNORM_BLOCK: + case VK_FORMAT_ASTC_8x6_SRGB_BLOCK: + pFormatSize->flags = KTX_FORMAT_SIZE_COMPRESSED_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 16 * 8; + pFormatSize->blockWidth = 8; + pFormatSize->blockHeight = 6; + pFormatSize->blockDepth = 1; + break; + case VK_FORMAT_ASTC_8x8_UNORM_BLOCK: + case VK_FORMAT_ASTC_8x8_SRGB_BLOCK: + pFormatSize->flags = KTX_FORMAT_SIZE_COMPRESSED_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 16 * 8; + pFormatSize->blockWidth = 8; + pFormatSize->blockHeight = 8; + pFormatSize->blockDepth = 1; + break; + case VK_FORMAT_ASTC_10x5_UNORM_BLOCK: + case VK_FORMAT_ASTC_10x5_SRGB_BLOCK: + pFormatSize->flags = KTX_FORMAT_SIZE_COMPRESSED_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 16 * 8; + pFormatSize->blockWidth = 10; + pFormatSize->blockHeight = 5; + pFormatSize->blockDepth = 1; + break; + case VK_FORMAT_ASTC_10x6_UNORM_BLOCK: + case VK_FORMAT_ASTC_10x6_SRGB_BLOCK: + pFormatSize->flags = KTX_FORMAT_SIZE_COMPRESSED_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 16 * 8; + pFormatSize->blockWidth = 10; + pFormatSize->blockHeight = 6; + pFormatSize->blockDepth = 1; + break; + case VK_FORMAT_ASTC_10x8_UNORM_BLOCK: + case VK_FORMAT_ASTC_10x8_SRGB_BLOCK: + pFormatSize->flags = KTX_FORMAT_SIZE_COMPRESSED_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 16 * 8; + pFormatSize->blockWidth = 10; + pFormatSize->blockHeight = 8; + pFormatSize->blockDepth = 1; + break; + case VK_FORMAT_ASTC_10x10_UNORM_BLOCK: + case VK_FORMAT_ASTC_10x10_SRGB_BLOCK: + pFormatSize->flags = KTX_FORMAT_SIZE_COMPRESSED_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 16 * 8; + pFormatSize->blockWidth = 10; + pFormatSize->blockHeight = 10; + pFormatSize->blockDepth = 1; + break; + case VK_FORMAT_ASTC_12x10_UNORM_BLOCK: + case VK_FORMAT_ASTC_12x10_SRGB_BLOCK: + pFormatSize->flags = KTX_FORMAT_SIZE_COMPRESSED_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 16 * 8; + pFormatSize->blockWidth = 12; + pFormatSize->blockHeight = 10; + pFormatSize->blockDepth = 1; + break; + case VK_FORMAT_ASTC_12x12_UNORM_BLOCK: + case VK_FORMAT_ASTC_12x12_SRGB_BLOCK: + pFormatSize->flags = KTX_FORMAT_SIZE_COMPRESSED_BIT; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 16 * 8; + pFormatSize->blockWidth = 12; + pFormatSize->blockHeight = 12; + pFormatSize->blockDepth = 1; + break; + default: + pFormatSize->flags = 0; + pFormatSize->paletteSizeInBits = 0; + pFormatSize->blockSizeInBits = 0 * 8; + pFormatSize->blockWidth = 1; + pFormatSize->blockHeight = 1; + pFormatSize->blockDepth = 1; + break; + } +} + +#endif // !VK_FORMAT_H diff --git a/thirdparty/libktx/lib/vkformat_enum.h b/thirdparty/libktx/lib/vkformat_enum.h new file mode 100644 index 000000000000..c6d85602bd22 --- /dev/null +++ b/thirdparty/libktx/lib/vkformat_enum.h @@ -0,0 +1,300 @@ +#if !defined(_VKFORMAT_ENUM_H_) && !defined(VULKAN_CORE_H_) +#define _VKFORMAT_ENUM_H_ + +/***************************** Do not edit. ***************************** + Automatically generated from vulkan_core.h version 151 by mkvkformatfiles. + *************************************************************************/ + +/* +** Copyright (c) 2015-2020 The Khronos Group Inc. +** +** SPDX-License-Identifier: Apache-2.0 +*/ + +#if defined(_MSC_VER) && _MSC_VER < 1900 // Older than VS 2015. +typedef unsigned __int32 VkFlags; +#else +#include +typedef uint32_t VkFlags; +#endif + +typedef enum VkFormat { + VK_FORMAT_UNDEFINED = 0, + VK_FORMAT_R4G4_UNORM_PACK8 = 1, + VK_FORMAT_R4G4B4A4_UNORM_PACK16 = 2, + VK_FORMAT_B4G4R4A4_UNORM_PACK16 = 3, + VK_FORMAT_R5G6B5_UNORM_PACK16 = 4, + VK_FORMAT_B5G6R5_UNORM_PACK16 = 5, + VK_FORMAT_R5G5B5A1_UNORM_PACK16 = 6, + VK_FORMAT_B5G5R5A1_UNORM_PACK16 = 7, + VK_FORMAT_A1R5G5B5_UNORM_PACK16 = 8, + VK_FORMAT_R8_UNORM = 9, + VK_FORMAT_R8_SNORM = 10, + VK_FORMAT_R8_USCALED = 11, + VK_FORMAT_R8_SSCALED = 12, + VK_FORMAT_R8_UINT = 13, + VK_FORMAT_R8_SINT = 14, + VK_FORMAT_R8_SRGB = 15, + VK_FORMAT_R8G8_UNORM = 16, + VK_FORMAT_R8G8_SNORM = 17, + VK_FORMAT_R8G8_USCALED = 18, + VK_FORMAT_R8G8_SSCALED = 19, + VK_FORMAT_R8G8_UINT = 20, + VK_FORMAT_R8G8_SINT = 21, + VK_FORMAT_R8G8_SRGB = 22, + VK_FORMAT_R8G8B8_UNORM = 23, + VK_FORMAT_R8G8B8_SNORM = 24, + VK_FORMAT_R8G8B8_USCALED = 25, + VK_FORMAT_R8G8B8_SSCALED = 26, + VK_FORMAT_R8G8B8_UINT = 27, + VK_FORMAT_R8G8B8_SINT = 28, + VK_FORMAT_R8G8B8_SRGB = 29, + VK_FORMAT_B8G8R8_UNORM = 30, + VK_FORMAT_B8G8R8_SNORM = 31, + VK_FORMAT_B8G8R8_USCALED = 32, + VK_FORMAT_B8G8R8_SSCALED = 33, + VK_FORMAT_B8G8R8_UINT = 34, + VK_FORMAT_B8G8R8_SINT = 35, + VK_FORMAT_B8G8R8_SRGB = 36, + VK_FORMAT_R8G8B8A8_UNORM = 37, + VK_FORMAT_R8G8B8A8_SNORM = 38, + VK_FORMAT_R8G8B8A8_USCALED = 39, + VK_FORMAT_R8G8B8A8_SSCALED = 40, + VK_FORMAT_R8G8B8A8_UINT = 41, + VK_FORMAT_R8G8B8A8_SINT = 42, + VK_FORMAT_R8G8B8A8_SRGB = 43, + VK_FORMAT_B8G8R8A8_UNORM = 44, + VK_FORMAT_B8G8R8A8_SNORM = 45, + VK_FORMAT_B8G8R8A8_USCALED = 46, + VK_FORMAT_B8G8R8A8_SSCALED = 47, + VK_FORMAT_B8G8R8A8_UINT = 48, + VK_FORMAT_B8G8R8A8_SINT = 49, + VK_FORMAT_B8G8R8A8_SRGB = 50, + VK_FORMAT_A8B8G8R8_UNORM_PACK32 = 51, + VK_FORMAT_A8B8G8R8_SNORM_PACK32 = 52, + VK_FORMAT_A8B8G8R8_USCALED_PACK32 = 53, + VK_FORMAT_A8B8G8R8_SSCALED_PACK32 = 54, + VK_FORMAT_A8B8G8R8_UINT_PACK32 = 55, + VK_FORMAT_A8B8G8R8_SINT_PACK32 = 56, + VK_FORMAT_A8B8G8R8_SRGB_PACK32 = 57, + VK_FORMAT_A2R10G10B10_UNORM_PACK32 = 58, + VK_FORMAT_A2R10G10B10_SNORM_PACK32 = 59, + VK_FORMAT_A2R10G10B10_USCALED_PACK32 = 60, + VK_FORMAT_A2R10G10B10_SSCALED_PACK32 = 61, + VK_FORMAT_A2R10G10B10_UINT_PACK32 = 62, + VK_FORMAT_A2R10G10B10_SINT_PACK32 = 63, + VK_FORMAT_A2B10G10R10_UNORM_PACK32 = 64, + VK_FORMAT_A2B10G10R10_SNORM_PACK32 = 65, + VK_FORMAT_A2B10G10R10_USCALED_PACK32 = 66, + VK_FORMAT_A2B10G10R10_SSCALED_PACK32 = 67, + VK_FORMAT_A2B10G10R10_UINT_PACK32 = 68, + VK_FORMAT_A2B10G10R10_SINT_PACK32 = 69, + VK_FORMAT_R16_UNORM = 70, + VK_FORMAT_R16_SNORM = 71, + VK_FORMAT_R16_USCALED = 72, + VK_FORMAT_R16_SSCALED = 73, + VK_FORMAT_R16_UINT = 74, + VK_FORMAT_R16_SINT = 75, + VK_FORMAT_R16_SFLOAT = 76, + VK_FORMAT_R16G16_UNORM = 77, + VK_FORMAT_R16G16_SNORM = 78, + VK_FORMAT_R16G16_USCALED = 79, + VK_FORMAT_R16G16_SSCALED = 80, + VK_FORMAT_R16G16_UINT = 81, + VK_FORMAT_R16G16_SINT = 82, + VK_FORMAT_R16G16_SFLOAT = 83, + VK_FORMAT_R16G16B16_UNORM = 84, + VK_FORMAT_R16G16B16_SNORM = 85, + VK_FORMAT_R16G16B16_USCALED = 86, + VK_FORMAT_R16G16B16_SSCALED = 87, + VK_FORMAT_R16G16B16_UINT = 88, + VK_FORMAT_R16G16B16_SINT = 89, + VK_FORMAT_R16G16B16_SFLOAT = 90, + VK_FORMAT_R16G16B16A16_UNORM = 91, + VK_FORMAT_R16G16B16A16_SNORM = 92, + VK_FORMAT_R16G16B16A16_USCALED = 93, + VK_FORMAT_R16G16B16A16_SSCALED = 94, + VK_FORMAT_R16G16B16A16_UINT = 95, + VK_FORMAT_R16G16B16A16_SINT = 96, + VK_FORMAT_R16G16B16A16_SFLOAT = 97, + VK_FORMAT_R32_UINT = 98, + VK_FORMAT_R32_SINT = 99, + VK_FORMAT_R32_SFLOAT = 100, + VK_FORMAT_R32G32_UINT = 101, + VK_FORMAT_R32G32_SINT = 102, + VK_FORMAT_R32G32_SFLOAT = 103, + VK_FORMAT_R32G32B32_UINT = 104, + VK_FORMAT_R32G32B32_SINT = 105, + VK_FORMAT_R32G32B32_SFLOAT = 106, + VK_FORMAT_R32G32B32A32_UINT = 107, + VK_FORMAT_R32G32B32A32_SINT = 108, + VK_FORMAT_R32G32B32A32_SFLOAT = 109, + VK_FORMAT_R64_UINT = 110, + VK_FORMAT_R64_SINT = 111, + VK_FORMAT_R64_SFLOAT = 112, + VK_FORMAT_R64G64_UINT = 113, + VK_FORMAT_R64G64_SINT = 114, + VK_FORMAT_R64G64_SFLOAT = 115, + VK_FORMAT_R64G64B64_UINT = 116, + VK_FORMAT_R64G64B64_SINT = 117, + VK_FORMAT_R64G64B64_SFLOAT = 118, + VK_FORMAT_R64G64B64A64_UINT = 119, + VK_FORMAT_R64G64B64A64_SINT = 120, + VK_FORMAT_R64G64B64A64_SFLOAT = 121, + VK_FORMAT_B10G11R11_UFLOAT_PACK32 = 122, + VK_FORMAT_E5B9G9R9_UFLOAT_PACK32 = 123, + VK_FORMAT_D16_UNORM = 124, + VK_FORMAT_X8_D24_UNORM_PACK32 = 125, + VK_FORMAT_D32_SFLOAT = 126, + VK_FORMAT_S8_UINT = 127, + VK_FORMAT_D16_UNORM_S8_UINT = 128, + VK_FORMAT_D24_UNORM_S8_UINT = 129, + VK_FORMAT_D32_SFLOAT_S8_UINT = 130, + VK_FORMAT_BC1_RGB_UNORM_BLOCK = 131, + VK_FORMAT_BC1_RGB_SRGB_BLOCK = 132, + VK_FORMAT_BC1_RGBA_UNORM_BLOCK = 133, + VK_FORMAT_BC1_RGBA_SRGB_BLOCK = 134, + VK_FORMAT_BC2_UNORM_BLOCK = 135, + VK_FORMAT_BC2_SRGB_BLOCK = 136, + VK_FORMAT_BC3_UNORM_BLOCK = 137, + VK_FORMAT_BC3_SRGB_BLOCK = 138, + VK_FORMAT_BC4_UNORM_BLOCK = 139, + VK_FORMAT_BC4_SNORM_BLOCK = 140, + VK_FORMAT_BC5_UNORM_BLOCK = 141, + VK_FORMAT_BC5_SNORM_BLOCK = 142, + VK_FORMAT_BC6H_UFLOAT_BLOCK = 143, + VK_FORMAT_BC6H_SFLOAT_BLOCK = 144, + VK_FORMAT_BC7_UNORM_BLOCK = 145, + VK_FORMAT_BC7_SRGB_BLOCK = 146, + VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK = 147, + VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK = 148, + VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK = 149, + VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK = 150, + VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK = 151, + VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK = 152, + VK_FORMAT_EAC_R11_UNORM_BLOCK = 153, + VK_FORMAT_EAC_R11_SNORM_BLOCK = 154, + VK_FORMAT_EAC_R11G11_UNORM_BLOCK = 155, + VK_FORMAT_EAC_R11G11_SNORM_BLOCK = 156, + VK_FORMAT_ASTC_4x4_UNORM_BLOCK = 157, + VK_FORMAT_ASTC_4x4_SRGB_BLOCK = 158, + VK_FORMAT_ASTC_5x4_UNORM_BLOCK = 159, + VK_FORMAT_ASTC_5x4_SRGB_BLOCK = 160, + VK_FORMAT_ASTC_5x5_UNORM_BLOCK = 161, + VK_FORMAT_ASTC_5x5_SRGB_BLOCK = 162, + VK_FORMAT_ASTC_6x5_UNORM_BLOCK = 163, + VK_FORMAT_ASTC_6x5_SRGB_BLOCK = 164, + VK_FORMAT_ASTC_6x6_UNORM_BLOCK = 165, + VK_FORMAT_ASTC_6x6_SRGB_BLOCK = 166, + VK_FORMAT_ASTC_8x5_UNORM_BLOCK = 167, + VK_FORMAT_ASTC_8x5_SRGB_BLOCK = 168, + VK_FORMAT_ASTC_8x6_UNORM_BLOCK = 169, + VK_FORMAT_ASTC_8x6_SRGB_BLOCK = 170, + VK_FORMAT_ASTC_8x8_UNORM_BLOCK = 171, + VK_FORMAT_ASTC_8x8_SRGB_BLOCK = 172, + VK_FORMAT_ASTC_10x5_UNORM_BLOCK = 173, + VK_FORMAT_ASTC_10x5_SRGB_BLOCK = 174, + VK_FORMAT_ASTC_10x6_UNORM_BLOCK = 175, + VK_FORMAT_ASTC_10x6_SRGB_BLOCK = 176, + VK_FORMAT_ASTC_10x8_UNORM_BLOCK = 177, + VK_FORMAT_ASTC_10x8_SRGB_BLOCK = 178, + VK_FORMAT_ASTC_10x10_UNORM_BLOCK = 179, + VK_FORMAT_ASTC_10x10_SRGB_BLOCK = 180, + VK_FORMAT_ASTC_12x10_UNORM_BLOCK = 181, + VK_FORMAT_ASTC_12x10_SRGB_BLOCK = 182, + VK_FORMAT_ASTC_12x12_UNORM_BLOCK = 183, + VK_FORMAT_ASTC_12x12_SRGB_BLOCK = 184, + VK_FORMAT_G8B8G8R8_422_UNORM = 1000156000, + VK_FORMAT_B8G8R8G8_422_UNORM = 1000156001, + VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM = 1000156002, + VK_FORMAT_G8_B8R8_2PLANE_420_UNORM = 1000156003, + VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM = 1000156004, + VK_FORMAT_G8_B8R8_2PLANE_422_UNORM = 1000156005, + VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM = 1000156006, + VK_FORMAT_R10X6_UNORM_PACK16 = 1000156007, + VK_FORMAT_R10X6G10X6_UNORM_2PACK16 = 1000156008, + VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16 = 1000156009, + VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16 = 1000156010, + VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16 = 1000156011, + VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16 = 1000156012, + VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16 = 1000156013, + VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16 = 1000156014, + VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16 = 1000156015, + VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16 = 1000156016, + VK_FORMAT_R12X4_UNORM_PACK16 = 1000156017, + VK_FORMAT_R12X4G12X4_UNORM_2PACK16 = 1000156018, + VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16 = 1000156019, + VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16 = 1000156020, + VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16 = 1000156021, + VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16 = 1000156022, + VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16 = 1000156023, + VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16 = 1000156024, + VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16 = 1000156025, + VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16 = 1000156026, + VK_FORMAT_G16B16G16R16_422_UNORM = 1000156027, + VK_FORMAT_B16G16R16G16_422_UNORM = 1000156028, + VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM = 1000156029, + VK_FORMAT_G16_B16R16_2PLANE_420_UNORM = 1000156030, + VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM = 1000156031, + VK_FORMAT_G16_B16R16_2PLANE_422_UNORM = 1000156032, + VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM = 1000156033, + VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG = 1000054000, + VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG = 1000054001, + VK_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG = 1000054002, + VK_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG = 1000054003, + VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG = 1000054004, + VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG = 1000054005, + VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG = 1000054006, + VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG = 1000054007, + VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK_EXT = 1000066000, + VK_FORMAT_ASTC_5x4_SFLOAT_BLOCK_EXT = 1000066001, + VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK_EXT = 1000066002, + VK_FORMAT_ASTC_6x5_SFLOAT_BLOCK_EXT = 1000066003, + VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK_EXT = 1000066004, + VK_FORMAT_ASTC_8x5_SFLOAT_BLOCK_EXT = 1000066005, + VK_FORMAT_ASTC_8x6_SFLOAT_BLOCK_EXT = 1000066006, + VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK_EXT = 1000066007, + VK_FORMAT_ASTC_10x5_SFLOAT_BLOCK_EXT = 1000066008, + VK_FORMAT_ASTC_10x6_SFLOAT_BLOCK_EXT = 1000066009, + VK_FORMAT_ASTC_10x8_SFLOAT_BLOCK_EXT = 1000066010, + VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK_EXT = 1000066011, + VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK_EXT = 1000066012, + VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK_EXT = 1000066013, + VK_FORMAT_ASTC_3x3x3_UNORM_BLOCK_EXT = 1000288000, + VK_FORMAT_ASTC_3x3x3_SRGB_BLOCK_EXT = 1000288001, + VK_FORMAT_ASTC_3x3x3_SFLOAT_BLOCK_EXT = 1000288002, + VK_FORMAT_ASTC_4x3x3_UNORM_BLOCK_EXT = 1000288003, + VK_FORMAT_ASTC_4x3x3_SRGB_BLOCK_EXT = 1000288004, + VK_FORMAT_ASTC_4x3x3_SFLOAT_BLOCK_EXT = 1000288005, + VK_FORMAT_ASTC_4x4x3_UNORM_BLOCK_EXT = 1000288006, + VK_FORMAT_ASTC_4x4x3_SRGB_BLOCK_EXT = 1000288007, + VK_FORMAT_ASTC_4x4x3_SFLOAT_BLOCK_EXT = 1000288008, + VK_FORMAT_ASTC_4x4x4_UNORM_BLOCK_EXT = 1000288009, + VK_FORMAT_ASTC_4x4x4_SRGB_BLOCK_EXT = 1000288010, + VK_FORMAT_ASTC_4x4x4_SFLOAT_BLOCK_EXT = 1000288011, + VK_FORMAT_ASTC_5x4x4_UNORM_BLOCK_EXT = 1000288012, + VK_FORMAT_ASTC_5x4x4_SRGB_BLOCK_EXT = 1000288013, + VK_FORMAT_ASTC_5x4x4_SFLOAT_BLOCK_EXT = 1000288014, + VK_FORMAT_ASTC_5x5x4_UNORM_BLOCK_EXT = 1000288015, + VK_FORMAT_ASTC_5x5x4_SRGB_BLOCK_EXT = 1000288016, + VK_FORMAT_ASTC_5x5x4_SFLOAT_BLOCK_EXT = 1000288017, + VK_FORMAT_ASTC_5x5x5_UNORM_BLOCK_EXT = 1000288018, + VK_FORMAT_ASTC_5x5x5_SRGB_BLOCK_EXT = 1000288019, + VK_FORMAT_ASTC_5x5x5_SFLOAT_BLOCK_EXT = 1000288020, + VK_FORMAT_ASTC_6x5x5_UNORM_BLOCK_EXT = 1000288021, + VK_FORMAT_ASTC_6x5x5_SRGB_BLOCK_EXT = 1000288022, + VK_FORMAT_ASTC_6x5x5_SFLOAT_BLOCK_EXT = 1000288023, + VK_FORMAT_ASTC_6x6x5_UNORM_BLOCK_EXT = 1000288024, + VK_FORMAT_ASTC_6x6x5_SRGB_BLOCK_EXT = 1000288025, + VK_FORMAT_ASTC_6x6x5_SFLOAT_BLOCK_EXT = 1000288026, + VK_FORMAT_ASTC_6x6x6_UNORM_BLOCK_EXT = 1000288027, + VK_FORMAT_ASTC_6x6x6_SRGB_BLOCK_EXT = 1000288028, + VK_FORMAT_ASTC_6x6x6_SFLOAT_BLOCK_EXT = 1000288029, + VK_FORMAT_A4R4G4B4_UNORM_PACK16_EXT = 1000340000, + VK_FORMAT_A4B4G4R4_UNORM_PACK16_EXT = 1000340001, + VK_FORMAT_MAX_ENUM = 0x7FFFFFFF +} VkFormat; + +#define VK_FORMAT_MAX_STANDARD_ENUM 184 + +#endif /* _VKFORMAT_ENUM_H_ */ diff --git a/thirdparty/libktx/other_include/KHR/khrplatform.h b/thirdparty/libktx/other_include/KHR/khrplatform.h new file mode 100644 index 000000000000..5b55ea2b9814 --- /dev/null +++ b/thirdparty/libktx/other_include/KHR/khrplatform.h @@ -0,0 +1,290 @@ +#ifndef __khrplatform_h_ +#define __khrplatform_h_ + +/* +** Copyright (c) 2008-2018 The Khronos Group Inc. +** +** Permission is hereby granted, free of charge, to any person obtaining a +** copy of this software and/or associated documentation files (the +** "Materials"), to deal in the Materials without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Materials, and to +** permit persons to whom the Materials are furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be included +** in all copies or substantial portions of the Materials. +** +** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. +*/ + +/* Khronos platform-specific types and definitions. + * + * The master copy of khrplatform.h is maintained in the Khronos EGL + * Registry repository at https://github.com/KhronosGroup/EGL-Registry + * The last semantic modification to khrplatform.h was at commit ID: + * 67a3e0864c2d75ea5287b9f3d2eb74a745936692 + * + * Adopters may modify this file to suit their platform. Adopters are + * encouraged to submit platform specific modifications to the Khronos + * group so that they can be included in future versions of this file. + * Please submit changes by filing pull requests or issues on + * the EGL Registry repository linked above. + * + * + * See the Implementer's Guidelines for information about where this file + * should be located on your system and for more details of its use: + * http://www.khronos.org/registry/implementers_guide.pdf + * + * This file should be included as + * #include + * by Khronos client API header files that use its types and defines. + * + * The types in khrplatform.h should only be used to define API-specific types. + * + * Types defined in khrplatform.h: + * khronos_int8_t signed 8 bit + * khronos_uint8_t unsigned 8 bit + * khronos_int16_t signed 16 bit + * khronos_uint16_t unsigned 16 bit + * khronos_int32_t signed 32 bit + * khronos_uint32_t unsigned 32 bit + * khronos_int64_t signed 64 bit + * khronos_uint64_t unsigned 64 bit + * khronos_intptr_t signed same number of bits as a pointer + * khronos_uintptr_t unsigned same number of bits as a pointer + * khronos_ssize_t signed size + * khronos_usize_t unsigned size + * khronos_float_t signed 32 bit floating point + * khronos_time_ns_t unsigned 64 bit time in nanoseconds + * khronos_utime_nanoseconds_t unsigned time interval or absolute time in + * nanoseconds + * khronos_stime_nanoseconds_t signed time interval in nanoseconds + * khronos_boolean_enum_t enumerated boolean type. This should + * only be used as a base type when a client API's boolean type is + * an enum. Client APIs which use an integer or other type for + * booleans cannot use this as the base type for their boolean. + * + * Tokens defined in khrplatform.h: + * + * KHRONOS_FALSE, KHRONOS_TRUE Enumerated boolean false/true values. + * + * KHRONOS_SUPPORT_INT64 is 1 if 64 bit integers are supported; otherwise 0. + * KHRONOS_SUPPORT_FLOAT is 1 if floats are supported; otherwise 0. + * + * Calling convention macros defined in this file: + * KHRONOS_APICALL + * KHRONOS_APIENTRY + * KHRONOS_APIATTRIBUTES + * + * These may be used in function prototypes as: + * + * KHRONOS_APICALL void KHRONOS_APIENTRY funcname( + * int arg1, + * int arg2) KHRONOS_APIATTRIBUTES; + */ + +#if defined(__SCITECH_SNAP__) && !defined(KHRONOS_STATIC) +# define KHRONOS_STATIC 1 +#endif + +/*------------------------------------------------------------------------- + * Definition of KHRONOS_APICALL + *------------------------------------------------------------------------- + * This precedes the return type of the function in the function prototype. + */ +#if defined(KHRONOS_STATIC) + /* If the preprocessor constant KHRONOS_STATIC is defined, make the + * header compatible with static linking. */ +# define KHRONOS_APICALL +#elif defined(_WIN32) +# define KHRONOS_APICALL __declspec(dllimport) +#elif defined (__SYMBIAN32__) +# define KHRONOS_APICALL IMPORT_C +#elif defined(__ANDROID__) +# define KHRONOS_APICALL __attribute__((visibility("default"))) +#else +# define KHRONOS_APICALL +#endif + +/*------------------------------------------------------------------------- + * Definition of KHRONOS_APIENTRY + *------------------------------------------------------------------------- + * This follows the return type of the function and precedes the function + * name in the function prototype. + */ +#if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(KHRONOS_STATIC) + /* Win32 but not WinCE */ +# define KHRONOS_APIENTRY __stdcall +#else +# define KHRONOS_APIENTRY +#endif + +/*------------------------------------------------------------------------- + * Definition of KHRONOS_APIATTRIBUTES + *------------------------------------------------------------------------- + * This follows the closing parenthesis of the function prototype arguments. + */ +#if defined (__ARMCC_2__) +#define KHRONOS_APIATTRIBUTES __softfp +#else +#define KHRONOS_APIATTRIBUTES +#endif + +/*------------------------------------------------------------------------- + * basic type definitions + *-----------------------------------------------------------------------*/ +#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__GNUC__) || defined(__SCO__) || defined(__USLC__) + + +/* + * Using + */ +#include +typedef int32_t khronos_int32_t; +typedef uint32_t khronos_uint32_t; +typedef int64_t khronos_int64_t; +typedef uint64_t khronos_uint64_t; +#define KHRONOS_SUPPORT_INT64 1 +#define KHRONOS_SUPPORT_FLOAT 1 + +#elif defined(__VMS ) || defined(__sgi) + +/* + * Using + */ +#include +typedef int32_t khronos_int32_t; +typedef uint32_t khronos_uint32_t; +typedef int64_t khronos_int64_t; +typedef uint64_t khronos_uint64_t; +#define KHRONOS_SUPPORT_INT64 1 +#define KHRONOS_SUPPORT_FLOAT 1 + +#elif defined(_WIN32) && !defined(__SCITECH_SNAP__) + +/* + * Win32 + */ +typedef __int32 khronos_int32_t; +typedef unsigned __int32 khronos_uint32_t; +typedef __int64 khronos_int64_t; +typedef unsigned __int64 khronos_uint64_t; +#define KHRONOS_SUPPORT_INT64 1 +#define KHRONOS_SUPPORT_FLOAT 1 + +#elif defined(__sun__) || defined(__digital__) + +/* + * Sun or Digital + */ +typedef int khronos_int32_t; +typedef unsigned int khronos_uint32_t; +#if defined(__arch64__) || defined(_LP64) +typedef long int khronos_int64_t; +typedef unsigned long int khronos_uint64_t; +#else +typedef long long int khronos_int64_t; +typedef unsigned long long int khronos_uint64_t; +#endif /* __arch64__ */ +#define KHRONOS_SUPPORT_INT64 1 +#define KHRONOS_SUPPORT_FLOAT 1 + +#elif 0 + +/* + * Hypothetical platform with no float or int64 support + */ +typedef int khronos_int32_t; +typedef unsigned int khronos_uint32_t; +#define KHRONOS_SUPPORT_INT64 0 +#define KHRONOS_SUPPORT_FLOAT 0 + +#else + +/* + * Generic fallback + */ +#include +typedef int32_t khronos_int32_t; +typedef uint32_t khronos_uint32_t; +typedef int64_t khronos_int64_t; +typedef uint64_t khronos_uint64_t; +#define KHRONOS_SUPPORT_INT64 1 +#define KHRONOS_SUPPORT_FLOAT 1 + +#endif + + +/* + * Types that are (so far) the same on all platforms + */ +typedef signed char khronos_int8_t; +typedef unsigned char khronos_uint8_t; +typedef signed short int khronos_int16_t; +typedef unsigned short int khronos_uint16_t; + +/* + * Types that differ between LLP64 and LP64 architectures - in LLP64, + * pointers are 64 bits, but 'long' is still 32 bits. Win64 appears + * to be the only LLP64 architecture in current use. + */ +#ifdef _WIN64 +typedef signed long long int khronos_intptr_t; +typedef unsigned long long int khronos_uintptr_t; +typedef signed long long int khronos_ssize_t; +typedef unsigned long long int khronos_usize_t; +#else +typedef signed long int khronos_intptr_t; +typedef unsigned long int khronos_uintptr_t; +typedef signed long int khronos_ssize_t; +typedef unsigned long int khronos_usize_t; +#endif + +#if KHRONOS_SUPPORT_FLOAT +/* + * Float type + */ +typedef float khronos_float_t; +#endif + +#if KHRONOS_SUPPORT_INT64 +/* Time types + * + * These types can be used to represent a time interval in nanoseconds or + * an absolute Unadjusted System Time. Unadjusted System Time is the number + * of nanoseconds since some arbitrary system event (e.g. since the last + * time the system booted). The Unadjusted System Time is an unsigned + * 64 bit value that wraps back to 0 every 584 years. Time intervals + * may be either signed or unsigned. + */ +typedef khronos_uint64_t khronos_utime_nanoseconds_t; +typedef khronos_int64_t khronos_stime_nanoseconds_t; +#endif + +/* + * Dummy value used to pad enum types to 32 bits. + */ +#ifndef KHRONOS_MAX_ENUM +#define KHRONOS_MAX_ENUM 0x7FFFFFFF +#endif + +/* + * Enumerated boolean type + * + * Values other than zero should be considered to be true. Therefore + * comparisons should not be made against KHRONOS_TRUE. + */ +typedef enum { + KHRONOS_FALSE = 0, + KHRONOS_TRUE = 1, + KHRONOS_BOOLEAN_ENUM_FORCE_SIZE = KHRONOS_MAX_ENUM +} khronos_boolean_enum_t; + +#endif /* __khrplatform_h_ */ diff --git a/thirdparty/libktx/utils/unused.h b/thirdparty/libktx/utils/unused.h new file mode 100644 index 000000000000..31870ab6395c --- /dev/null +++ b/thirdparty/libktx/utils/unused.h @@ -0,0 +1,37 @@ +/* -*- tab-width: 4; -*- */ +/* vi: set sw=2 ts=4 expandtab: */ + +/* Copyright 2019-2018 The Khronos Group Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + +/* I'm extending this beyond the purpose implied by its name rather than creating + * a new file to hold the FALLTHROUGH declaration as this + * file is already included in most places FALLTHROUGH + * is needed. + */ + +#ifndef _UNUSED_H +#define _UNUSED_H + +#if (__cplusplus >= 201703L) +#define MAYBE_UNUSED [[maybe_unused]] +#elif __GNUC__ || __clang__ + #define MAYBE_UNUSED __attribute__((unused)) +#else + // Boohoo. VC++ has no equivalent + #define MAYBE_UNUSED +#endif + +#define U_ASSERT_ONLY MAYBE_UNUSED + +// For unused parameters of c functions. Portable. +#define UNUSED(x) (void)(x) + +#if !__clang__ && __GNUC__ // grumble ... clang ... grumble +#define FALLTHROUGH __attribute__((fallthrough)) +#else +#define FALLTHROUGH +#endif + +#endif /* UNUSED_H */