summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--COPYRIGHT.txt6
-rw-r--r--core/io/image.cpp10
-rw-r--r--core/io/image.h2
-rw-r--r--doc/classes/Image.xml7
-rw-r--r--modules/gltf/extensions/gltf_document_extension_texture_ktx.cpp66
-rw-r--r--modules/gltf/extensions/gltf_document_extension_texture_ktx.h47
-rw-r--r--modules/gltf/register_types.cpp2
-rw-r--r--modules/ktx/SCsub60
-rw-r--r--modules/ktx/config.py6
-rw-r--r--modules/ktx/register_types.cpp53
-rw-r--r--modules/ktx/register_types.h39
-rw-r--r--modules/ktx/texture_loader_ktx.cpp562
-rw-r--r--modules/ktx/texture_loader_ktx.h48
-rw-r--r--thirdparty/README.md19
-rw-r--r--thirdparty/libktx/Apache-2.0.txt208
-rw-r--r--thirdparty/libktx/LICENSE.dfdutils.adoc10
-rw-r--r--thirdparty/libktx/LICENSE.md36
-rw-r--r--thirdparty/libktx/godot.patch45
-rw-r--r--thirdparty/libktx/include/KHR/khr_df.h619
-rw-r--r--thirdparty/libktx/include/ktx.h1810
-rw-r--r--thirdparty/libktx/include/ktxvulkan.h253
-rw-r--r--thirdparty/libktx/lib/basis_sgd.h85
-rw-r--r--thirdparty/libktx/lib/basis_transcode.cpp733
-rw-r--r--thirdparty/libktx/lib/checkheader.c259
-rw-r--r--thirdparty/libktx/lib/dfdutils/KHR/khr_df.h619
-rw-r--r--thirdparty/libktx/lib/dfdutils/colourspaces.c51
-rw-r--r--thirdparty/libktx/lib/dfdutils/createdfd.c659
-rw-r--r--thirdparty/libktx/lib/dfdutils/dfd.h170
-rw-r--r--thirdparty/libktx/lib/dfdutils/dfd2vk.inl599
-rw-r--r--thirdparty/libktx/lib/dfdutils/interpretdfd.c345
-rw-r--r--thirdparty/libktx/lib/dfdutils/printdfd.c97
-rw-r--r--thirdparty/libktx/lib/dfdutils/queries.c146
-rw-r--r--thirdparty/libktx/lib/dfdutils/vk2dfd.c34
-rw-r--r--thirdparty/libktx/lib/dfdutils/vk2dfd.inl340
-rw-r--r--thirdparty/libktx/lib/filestream.c393
-rw-r--r--thirdparty/libktx/lib/filestream.h27
-rw-r--r--thirdparty/libktx/lib/formatsize.h58
-rw-r--r--thirdparty/libktx/lib/gl_format.h2654
-rw-r--r--thirdparty/libktx/lib/hashlist.c604
-rw-r--r--thirdparty/libktx/lib/ktxint.h266
-rw-r--r--thirdparty/libktx/lib/memstream.c561
-rw-r--r--thirdparty/libktx/lib/memstream.h43
-rw-r--r--thirdparty/libktx/lib/swap.c57
-rw-r--r--thirdparty/libktx/lib/texture.c911
-rw-r--r--thirdparty/libktx/lib/texture.h107
-rw-r--r--thirdparty/libktx/lib/texture1.c1459
-rw-r--r--thirdparty/libktx/lib/texture1.h46
-rw-r--r--thirdparty/libktx/lib/texture2.c2524
-rw-r--r--thirdparty/libktx/lib/texture2.h68
-rw-r--r--thirdparty/libktx/lib/texture_funcs.inl76
-rw-r--r--thirdparty/libktx/lib/uthash.h942
-rw-r--r--thirdparty/libktx/lib/vk_format.h1388
-rw-r--r--thirdparty/libktx/lib/vkformat_enum.h300
-rw-r--r--thirdparty/libktx/other_include/KHR/khrplatform.h290
-rw-r--r--thirdparty/libktx/utils/unused.h37
55 files changed, 20856 insertions, 0 deletions
diff --git a/COPYRIGHT.txt b/COPYRIGHT.txt
index f884c690fa..aa98d69ca4 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 a5fea09113..3ca39f98c0 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<uint8_t> &p_array) {
return _load_from_buffer(p_array, _dds_mem_loader_func);
}
+Error Image::load_ktx_from_buffer(const Vector<uint8_t> &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 f68543ba24..cb7c6bff52 100644
--- a/core/io/image.h
+++ b/core/io/image.h
@@ -151,6 +151,7 @@ public:
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 @@ public:
Error load_tga_from_buffer(const Vector<uint8_t> &p_array);
Error load_bmp_from_buffer(const Vector<uint8_t> &p_array);
Error load_dds_from_buffer(const Vector<uint8_t> &p_array);
+ Error load_ktx_from_buffer(const Vector<uint8_t> &p_array);
Error load_svg_from_buffer(const Vector<uint8_t> &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 1486990995..6451062fc5 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.
</description>
</method>
+ <method name="load_ktx_from_buffer">
+ <return type="int" enum="Error" />
+ <param index="0" name="buffer" type="PackedByteArray" />
+ <description>
+ Loads an image from the binary contents of a KTX file.
+ </description>
+ </method>
<method name="load_png_from_buffer">
<return type="int" enum="Error" />
<param index="0" name="buffer" type="PackedByteArray" />
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 0000000000..ca61a24201
--- /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<GLTFState> p_state, Vector<String> p_extensions) {
+ if (!p_extensions.has("KHR_texture_basisu")) {
+ return ERR_SKIP;
+ }
+ return OK;
+}
+
+Vector<String> GLTFDocumentExtensionTextureKTX::get_supported_extensions() {
+ Vector<String> ret;
+ ret.push_back("KHR_texture_basisu");
+ return ret;
+}
+
+Error GLTFDocumentExtensionTextureKTX::parse_image_data(Ref<GLTFState> p_state, const PackedByteArray &p_image_data, const String &p_mime_type, Ref<Image> 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<GLTFState> p_state, const Dictionary &p_texture_json, Ref<GLTFTexture> 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 0000000000..e4cb38a044
--- /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<GLTFState> p_state, Vector<String> p_extensions) override;
+ Vector<String> get_supported_extensions() override;
+ Error parse_image_data(Ref<GLTFState> p_state, const PackedByteArray &p_image_data, const String &p_mime_type, Ref<Image> r_image) override;
+ Error parse_texture_json(Ref<GLTFState> p_state, const Dictionary &p_texture_json, Ref<GLTFTexture> 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 1788ffac3a..c56ad6aedd 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 0000000000..9e45313701
--- /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 0000000000..d22f9454ed
--- /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 0000000000..1d48e05a90
--- /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<ResourceFormatKTX> 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 0000000000..a50dc48b40
--- /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 0000000000..155ed56bd0
--- /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 <ktx.h>
+#include <vk_format.h>
+
+KTX_error_code ktx_read(ktxStream *stream, void *dst, const ktx_size_t count) {
+ Ref<FileAccess> *f = reinterpret_cast<Ref<FileAccess> *>(stream->data.custom_ptr.address);
+ (*f)->get_buffer(reinterpret_cast<uint8_t *>(dst), count);
+ return KTX_SUCCESS;
+}
+
+KTX_error_code ktx_skip(ktxStream *stream, const ktx_size_t count) {
+ Ref<FileAccess> *f = reinterpret_cast<Ref<FileAccess> *>(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<FileAccess> *f = reinterpret_cast<Ref<FileAccess> *>(stream->data.custom_ptr.address);
+ (*f)->store_buffer(reinterpret_cast<const uint8_t *>(src), size * count);
+ return KTX_SUCCESS;
+}
+
+KTX_error_code ktx_getpos(ktxStream *stream, ktx_off_t *const offset) {
+ Ref<FileAccess> *f = reinterpret_cast<Ref<FileAccess> *>(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<FileAccess> *f = reinterpret_cast<Ref<FileAccess> *>(stream->data.custom_ptr.address);
+ (*f)->seek(offset);
+ return KTX_SUCCESS;
+}
+
+KTX_error_code ktx_getsize(ktxStream *stream, ktx_size_t *const size) {
+ Ref<FileAccess> *f = reinterpret_cast<Ref<FileAccess> *>(stream->data.custom_ptr.address);
+ *size = (*f)->get_length();
+ return KTX_SUCCESS;
+}
+
+void ktx_destruct(ktxStream *stream) {
+ (void)stream;
+}
+
+static Ref<Image> load_from_file_access(Ref<FileAccess> 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<Resource>(), "Invalid or unsupported KTX texture file.");
+ }
+
+ if (ktx_texture->numDimensions != 2) {
+ ktxTexture_Destroy(ktx_texture);
+ ERR_FAIL_V_MSG(Ref<Resource>(), "Unsupported non-2D KTX texture file.");
+ }
+
+ if (ktx_texture->isCubemap || ktx_texture->numFaces != 1) {
+ ktxTexture_Destroy(ktx_texture);
+ ERR_FAIL_V_MSG(Ref<Resource>(), "Unsupported cube map KTX texture file.");
+ }
+
+ if (ktx_texture->isArray) {
+ ktxTexture_Destroy(ktx_texture);
+ ERR_FAIL_V_MSG(Ref<Resource>(), "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<Resource>(), "Unsupported format " + itos(((ktxTexture1 *)ktx_texture)->glInternalformat) + " of KTX1 texture file.");
+ }
+ break;
+ case ktxTexture2_c: {
+ ktxTexture2 *ktx_texture2 = reinterpret_cast<ktxTexture2 *>(ktx_texture);
+ if (ktx_texture2->vkFormat == VK_FORMAT_UNDEFINED) {
+ if (!ktxTexture2_NeedsTranscoding(ktx_texture2)) {
+ ktxTexture_Destroy(ktx_texture);
+ ERR_FAIL_V_MSG(Ref<Resource>(), "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<Resource>(), "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<Resource>(), "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<Resource>(), "Unsupported format " + itos(((ktxTexture2 *)ktx_texture)->vkFormat) + " of KTX2 texture file.");
+ break;
+ }
+ break;
+ }
+ default:
+ ktxTexture_Destroy(ktx_texture);
+ ERR_FAIL_V_MSG(Ref<Resource>(), "Unsupported version KTX texture file.");
+ break;
+ }
+
+ Vector<uint8_t> 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<ktx_size_t>(s)) {
+ if (!i) {
+ ktxTexture_Destroy(ktx_texture);
+ ERR_FAIL_V_MSG(Ref<Resource>(), "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<Resource>(), "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<Image> 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<Resource> 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<FileAccess> f = FileAccess::open(p_path, FileAccess::READ, &err);
+ if (f.is_null()) {
+ return Ref<Resource>();
+ }
+
+ Ref<FileAccess> fref(f);
+ if (r_error) {
+ *r_error = ERR_FILE_CORRUPT;
+ }
+
+ ERR_FAIL_COND_V_MSG(err != OK, Ref<Resource>(), "Unable to open KTX texture file '" + p_path + "'.");
+ Ref<Image> img = load_from_file_access(f, r_error);
+ Ref<ImageTexture> texture = ImageTexture::create_from_image(img);
+ return texture;
+}
+
+static Ref<Image> _ktx_mem_loader_func(const uint8_t *p_ktx, int p_size) {
+ Ref<FileAccessMemory> f;
+ f.instantiate();
+ f->open_custom(p_ktx, p_size);
+ Error err;
+ Ref<Image> img = load_from_file_access(f, &err);
+ ERR_FAIL_COND_V(err, Ref<Image>());
+ return img;
+}
+
+void ResourceFormatKTX::get_recognized_extensions(List<String> *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 0000000000..0ea676be6b
--- /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<Resource> 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<String> *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 5053502971..ac21113898 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 0000000000..4ed90b9522
--- /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 0000000000..f206249940
--- /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 0000000000..7b6d05fe48
--- /dev/null
+++ b/thirdparty/libktx/LICENSE.md
@@ -0,0 +1,36 @@
+LICENSE file for the KhronosGroup/KTX-Software project {#license}
+======================================================
+
+<!--
+ Can't put at start. Doxygen requires page title on first line.
+ Copyright 2013-2020 Mark Callow
+ SPDX-License-Identifier: Apache-2.0
+-->
+
+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 0000000000..8a492ee27d
--- /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 0000000000..bbd0d14bd9
--- /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 0000000000..0af87f2519
--- /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 <stdio.h>
+#include <stdbool.h>
+#include <sys/types.h>
+
+#include <KHR/khr_df.h>
+
+/*
+ * 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 <KHR/khrplatform.h> 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 <stdint.h>
+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 <tt>ktxTexture_Iterate*</tt>
+ * 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 <ktxvulkan.h> 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 <a href="http://www.khronos.org/bugzilla/show_bug.cgi?id=999">999</a>: 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 <a href="http://www.khronos.org/bugzilla/show_bug.cgi?id=571">571</a>: crash when null passed for pIsMipmapped.
+@li Public Bugzilla <a href="http://www.khronos.org/bugzilla/show_bug.cgi?id=572">572</a>: memory leak when unpacking ETC textures.
+@li Public Bugzilla <a href="http://www.khronos.org/bugzilla/show_bug.cgi?id=573">573</a>: potential crash when unpacking ETC textures with unused padding pixels.
+@li Public Bugzilla <a href="http://www.khronos.org/bugzilla/show_bug.cgi?id=576">576</a>: 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 0000000000..e695ee6863
--- /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 <ktx.h>
+
+#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 0000000000..6c55909652
--- /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 <stdint.h>
+
+#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<ktxBasisLzEtc1sImageDesc*>(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 0000000000..8df65bcb68
--- /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 <inttypes.h>
+#include <stdio.h>
+#include <KHR/khr_df.h>
+
+#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<ktxBasisLzGlobalHeader*>(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<basisu_transcoder_state> 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<basisu_transcoder_state> 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 0000000000..07e5d919c8
--- /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 <assert.h>
+#include <string.h>
+
+#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 0000000000..bbd0d14bd9
--- /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 0000000000..0d998a71aa
--- /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 <KHR/khr_df.h>
+#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 0000000000..ea00d8d745
--- /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 <stdlib.h>
+#include <KHR/khr_df.h>
+
+#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 0000000000..3ba0249dbb
--- /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 <KHR/khr_df.h>
+
+#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 <vulkan/vulkan_core.h>
+#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 0000000000..cfed9140e9
--- /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 0000000000..273410a18c
--- /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 <stdint.h>
+#include <stdio.h>
+#include <KHR/khr_df.h>
+#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 0000000000..36d3d2c50d
--- /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 <stdio.h>
+#include <KHR/khr_df.h>
+#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 0000000000..19488f9e33
--- /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 <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <KHR/khr_df.h>
+#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 0000000000..d476ced1be
--- /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 0000000000..4ae1e6d5e1
--- /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 0000000000..b1e0eba7c6
--- /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 <assert.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <string.h>
+/* 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 <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h> // For stat.h on Windows
+#define __USE_MISC 1 // For declaration of S_IF...
+#include <sys/stat.h>
+
+#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 0000000000..5c0ea7d2dd
--- /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 0000000000..7112a3a90d
--- /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 0000000000..2381505a68
--- /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 <assert.h>
+#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 0000000000..0ca89fc561
--- /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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+// 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 0000000000..03c9945ce7
--- /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 <math.h>
+
+/* 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 0000000000..b963fa70ca
--- /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 <assert.h>
+#include <string.h>
+#include <stdlib.h>
+
+#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 0000000000..4ef8d59cd2
--- /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 0000000000..3fdeb4f3a4
--- /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 <KHR/khrplatform.h>
+#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 0000000000..35619a3e73
--- /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 <assert.h>
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+
+#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 <tt>base{Width,Height,Depth}</tt> 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 <tt>base{Width,Height,Depth}</tt> 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
+ * <tt>base{Width,Height,Depth}</tt>.
+ * @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 0000000000..e415a09d6a
--- /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 0000000000..8420f402b2
--- /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 <stdlib.h>
+#include <string.h>
+
+#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 <tt>base{Width,Height,Depth}</tt> 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 <tt>base{Width,Height,Depth}</tt> 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
+ * <tt>base{Width,Height,Depth}</tt>.
+ * @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 0000000000..95734cc5f7
--- /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 0000000000..afbe7dcbfe
--- /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 <stdlib.h>
+#include <string.h>
+#include <zstd.h>
+#include <zstd_errors.h>
+#include <KHR/khr_df.h>
+
+#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 <tt>base{Width,Height,Depth}</tt> 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 <tt>base{Width,Height,Depth}</tt> 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
+ * <tt>base{Width,Height,Depth}</tt>.
+ * @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 0000000000..14e4115ecf
--- /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 0000000000..5de16a396b
--- /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 0000000000..aa4729027c
--- /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 <string.h> /* memcmp,strlen */
+#include <stddef.h> /* 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 <inttypes.h> /* 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 <unistd.h> 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 0000000000..18adf33b59
--- /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 0000000000..c6d85602bd
--- /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 <stdint.h>
+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 0000000000..5b55ea2b98
--- /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 <KHR/khrplatform.h>
+ * 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 <stdint.h>
+ */
+#include <stdint.h>
+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 <inttypes.h>
+ */
+#include <inttypes.h>
+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 <stdint.h>
+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 0000000000..31870ab639
--- /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 */