From 1be2fe1f7b97b8d70048bdec14a9ef8beb5db013 Mon Sep 17 00:00:00 2001 From: Jakub Marcowski <01158831@pw.edu.pl> Date: Wed, 7 Feb 2024 19:55:27 +0100 Subject: [PATCH] libktx: Update to 4.3.1 --- modules/ktx/SCsub | 6 + thirdparty/README.md | 12 +- thirdparty/libktx/godot.patch | 45 - thirdparty/libktx/include/KHR/khr_df.h | 163 +-- thirdparty/libktx/include/ktx.h | 49 +- thirdparty/libktx/include/ktxvulkan.h | 58 +- thirdparty/libktx/lib/basis_sgd.h | 2 +- thirdparty/libktx/lib/basis_transcode.cpp | 6 + thirdparty/libktx/lib/checkheader.c | 46 +- thirdparty/libktx/lib/dfdutils/colourspaces.c | 22 +- thirdparty/libktx/lib/dfdutils/createdfd.c | 140 ++- thirdparty/libktx/lib/dfdutils/dfd.h | 80 +- thirdparty/libktx/lib/dfdutils/dfd2vk.inl | 4 + thirdparty/libktx/lib/dfdutils/interpretdfd.c | 558 +++++---- thirdparty/libktx/lib/dfdutils/printdfd.c | 1062 +++++++++++++++-- thirdparty/libktx/lib/dfdutils/vk2dfd.inl | 115 +- thirdparty/libktx/lib/filestream.c | 16 +- thirdparty/libktx/lib/formatsize.h | 1 + thirdparty/libktx/lib/gl_format.h | 4 +- thirdparty/libktx/lib/hashlist.c | 26 +- thirdparty/libktx/lib/ktxint.h | 86 +- thirdparty/libktx/lib/miniz_wrapper.cpp | 149 +++ thirdparty/libktx/lib/swap.c | 2 +- thirdparty/libktx/lib/texture.c | 76 +- thirdparty/libktx/lib/texture1.c | 49 +- thirdparty/libktx/lib/texture2.c | 348 +++++- thirdparty/libktx/lib/texture2.h | 2 + thirdparty/libktx/lib/vkformat_check.c | 165 +++ thirdparty/libktx/lib/vkformat_enum.h | 50 +- thirdparty/libktx/patches/godot.patch | 50 + 30 files changed, 2734 insertions(+), 658 deletions(-) delete mode 100644 thirdparty/libktx/godot.patch create mode 100644 thirdparty/libktx/lib/miniz_wrapper.cpp create mode 100644 thirdparty/libktx/lib/vkformat_check.c create mode 100644 thirdparty/libktx/patches/godot.patch diff --git a/modules/ktx/SCsub b/modules/ktx/SCsub index b160f7a2872..acdb8299798 100644 --- a/modules/ktx/SCsub +++ b/modules/ktx/SCsub @@ -16,10 +16,12 @@ thirdparty_sources = [ "lib/filestream.c", "lib/hashlist.c", "lib/memstream.c", + "lib/miniz_wrapper.cpp", "lib/swap.c", "lib/texture.c", "lib/texture1.c", "lib/texture2.c", + "lib/vkformat_check.c", "lib/dfdutils/createdfd.c", "lib/dfdutils/colourspaces.c", "lib/dfdutils/interpretdfd.c", @@ -33,7 +35,11 @@ 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"]) + env_ktx.Prepend(CPPPATH=["#thirdparty/basis_universal"]) +if env.editor_build: + # We already build miniz in the basis_universal module (editor only). + env_ktx.Append(CPPDEFINES=["MINIZ_HEADER_FILE_ONLY"]) if env["vulkan"]: env_ktx.Prepend(CPPPATH=["#thirdparty/vulkan/include"]) diff --git a/thirdparty/README.md b/thirdparty/README.md index 2e99abc622d..8a11cc9447d 100644 --- a/thirdparty/README.md +++ b/thirdparty/README.md @@ -426,19 +426,21 @@ Files extracted from upstream source: ## libktx - Upstream: https://github.com/KhronosGroup/KTX-Software -- Version: 4.1.0 (d7255fe73cd53b856731ceb9f2c279181d0dbbca, 2023) +- Version: 4.3.1 (c0214158d551cfc779624b0f84130bcbbefef59a, 2024) - 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` +- `lib/dfdutils/LICENSE.adoc` as `LICENSE.dfdutils.adoc` (in root) +- `lib/dfdutils/LICENSES/Apache-2.0.txt` as `Apache-2.0.txt` (in root) +- `lib/dfdutils/{KHR/*,dfd.h,colourspaces.c,createdfd.c,interpretdfd.c,printdfd.c,queries.c,dfd2vk.inl,vk2dfd.*}` +- `lib/{basis_sgd.h,formatsize.h,gl_format.h,ktxint.h,uthash.h,vk_format.h,vkformat_enum.h,checkheader.c,swap.c,hashlist.c,vkformat_check.c,basis_transcode.cpp,miniz_wrapper.cpp,filestream.*,memstream.*,texture*}` - `other_include/KHR/*` +- `utils/unused.h` -Some Godot-specific changes are applied via `godot.patch`. +Some Godot-specific changes are applied via patches included in the `patches` folder. ## libogg diff --git a/thirdparty/libktx/godot.patch b/thirdparty/libktx/godot.patch deleted file mode 100644 index 8a492ee27dd..00000000000 --- a/thirdparty/libktx/godot.patch +++ /dev/null @@ -1,45 +0,0 @@ ---- 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 index bbd0d14bd90..c0d03aa763e 100644 --- a/thirdparty/libktx/include/KHR/khr_df.h +++ b/thirdparty/libktx/include/KHR/khr_df.h @@ -17,6 +17,11 @@ #ifndef _KHR_DATA_FORMAT_H_ #define _KHR_DATA_FORMAT_H_ +/** @file khr_df.h + + @brief Data Format enums and macros. +*/ + /* Accessors */ typedef enum _khr_word_e { KHR_DF_WORD_VENDORID = 0U, @@ -217,41 +222,42 @@ typedef enum _khr_df_versionnumber_e { KHR_DF_VERSIONNUMBER_MAX = 0xFFFFU } khr_df_versionnumber_e; -/* Model in which the color coordinate space is defined. +/** @~English + @brief 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 */ + /** No interpretation of color channels defined */ KHR_DF_MODEL_UNSPECIFIED = 0U, - /* Color primaries (red, green, blue) + alpha, depth and stencil */ + /** Color primaries (red, green, blue) + alpha, depth and stencil */ KHR_DF_MODEL_RGBSDA = 1U, - /* Color differences (Y', Cb, Cr) + alpha, depth and stencil */ + /** Color differences (Y', Cb, Cr) + alpha, depth and stencil */ KHR_DF_MODEL_YUVSDA = 2U, - /* Color differences (Y', I, Q) + alpha, depth and stencil */ + /** Color differences (Y', I, Q) + alpha, depth and stencil */ KHR_DF_MODEL_YIQSDA = 3U, - /* Perceptual color (CIE L*a*b*) + alpha, depth and stencil */ + /** Perceptual color (CIE L*a*b*) + alpha, depth and stencil */ KHR_DF_MODEL_LABSDA = 4U, - /* Subtractive colors (cyan, magenta, yellow, black) + alpha */ + /** Subtractive colors (cyan, magenta, yellow, black) + alpha */ KHR_DF_MODEL_CMYKA = 5U, - /* Non-color coordinate data (X, Y, Z, W) */ + /** Non-color coordinate data (X, Y, Z, W) */ KHR_DF_MODEL_XYZW = 6U, - /* Hue, saturation, value, hue angle on color circle, plus alpha */ + /** 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 */ + /** 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 */ + /** Hue, saturation, value, hue on color hexagon, plus alpha */ KHR_DF_MODEL_HSVA_HEX = 9U, - /* Hue, saturation, lightness, hue on color hexagon, plus alpha */ + /** Hue, saturation, lightness, hue on color hexagon, plus alpha */ KHR_DF_MODEL_HSLA_HEX = 10U, - /* Lightweight approximate color difference (luma, orange, green) */ + /** Lightweight approximate color difference (luma, orange, green) */ KHR_DF_MODEL_YCGCOA = 11U, - /* ITU BT.2020 constant luminance YcCbcCrc */ + /** ITU BT.2020 constant luminance YcCbcCrc */ KHR_DF_MODEL_YCCBCCRC = 12U, - /* ITU BT.2100 constant intensity ICtCp */ + /** ITU BT.2100 constant intensity ICtCp */ KHR_DF_MODEL_ICTCP = 13U, - /* CIE 1931 XYZ color coordinates (X, Y, Z) */ + /** CIE 1931 XYZ color coordinates (X, Y, Z) */ KHR_DF_MODEL_CIEXYZ = 14U, - /* CIE 1931 xyY color coordinates (X, Y, Y) */ + /** CIE 1931 xyY color coordinates (X, Y, Y) */ KHR_DF_MODEL_CIEXYY = 15U, /* Compressed formats start at 128. */ @@ -260,51 +266,54 @@ typedef enum _khr_df_model_e { 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 */ + /** 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 */ + /** 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 */ + /** 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) */ + /** 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) */ + /** 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 */ + /** BC6H - DX11 format for 16-bit float channels */ KHR_DF_MODEL_BC6H = 133U, - /* BC7 - DX11 format */ + /** 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 */ + /** 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 */ + /** 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 */ + /** 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 */ + /** ETC1S is a simplified subset of ETC1 */ KHR_DF_MODEL_ETC1S = 163U, - /* PowerVR Texture Compression */ + /** PowerVR Texture Compression v1 */ KHR_DF_MODEL_PVRTC = 164U, + /** PowerVR Texture Compression v2 */ KHR_DF_MODEL_PVRTC2 = 165U, + /** UASTC is a transcodable subset of ASTC + with additions to support the transcoding. */ KHR_DF_MODEL_UASTC = 166U, /* Proprietary formats (ATITC, etc.) should follow */ KHR_DF_MODEL_MAX = 0xFFU @@ -520,86 +529,88 @@ typedef enum _khr_df_model_channels_e { KHR_DF_CHANNEL_COMMON_A = 15U } khr_df_model_channels_e; -/* Definition of the primary colors in color coordinates. +/** @~English + @brief 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 */ + /** No color primaries defined */ KHR_DF_PRIMARIES_UNSPECIFIED = 0U, - /* Color primaries of ITU-R BT.709 and sRGB */ + /** Color primaries of ITU-R BT.709 and sRGB */ KHR_DF_PRIMARIES_BT709 = 1U, - /* Synonym for KHR_DF_PRIMARIES_BT709 */ + /** Synonym for KHR_DF_PRIMARIES_BT709 */ KHR_DF_PRIMARIES_SRGB = 1U, - /* Color primaries of ITU-R BT.601 (625-line EBU variant) */ + /** 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) */ + /** 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 */ + /** Color primaries of ITU-R BT.2020 */ KHR_DF_PRIMARIES_BT2020 = 4U, - /* CIE theoretical color coordinate space */ + /** CIE theoretical color coordinate space */ KHR_DF_PRIMARIES_CIEXYZ = 5U, - /* Academy Color Encoding System primaries */ + /** Academy Color Encoding System primaries */ KHR_DF_PRIMARIES_ACES = 6U, - /* Color primaries of ACEScc */ + /** Color primaries of ACEScc */ KHR_DF_PRIMARIES_ACESCC = 7U, - /* Legacy NTSC 1953 primaries */ + /** Legacy NTSC 1953 primaries */ KHR_DF_PRIMARIES_NTSC1953 = 8U, - /* Legacy PAL 525-line primaries */ + /** Legacy PAL 525-line primaries */ KHR_DF_PRIMARIES_PAL525 = 9U, - /* Color primaries of Display P3 */ + /** Color primaries of Display P3 */ KHR_DF_PRIMARIES_DISPLAYP3 = 10U, - /* Color primaries of Adobe RGB (1998) */ + /** 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 +/** @~English + @brief 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 */ + /** No transfer function defined */ KHR_DF_TRANSFER_UNSPECIFIED = 0U, - /* Linear transfer function (value proportional to intensity) */ + /** Linear transfer function (value proportional to intensity) */ KHR_DF_TRANSFER_LINEAR = 1U, - /* Perceptually-linear transfer function of sRGH (~2.4) */ + /** 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) */ + /** 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) */ + /** 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) */ + /** Perceptually-linear gamma function of original NTSC (simple 2.2 gamma) */ KHR_DF_TRANSFER_NTSC = 4U, - /* Sony S-log used by Sony video cameras */ + /** Sony S-log used by Sony video cameras */ KHR_DF_TRANSFER_SLOG = 5U, - /* Sony S-log 2 used by Sony video cameras */ + /** Sony S-log 2 used by Sony video cameras */ KHR_DF_TRANSFER_SLOG2 = 6U, - /* ITU BT.1886 EOTF */ + /** ITU BT.1886 EOTF */ KHR_DF_TRANSFER_BT1886 = 7U, - /* ITU BT.2100 HLG OETF */ + /** ITU BT.2100 HLG OETF */ KHR_DF_TRANSFER_HLG_OETF = 8U, - /* ITU BT.2100 HLG EOTF */ + /** ITU BT.2100 HLG EOTF */ KHR_DF_TRANSFER_HLG_EOTF = 9U, - /* ITU BT.2100 PQ EOTF */ + /** ITU BT.2100 PQ EOTF */ KHR_DF_TRANSFER_PQ_EOTF = 10U, - /* ITU BT.2100 PQ OETF */ + /** ITU BT.2100 PQ OETF */ KHR_DF_TRANSFER_PQ_OETF = 11U, - /* DCI P3 transfer function */ + /** DCI P3 transfer function */ KHR_DF_TRANSFER_DCIP3 = 12U, - /* Legacy PAL OETF */ + /** Legacy PAL OETF */ KHR_DF_TRANSFER_PAL_OETF = 13U, - /* Legacy PAL 625-line EOTF */ + /** Legacy PAL 625-line EOTF */ KHR_DF_TRANSFER_PAL625_EOTF = 14U, - /* Legacy ST240 transfer function */ + /** Legacy ST240 transfer function */ KHR_DF_TRANSFER_ST240 = 15U, - /* ACEScc transfer function */ + /** ACEScc transfer function */ KHR_DF_TRANSFER_ACESCC = 16U, - /* ACEScct transfer function */ + /** ACEScct transfer function */ KHR_DF_TRANSFER_ACESCCT = 17U, - /* Adobe RGB (1998) transfer function */ + /** Adobe RGB (1998) transfer function */ KHR_DF_TRANSFER_ADOBERGB = 18U, KHR_DF_TRANSFER_MAX = 0xFFU } khr_df_transfer_e; diff --git a/thirdparty/libktx/include/ktx.h b/thirdparty/libktx/include/ktx.h index 0af87f25190..dcf5dae42a5 100644 --- a/thirdparty/libktx/include/ktx.h +++ b/thirdparty/libktx/include/ktx.h @@ -25,6 +25,7 @@ * @snippet{doc} version.h API version */ +#include #include #include #include @@ -156,6 +157,7 @@ extern "C" { * @brief Required unpack alignment */ #define KTX_GL_UNPACK_ALIGNMENT 4 +#define KTX_FACESLICE_WHOLE_LEVEL UINT_MAX #define KTX_TRUE true #define KTX_FALSE false @@ -176,15 +178,17 @@ typedef enum ktx_error_code_e { 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_INVALID_VALUE, /*!< A parameter value was not valid. */ + KTX_NOT_FOUND, /*!< Requested metadata key or required dynamically loaded GPU function 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_DECOMPRESS_LENGTH_ERROR, /*!< Decompressed byte count does not match expected byte size */ + KTX_DECOMPRESS_CHECKSUM_ERROR, /*!< Checksum mismatch when decompressing */ + KTX_ERROR_MAX_ENUM = KTX_DECOMPRESS_CHECKSUM_ERROR /*!< For safety checks. */ } ktx_error_code_e; /** * @deprecated @@ -672,8 +676,9 @@ 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_ZLIB = 3, /*!< ZLIB supercompression. */ KTX_SS_BEGIN_RANGE = KTX_SS_NONE, - KTX_SS_END_RANGE = KTX_SS_ZSTD, + KTX_SS_END_RANGE = KTX_SS_ZLIB, KTX_SS_BEGIN_VENDOR_RANGE = 0x10000, KTX_SS_END_VENDOR_RANGE = 0x1ffff, KTX_SS_BEGIN_RESERVED = 0x20000, @@ -703,15 +708,21 @@ typedef struct ktxTexture2 { struct ktxTexture2_private* _private; /*!< Private data. */ } ktxTexture2; +/** + * @brief Helper for casting ktxTexture1 and ktxTexture2 to ktxTexture. + * + * Use with caution. + */ #define ktxTexture(t) ((ktxTexture*)t) /** * @memberof ktxTexture * @~English - * @brief Structure for passing texture information to ktxTexture1_Create() and - * ktxTexture2_Create(). + * @brief Structure for passing texture information to ktxTexture1\_Create() and + * ktxTexture2\_Create(). * - * @sa ktxTexture1_Create() and ktxTexture2_Create(). + * @sa @ref ktxTexture1::ktxTexture1\_Create() "ktxTexture1_Create()" + * @sa @ref ktxTexture2::ktxTexture2\_Create() "ktxTexture2_Create()" */ typedef struct { @@ -766,9 +777,12 @@ enum ktxTextureCreateFlagBits { 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 + KTX_TEXTURE_CREATE_SKIP_KVDATA_BIT = 0x04, /*!< Skip any key-value data. This overrides the RAW_KVDATA_BIT. */ + KTX_TEXTURE_CREATE_CHECK_GLTF_BASISU_BIT = 0x08 + /*!< Load texture compatible with the rules + of KHR_texture_basisu glTF extension */ }; /** * @memberof ktxTexture @@ -1053,6 +1067,9 @@ 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 KTX_error_code KTX_APIENTRY +ktxTexture2_DeflateZLIB(ktxTexture2* This, ktx_uint32_t level); + KTX_API void KTX_APIENTRY ktxTexture2_GetComponentInfo(ktxTexture2* This, ktx_uint32_t* numComponents, ktx_uint32_t* componentByteLength); @@ -1682,6 +1699,19 @@ 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); +/*===========================================================* + * Utilities for printing info about a KTX2 file. * + *===========================================================*/ + +KTX_API KTX_error_code KTX_APIENTRY ktxPrintKTX2InfoTextForMemory(const ktx_uint8_t* bytes, ktx_size_t size); +KTX_API KTX_error_code KTX_APIENTRY ktxPrintKTX2InfoTextForNamedFile(const char* const filename); +KTX_API KTX_error_code KTX_APIENTRY ktxPrintKTX2InfoTextForStdioStream(FILE* stdioStream); +KTX_API KTX_error_code KTX_APIENTRY ktxPrintKTX2InfoTextForStream(ktxStream* stream); +KTX_API KTX_error_code KTX_APIENTRY ktxPrintKTX2InfoJSONForMemory(const ktx_uint8_t* bytes, ktx_size_t size, ktx_uint32_t base_indent, ktx_uint32_t indent_width, bool minified); +KTX_API KTX_error_code KTX_APIENTRY ktxPrintKTX2InfoJSONForNamedFile(const char* const filename, ktx_uint32_t base_indent, ktx_uint32_t indent_width, bool minified); +KTX_API KTX_error_code KTX_APIENTRY ktxPrintKTX2InfoJSONForStdioStream(FILE* stdioStream, ktx_uint32_t base_indent, ktx_uint32_t indent_width, bool minified); +KTX_API KTX_error_code KTX_APIENTRY ktxPrintKTX2InfoJSONForStream(ktxStream* stream, ktx_uint32_t base_indent, ktx_uint32_t indent_width, bool minified); + #ifdef __cplusplus } #endif @@ -1709,6 +1739,9 @@ KTX_API KTX_error_code KTX_APIENTRY ktxPrintInfoForMemory(const ktx_uint8_t* byt @~English @page libktx_history Revision History +No longer updated. Kept to preserve ancient history. For more recent history see the repo log at +https://github.com/KhronosGroup/KTX-Software. See also the Release Notes in the repo. + @section v8 Version 4.0 Added: @li Support for KTX Version 2. diff --git a/thirdparty/libktx/include/ktxvulkan.h b/thirdparty/libktx/include/ktxvulkan.h index e695ee6863d..2162b1fc591 100644 --- a/thirdparty/libktx/include/ktxvulkan.h +++ b/thirdparty/libktx/include/ktxvulkan.h @@ -23,8 +23,6 @@ * alternative is duplicating unattractively large parts of it. * * @author Mark Callow, Edgewise Consulting - * - * $Date$ */ #include @@ -116,8 +114,9 @@ typedef struct ktxVulkanTexture 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. */ + VkDeviceMemory deviceMemory; /*!< The memory (sub)allocation for the + image on the Vulkan device. Will not be + used with suballocators.*/ VkImageViewType viewType; /*!< ViewType corresponding to @p image. Reflects the dimensionality, cubeness and arrayness of the image. */ @@ -126,15 +125,41 @@ typedef struct ktxVulkanTexture 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. */ + uint64_t allocationId; /*!< An id referencing suballocation(s). */ } ktxVulkanTexture; +typedef uint64_t(*ktxVulkanTexture_subAllocatorAllocMemFuncPtr)(VkMemoryAllocateInfo* allocInfo, VkMemoryRequirements* memReq, uint64_t* pageCount); +typedef VkResult(*ktxVulkanTexture_subAllocatorBindBufferFuncPtr)(VkBuffer buffer, uint64_t allocId); +typedef VkResult(*ktxVulkanTexture_subAllocatorBindImageFuncPtr)(VkImage image, uint64_t allocId); +typedef VkResult(*ktxVulkanTexture_subAllocatorMemoryMapFuncPtr)(uint64_t allocId, uint64_t pageNumber, VkDeviceSize *mapLength, void** dataPtr); +typedef void (*ktxVulkanTexture_subAllocatorMemoryUnmapFuncPtr)(uint64_t allocId, uint64_t pageNumber); +typedef void (*ktxVulkanTexture_subAllocatorFreeMemFuncPtr)(uint64_t allocId); +/** + * @class ktxVulkanTexture_subAllocatorCallbacks + * @~English + * @brief Struct that contains all callbacks necessary for suballocation. + * + * These pointers must all be provided for upload or destroy to occur using suballocator callbacks. + */ +typedef struct { + ktxVulkanTexture_subAllocatorAllocMemFuncPtr allocMemFuncPtr; /*!< Pointer to the memory procurement function. Can suballocate one or more pages. */ + ktxVulkanTexture_subAllocatorBindBufferFuncPtr bindBufferFuncPtr; /*!< Pointer to bind-buffer-to-suballocation(s) function. */ + ktxVulkanTexture_subAllocatorBindImageFuncPtr bindImageFuncPtr; /*!< Pointer to bind-image-to-suballocation(s) function. */ + ktxVulkanTexture_subAllocatorMemoryMapFuncPtr memoryMapFuncPtr; /*!< Pointer to function for mapping the memory of a specific page. */ + ktxVulkanTexture_subAllocatorMemoryUnmapFuncPtr memoryUnmapFuncPtr; /*!< Pointer to function for unmapping the memory of a specific page. */ + ktxVulkanTexture_subAllocatorFreeMemFuncPtr freeMemFuncPtr; /*!< Pointer to the free procurement function. */ +} ktxVulkanTexture_subAllocatorCallbacks; + +KTX_API ktx_error_code_e KTX_APIENTRY +ktxVulkanTexture_Destruct_WithSuballocator(ktxVulkanTexture* This, VkDevice device, + const VkAllocationCallbacks* pAllocator, + ktxVulkanTexture_subAllocatorCallbacks* subAllocatorCallbacks); + KTX_API void KTX_APIENTRY ktxVulkanTexture_Destruct(ktxVulkanTexture* This, VkDevice device, const VkAllocationCallbacks* pAllocator); - - /** * @class ktxVulkanDeviceInfo * @~English @@ -210,6 +235,13 @@ ktxVulkanDeviceInfo_Destruct(ktxVulkanDeviceInfo* This); KTX_API void KTX_APIENTRY ktxVulkanDeviceInfo_Destroy(ktxVulkanDeviceInfo* This); KTX_API KTX_error_code KTX_APIENTRY +ktxTexture_VkUploadEx_WithSuballocator(ktxTexture* This, ktxVulkanDeviceInfo* vdi, + ktxVulkanTexture* vkTexture, + VkImageTiling tiling, + VkImageUsageFlags usageFlags, + VkImageLayout finalLayout, + ktxVulkanTexture_subAllocatorCallbacks* subAllocatorCallbacks); +KTX_API KTX_error_code KTX_APIENTRY ktxTexture_VkUploadEx(ktxTexture* This, ktxVulkanDeviceInfo* vdi, ktxVulkanTexture* vkTexture, VkImageTiling tiling, @@ -219,6 +251,13 @@ KTX_API KTX_error_code KTX_APIENTRY ktxTexture_VkUpload(ktxTexture* texture, ktxVulkanDeviceInfo* vdi, ktxVulkanTexture *vkTexture); KTX_API KTX_error_code KTX_APIENTRY +ktxTexture1_VkUploadEx_WithSuballocator(ktxTexture1* This, ktxVulkanDeviceInfo* vdi, + ktxVulkanTexture* vkTexture, + VkImageTiling tiling, + VkImageUsageFlags usageFlags, + VkImageLayout finalLayout, + ktxVulkanTexture_subAllocatorCallbacks* subAllocatorCallbacks); +KTX_API KTX_error_code KTX_APIENTRY ktxTexture1_VkUploadEx(ktxTexture1* This, ktxVulkanDeviceInfo* vdi, ktxVulkanTexture* vkTexture, VkImageTiling tiling, @@ -228,6 +267,13 @@ KTX_API KTX_error_code KTX_APIENTRY ktxTexture1_VkUpload(ktxTexture1* texture, ktxVulkanDeviceInfo* vdi, ktxVulkanTexture *vkTexture); KTX_API KTX_error_code KTX_APIENTRY +ktxTexture2_VkUploadEx_WithSuballocator(ktxTexture2* This, ktxVulkanDeviceInfo* vdi, + ktxVulkanTexture* vkTexture, + VkImageTiling tiling, + VkImageUsageFlags usageFlags, + VkImageLayout finalLayout, + ktxVulkanTexture_subAllocatorCallbacks* subAllocatorCallbacks); +KTX_API KTX_error_code KTX_APIENTRY ktxTexture2_VkUploadEx(ktxTexture2* This, ktxVulkanDeviceInfo* vdi, ktxVulkanTexture* vkTexture, VkImageTiling tiling, diff --git a/thirdparty/libktx/lib/basis_sgd.h b/thirdparty/libktx/lib/basis_sgd.h index 6c559096529..15804e8d265 100644 --- a/thirdparty/libktx/lib/basis_sgd.h +++ b/thirdparty/libktx/lib/basis_sgd.h @@ -28,7 +28,7 @@ extern "C" { // 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 }; +enum bu_image_flags__bits_e { ETC1S_P_FRAME = 0x02 }; typedef uint32_t buFlags; diff --git a/thirdparty/libktx/lib/basis_transcode.cpp b/thirdparty/libktx/lib/basis_transcode.cpp index 8df65bcb68f..d7ecb7a0fdc 100644 --- a/thirdparty/libktx/lib/basis_transcode.cpp +++ b/thirdparty/libktx/lib/basis_transcode.cpp @@ -372,6 +372,12 @@ ktxTexture2_transcodeUastc(ktxTexture2* This, This->dataSize = prototype->dataSize; prototype->pData = 0; prototype->dataSize = 0; + // Free SGD data + This->_private->_sgdByteLength = 0; + if (This->_private->_supercompressionGlobalData) { + free(This->_private->_supercompressionGlobalData); + This->_private->_supercompressionGlobalData = NULL; + } } ktxTexture2_Destroy(prototype); return result; diff --git a/thirdparty/libktx/lib/checkheader.c b/thirdparty/libktx/lib/checkheader.c index 07e5d919c8c..cee47ce3417 100644 --- a/thirdparty/libktx/lib/checkheader.c +++ b/thirdparty/libktx/lib/checkheader.c @@ -1,7 +1,7 @@ /* -*- tab-width: 4; -*- */ /* vi: set sw=2 ts=4 expandtab: */ -/* $Id: ee6f7be4d43390de78e1815ed158012c78ddeff1 $ */ +/* $Id$ */ /* * Copyright 2010-2020 The Khronos Group Inc. @@ -27,6 +27,10 @@ #include "ktx.h" #include "ktxint.h" +#include "vkformat_enum.h" + +bool isProhibitedFormat(VkFormat format); +bool isValidFormat(VkFormat format); /** * @internal @@ -112,7 +116,7 @@ KTX_error_code ktxCheckHeader1_(KTX_header* pHeader, if (pHeader->numberOfArrayElements > 0) { /* No 3D array textures yet. */ - return KTX_UNSUPPORTED_TEXTURE_TYPE; + return KTX_UNSUPPORTED_FEATURE; } pSuppInfo->textureDimension = 3; } @@ -192,6 +196,20 @@ KTX_error_code ktxCheckHeader2_(KTX_header2* pHeader, return KTX_UNKNOWN_FILE_FORMAT; } + /* Check format */ + if (isProhibitedFormat(pHeader->vkFormat)) + { + return KTX_FILE_DATA_ERROR; + } + if (!isValidFormat(pHeader->vkFormat)) + { + return KTX_UNSUPPORTED_FEATURE; + } + if (pHeader->supercompressionScheme == KTX_SS_BASIS_LZ && pHeader->vkFormat != VK_FORMAT_UNDEFINED) + { + 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 extension for 3D array textures in any 3D API. */ @@ -208,7 +226,7 @@ KTX_error_code ktxCheckHeader2_(KTX_header2* pHeader, if (pHeader->layerCount > 0) { /* No 3D array textures yet. */ - return KTX_UNSUPPORTED_TEXTURE_TYPE; + return KTX_UNSUPPORTED_FEATURE; } pSuppInfo->textureDimension = 3; } @@ -228,6 +246,16 @@ KTX_error_code ktxCheckHeader2_(KTX_header2* pHeader, /* cube map needs 2D faces */ return KTX_FILE_DATA_ERROR; } + if (pHeader->pixelDepth != 0) + { + /* cube map cannot have depth */ + return KTX_FILE_DATA_ERROR; + } + if (pHeader->pixelWidth != pHeader->pixelHeight) + { + /* cube map needs square faces */ + return KTX_FILE_DATA_ERROR; + } } else if (pHeader->faceCount != 1) { @@ -246,6 +274,18 @@ KTX_error_code ktxCheckHeader2_(KTX_header2* pHeader, pSuppInfo->generateMipmaps = 0; } + // Check supercompression + switch (pHeader->supercompressionScheme) { + case KTX_SS_NONE: + case KTX_SS_BASIS_LZ: + case KTX_SS_ZSTD: + case KTX_SS_ZLIB: + break; + default: + // Unsupported supercompression + return KTX_UNSUPPORTED_FEATURE; + } + // 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))) diff --git a/thirdparty/libktx/lib/dfdutils/colourspaces.c b/thirdparty/libktx/lib/dfdutils/colourspaces.c index 0d998a71aa7..8e934746bf4 100644 --- a/thirdparty/libktx/lib/dfdutils/colourspaces.c +++ b/thirdparty/libktx/lib/dfdutils/colourspaces.c @@ -36,7 +36,7 @@ sPrimaryMapping primaryMap[] = { * @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) { +khr_df_primaries_e findMapping(const 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 && @@ -49,3 +49,23 @@ khr_df_primaries_e findMapping(Primaries *p, float latitude) { /* No match */ return KHR_DF_PRIMARIES_UNSPECIFIED; } + +/** + * @brief Get the primaries corresponding to a KDFS primaries enum. + * + * @param[in] primaries the enum identifying the KDFS primaries. + * @param[out] p pointer to a Primaries struct that will + * be filled with the primary values. + */ +bool getPrimaries(khr_df_primaries_e primaries, Primaries *p) { + unsigned int i; + for (i = 0; i < sizeof(primaryMap)/sizeof(sPrimaryMapping); ++i) { + if (primaryMap[i].dfPrimaryEnum == primaries) { + *p = primaryMap[i].primaries; + return true; + } + } + + /* No match */ + return false; +} diff --git a/thirdparty/libktx/lib/dfdutils/createdfd.c b/thirdparty/libktx/lib/dfdutils/createdfd.c index ea00d8d7458..2a5af00c7e7 100644 --- a/thirdparty/libktx/lib/dfdutils/createdfd.c +++ b/thirdparty/libktx/lib/dfdutils/createdfd.c @@ -15,7 +15,9 @@ * Author: Andrew Garrard */ +#include #include +#include #include #include "dfd.h" @@ -228,6 +230,8 @@ uint32_t *createDFDUnpacked(int bigEndian, int numChannels, int bytes, * @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 paddings[] An array of length numChannels. + * Each entry is the number of padding bits after each channel. * @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 @@ -239,9 +243,9 @@ uint32_t *createDFDUnpacked(int bigEndian, int numChannels, int bytes, * @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 *createDFDPackedPadded(int bigEndian, int numChannels, + int bits[], int paddings[], int channels[], + enum VkSuffix suffix) { uint32_t *DFD = 0; if (numChannels == 6) { @@ -287,7 +291,7 @@ uint32_t *createDFDPacked(int bigEndian, int numChannels, int sampleCounter; for (channelCounter = 0; channelCounter < numChannels; ++channelCounter) { beChannelStart[channelCounter] = totalBits; - totalBits += bits[channelCounter]; + totalBits += bits[channelCounter] + paddings[channelCounter]; } BEMask = (totalBits - 1) & 0x18; for (channelCounter = 0; channelCounter < numChannels; ++channelCounter) { @@ -297,7 +301,7 @@ uint32_t *createDFDPacked(int bigEndian, int numChannels, bitChannel[((bitOffset + bits[channelCounter] - 1) & ~7) ^ BEMask] = channelCounter; numSamples++; } - bitOffset += bits[channelCounter]; + bitOffset += bits[channelCounter] + paddings[channelCounter]; } DFD = writeHeader(numSamples, totalBits >> 3, suffix, i_COLOR); @@ -339,7 +343,7 @@ uint32_t *createDFDPacked(int bigEndian, int numChannels, int totalBits = 0; int bitOffset = 0; for (sampleCounter = 0; sampleCounter < numChannels; ++sampleCounter) { - totalBits += bits[sampleCounter]; + totalBits += bits[sampleCounter] + paddings[sampleCounter]; } /* One sample per channel */ @@ -348,12 +352,98 @@ uint32_t *createDFDPacked(int bigEndian, int numChannels, writeSample(DFD, sampleCounter, channels[sampleCounter], bits[sampleCounter], bitOffset, 1, 1, suffix); - bitOffset += bits[sampleCounter]; + bitOffset += bits[sampleCounter] + paddings[sampleCounter]; } } 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) { + assert(numChannels <= 6); + int paddings[] = {0, 0, 0, 0, 0, 0}; + return createDFDPackedPadded(bigEndian, numChannels, bits, paddings, channels, suffix); +} + +uint32_t *createDFD422(int bigEndian, int numSamples, + int bits[], int paddings[], int channels[], + int position_xs[], int position_ys[], + enum VkSuffix suffix) { + assert(!bigEndian); (void) bigEndian; + assert(suffix == s_UNORM); (void) suffix; + + int totalBits = 0; + for (int i = 0; i < numSamples; ++i) + totalBits += bits[i] + paddings[i]; + assert(totalBits % 8 == 0); + + uint32_t BDFDSize = sizeof(uint32_t) * (KHR_DF_WORD_SAMPLESTART + numSamples * KHR_DF_WORD_SAMPLEWORDS); + uint32_t DFDSize = sizeof(uint32_t) + BDFDSize; + uint32_t *DFD = (uint32_t *) malloc(DFDSize); + memset(DFD, 0, DFDSize); + DFD[0] = DFDSize; + uint32_t *BDFD = DFD + 1; + KHR_DFDSETVAL(BDFD, VENDORID, KHR_DF_VENDORID_KHRONOS); + KHR_DFDSETVAL(BDFD, DESCRIPTORTYPE, KHR_DF_KHR_DESCRIPTORTYPE_BASICFORMAT); + KHR_DFDSETVAL(BDFD, VERSIONNUMBER, KHR_DF_VERSIONNUMBER_LATEST); + KHR_DFDSETVAL(BDFD, DESCRIPTORBLOCKSIZE, BDFDSize); + KHR_DFDSETVAL(BDFD, MODEL, KHR_DF_MODEL_YUVSDA); + KHR_DFDSETVAL(BDFD, PRIMARIES, KHR_DF_PRIMARIES_UNSPECIFIED); + KHR_DFDSETVAL(BDFD, TRANSFER, KHR_DF_TRANSFER_LINEAR); + KHR_DFDSETVAL(BDFD, FLAGS, KHR_DF_FLAG_ALPHA_STRAIGHT); + KHR_DFDSETVAL(BDFD, TEXELBLOCKDIMENSION0, 2 - 1); // 422 contains 2 x 1 blocks + KHR_DFDSETVAL(BDFD, TEXELBLOCKDIMENSION1, 1 - 1); + KHR_DFDSETVAL(BDFD, TEXELBLOCKDIMENSION2, 1 - 1); + KHR_DFDSETVAL(BDFD, TEXELBLOCKDIMENSION3, 1 - 1); + KHR_DFDSETVAL(BDFD, BYTESPLANE0, totalBits / 8); + KHR_DFDSETVAL(BDFD, BYTESPLANE1, 0); + KHR_DFDSETVAL(BDFD, BYTESPLANE2, 0); + KHR_DFDSETVAL(BDFD, BYTESPLANE3, 0); + KHR_DFDSETVAL(BDFD, BYTESPLANE4, 0); + KHR_DFDSETVAL(BDFD, BYTESPLANE5, 0); + KHR_DFDSETVAL(BDFD, BYTESPLANE6, 0); + KHR_DFDSETVAL(BDFD, BYTESPLANE7, 0); + + int bitOffset = 0; + for (int i = 0; i < numSamples; ++i) { + KHR_DFDSETSVAL(BDFD, i, BITOFFSET, bitOffset); + KHR_DFDSETSVAL(BDFD, i, BITLENGTH, bits[i] - 1); + KHR_DFDSETSVAL(BDFD, i, CHANNELID, channels[i]); + KHR_DFDSETSVAL(BDFD, i, QUALIFIERS, 0); // None of: FLOAT, SIGNED, EXPONENT, LINEAR + KHR_DFDSETSVAL(BDFD, i, SAMPLEPOSITION0, position_xs[i]); + KHR_DFDSETSVAL(BDFD, i, SAMPLEPOSITION1, position_ys[i]); + KHR_DFDSETSVAL(BDFD, i, SAMPLEPOSITION2, 0); + KHR_DFDSETSVAL(BDFD, i, SAMPLEPOSITION3, 0); + KHR_DFDSETSVAL(BDFD, i, SAMPLELOWER, 0); + KHR_DFDSETSVAL(BDFD, i, SAMPLEUPPER, (1u << bits[i]) - 1u); + bitOffset += bits[i] + paddings[i]; + } + + 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. */ @@ -657,3 +747,39 @@ uint32_t *createDFDDepthStencil(int depthBits, } return DFD; } + +/** + * @~English + * @brief Create a Data Format Descriptor for an alpha-only format. + * + * @param bigEndian Set to 1 for big-endian byte ordering and + 0 for little-endian byte ordering. + * @param bytes The number of bytes per channel. + * @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 *createDFDAlpha(int bigEndian, int bytes, + enum VkSuffix suffix) { + uint32_t *DFD; + int channel = 3; /* alpha channel */ + if (bigEndian) { + int channelByte; + /* Number of samples = number of channels * bytes per channel */ + DFD = writeHeader(bytes, bytes, suffix, i_COLOR); + /* Loop over the bytes that constitute a channel */ + for (channelByte = 0; channelByte < bytes; ++channelByte) { + writeSample(DFD, channelByte, channel, + 8, 8 * (bytes - channelByte - 1), + channelByte == bytes-1, channelByte == 0, suffix); + } + } else { /* Little-endian */ + /* One sample per channel */ + DFD = writeHeader(1, bytes, suffix, i_COLOR); + writeSample(DFD, 0, channel, + 8 * bytes, 0, + 1, 1, suffix); + } + return DFD; +} diff --git a/thirdparty/libktx/lib/dfdutils/dfd.h b/thirdparty/libktx/lib/dfdutils/dfd.h index 3ba0249dbb2..7f1fb74a6b9 100644 --- a/thirdparty/libktx/lib/dfdutils/dfd.h +++ b/thirdparty/libktx/lib/dfdutils/dfd.h @@ -19,6 +19,7 @@ #define _DFD_H_ #include +#include #ifdef __cplusplus extern "C" { @@ -72,11 +73,22 @@ uint32_t* vk2dfd(enum VkFormat format); uint32_t *createDFDUnpacked(int bigEndian, int numChannels, int bytes, int redBlueSwap, enum VkSuffix suffix); +/* Create a Data Format Descriptor for a packed padded format. */ +uint32_t *createDFDPackedPadded(int bigEndian, int numChannels, + int bits[], int paddings[], int channels[], + 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 4:2:2 format. */ +uint32_t *createDFD422(int bigEndian, int numChannels, + int bits[], int paddings[], int channels[], + int position_xs[], int position_ys[], + enum VkSuffix suffix); + /* Create a Data Format Descriptor for a compressed format. */ uint32_t *createDFDCompressed(enum VkCompScheme compScheme, int bwidth, int bheight, int bdepth, @@ -87,16 +99,22 @@ uint32_t *createDFDDepthStencil(int depthBits, int stencilBits, int sizeBytes); +/* Create a Data Format Descriptor for an alpha-only format */ +uint32_t *createDFDAlpha(int bigEndian, int bytes, + enum VkSuffix suffix); + /** @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. */ + i_BIG_ENDIAN_FORMAT_BIT = 1u << 0u, /*!< Confirmed big-endian. */ + i_PACKED_FORMAT_BIT = 1u << 1u, /*!< Packed format. */ + i_SRGB_FORMAT_BIT = 1u << 2u, /*!< sRGB transfer function. */ + i_NORMALIZED_FORMAT_BIT = 1u << 3u, /*!< Normalized (UNORM or SNORM). */ + i_SIGNED_FORMAT_BIT = 1u << 4u, /*!< Format is signed. */ + i_FLOAT_FORMAT_BIT = 1u << 5u, /*!< Format is floating point. */ + i_COMPRESSED_FORMAT_BIT = 1u << 6u, /*!< Format is block compressed (422). */ + i_YUVSDA_FORMAT_BIT = 1u << 7u, /*!< Color model is YUVSDA. */ + i_UNSUPPORTED_ERROR_BIT = 1u << 8u, /*!< 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, @@ -109,7 +127,9 @@ enum InterpretDFDResult { 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 + i_UNSUPPORTED_MIXED_CHANNELS = i_UNSUPPORTED_ERROR_BIT + 4, + /** Only 2x1 block is supported for YUVSDA model. */ + i_UNSUPPORTED_BLOCK_DIMENSIONS = i_UNSUPPORTED_ERROR_BIT + 5, }; /** @brief Interpretation of a channel from the data format descriptor. */ @@ -126,8 +146,47 @@ enum InterpretDFDResult interpretDFD(const uint32_t *DFD, InterpretedDFDChannel *A, uint32_t *wordBytes); +/* Returns the string representation. + * If there is no direct match or the value is invalid returns NULL */ +const char* dfdToStringVendorID(khr_df_vendorid_e value); + +/* Returns the string representation. + * If there is no direct match or the value is invalid returns NULL */ +const char* dfdToStringDescriptorType(khr_df_khr_descriptortype_e value); + +/* Returns the string representation. + * If there is no direct match or the value is invalid returns NULL */ +const char* dfdToStringVersionNumber(khr_df_versionnumber_e value); + +/* Returns the string representation of a bit in a khr_df_flags_e. + * If there is no direct match or the value is invalid returns NULL */ +const char* dfdToStringFlagsBit(uint32_t bit_index, bool bit_value); + +/* Returns the string representation. + * If there is no direct match or the value is invalid returns NULL */ +const char* dfdToStringTransferFunction(khr_df_transfer_e value); + +/* Returns the string representation. + * If there is no direct match or the value is invalid returns NULL */ +const char* dfdToStringColorPrimaries(khr_df_primaries_e value); + +/* Returns the string representation. + * If there is no direct match or the value is invalid returns NULL */ +const char* dfdToStringColorModel(khr_df_model_e value); + +/* Returns the string representation of a bit in a khr_df_sample_datatype_qualifiers_e. + * If there is no direct match or the value is invalid returns NULL */ +const char* dfdToStringSampleDatatypeQualifiersBit(uint32_t bit_index, bool bit_value); + +/* Returns the string representation. + * If there is no direct match or the value is invalid returns NULL */ +const char* dfdToStringChannelId(khr_df_model_e model, khr_df_model_channels_e value); + /* Print a human-readable interpretation of a data format descriptor. */ -void printDFD(uint32_t *DFD); +void printDFD(uint32_t *DFD, uint32_t dataSize); + +/* Print a JSON interpretation of a data format descriptor. */ +void printDFDJSON(uint32_t *DFD, uint32_t dataSize, uint32_t base_indent, uint32_t indent_width, bool minified); /* Get the number of components & component size from a DFD for an * unpacked format. @@ -161,7 +220,8 @@ typedef struct _Primaries { float Wy; /*!< White y. */ } Primaries; -khr_df_primaries_e findMapping(Primaries *p, float latitude); +khr_df_primaries_e findMapping(const Primaries *p, float latitude); +bool getPrimaries(khr_df_primaries_e primaries, Primaries *p); #ifdef __cplusplus } diff --git a/thirdparty/libktx/lib/dfdutils/dfd2vk.inl b/thirdparty/libktx/lib/dfdutils/dfd2vk.inl index cfed9140e9f..8b4de41597a 100644 --- a/thirdparty/libktx/lib/dfdutils/dfd2vk.inl +++ b/thirdparty/libktx/lib/dfdutils/dfd2vk.inl @@ -51,6 +51,7 @@ if (KHR_DFDVAL(dfd + 1, MODEL) == KHR_DF_MODEL_RGBSDA) { } 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; + if (B.offset == 10) return VK_FORMAT_A1B5G5R5_UNORM_PACK16_KHR; return VK_FORMAT_B5G5R5A1_UNORM_PACK16; } } else if (wordBytes == 4) { /* PACK32 */ @@ -74,6 +75,9 @@ if (KHR_DFDVAL(dfd + 1, MODEL) == KHR_DF_MODEL_RGBSDA) { } } else { /* Not a packed format */ if (wordBytes == 1) { + if (A.size > 8 && R.size == 0 && G.size == 0 && B.size == 0 && (r & i_NORMALIZED_FORMAT_BIT) && !(r & i_SIGNED_FORMAT_BIT)) { + return VK_FORMAT_A8_UNORM_KHR; + } if (A.size > 0) { /* 4 channels */ if (R.offset == 0) { /* RGBA */ if ((r & i_SRGB_FORMAT_BIT)) return VK_FORMAT_R8G8B8A8_SRGB; diff --git a/thirdparty/libktx/lib/dfdutils/interpretdfd.c b/thirdparty/libktx/lib/dfdutils/interpretdfd.c index 273410a18cc..6d25f33a1b6 100644 --- a/thirdparty/libktx/lib/dfdutils/interpretdfd.c +++ b/thirdparty/libktx/lib/dfdutils/interpretdfd.c @@ -17,6 +17,14 @@ #include #include "dfd.h" +static uint32_t bit_ceil(uint32_t x) { + x -= 1; + for (uint32_t i = 0; i < sizeof(x) * 8; ++i) + if (1u << i > x) + return 1u << i; + return 0; +} + /** * @~English * @brief Interpret a Data Format Descriptor for a simple format. @@ -25,8 +33,8 @@ 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 R Information about the decoded red channel or the depth channel, if any. + * @param G Information about the decoded green channel or the stencil 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). @@ -54,14 +62,14 @@ enum InterpretDFDResult interpretDFD(const uint32_t *DFD, const uint32_t *BDFDB = DFD+1; uint32_t numSamples = KHR_DFDSAMPLECOUNT(BDFDB); + if (numSamples == 0) + return i_UNSUPPORTED_CHANNEL_TYPES; - uint32_t sampleCounter; int determinedEndianness = 0; - int determinedNormalizedness = 0; - int determinedSignedness = 0; - int determinedFloatness = 0; enum InterpretDFDResult result = 0; /* Build this up incrementally. */ + bool isDepthStencil = false; + /* Clear these so following code doesn't get confused. */ R->offset = R->size = 0; G->offset = G->size = 0; @@ -76,270 +84,322 @@ enum InterpretDFDResult interpretDFD(const uint32_t *DFD, 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) { + for (uint32_t sampleCounter = 0; sampleCounter < numSamples; ++sampleCounter) { + uint32_t offset = KHR_DFDSVAL(BDFDB, sampleCounter, BITOFFSET); + uint32_t length = KHR_DFDSVAL(BDFDB, sampleCounter, BITLENGTH) + 1; + if ((offset & 0x7U) || ((offset + length) & 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; + // Check data types. + bool hasSigned = false; + bool hasFloat = false; + bool hasNormalized = false; + + // Note: We're ignoring 9995, which is weird and worth special-casing + // rather than trying to generalise to all float formats. + for (uint32_t i = 0; i < numSamples; ++i) { + const bool isSigned = (KHR_DFDSVAL(BDFDB, i, QUALIFIERS) & KHR_DF_SAMPLE_DATATYPE_SIGNED) != 0; + const bool isFloat = (KHR_DFDSVAL(BDFDB, i, QUALIFIERS) & KHR_DF_SAMPLE_DATATYPE_FLOAT) != 0; + + // We define "unnormalized" as "sample_upper = 1" or "sample_upper = 1.0f". + // 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. + const bool isNormalized = isFloat ? + *(float*) (void*) &BDFDB[KHR_DF_WORD_SAMPLESTART + + KHR_DF_WORD_SAMPLEWORDS * i + + KHR_DF_SAMPLEWORD_SAMPLEUPPER] != 1.0f : + KHR_DFDSVAL(BDFDB, i, SAMPLEUPPER) != 1U; + + hasSigned |= isSigned; + hasFloat |= isFloat; + // By our definition the normalizedness of a single bit channel (like in RGBA 5:5:5:1) + // is ambiguous. Ignore these during normalized checks. + if (KHR_DFDSVAL(BDFDB, i, BITLENGTH) > 0) + hasNormalized |= isNormalized; + } + result |= hasSigned ? i_SIGNED_FORMAT_BIT : 0; + result |= hasFloat ? i_FLOAT_FORMAT_BIT : 0; + result |= hasNormalized ? i_NORMALIZED_FORMAT_BIT : 0; + + // Checks based on color model + if (KHR_DFDVAL(BDFDB, MODEL) == KHR_DF_MODEL_YUVSDA) { + result |= i_NORMALIZED_FORMAT_BIT; + result |= i_COMPRESSED_FORMAT_BIT; + result |= i_YUVSDA_FORMAT_BIT; + + for (uint32_t i = 0; i < numSamples; ++i) { + switch (KHR_DFDSVAL(BDFDB, i, CHANNELID)) { + case KHR_DF_CHANNEL_YUVSDA_Y: + case KHR_DF_CHANNEL_YUVSDA_U: + case KHR_DF_CHANNEL_YUVSDA_V: + case KHR_DF_CHANNEL_YUVSDA_A: 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; + case KHR_DF_CHANNEL_YUVSDA_DEPTH: + case KHR_DF_CHANNEL_YUVSDA_STENCIL: + isDepthStencil = true; 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; + } + + // Determine wordBytes + uint32_t largestSampleSize = 0; + for (uint32_t i = 0; i < numSamples; ++i) { + uint32_t length = KHR_DFDSVAL(BDFDB, i, BITLENGTH) + 1; + if (largestSampleSize < length) + largestSampleSize = length; + } + *wordBytes = ((result & i_PACKED_FORMAT_BIT) ? 4 : 1) * bit_ceil(largestSampleSize) / 8; + + } else if (KHR_DFDVAL(BDFDB, MODEL) == KHR_DF_MODEL_RGBSDA) { + /* 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 (uint32_t sampleCounter = 0; sampleCounter < numSamples; ++sampleCounter) { + if (KHR_DFDSVAL(BDFDB, sampleCounter, SAMPLEPOSITION_ALL)) + return i_UNSUPPORTED_MULTIPLE_SAMPLE_LOCATIONS; + } + + /* For Depth/Stencil formats mixed channels are allowed */ + for (uint32_t sampleCounter = 0; sampleCounter < numSamples; ++sampleCounter) { + switch (KHR_DFDSVAL(BDFDB, sampleCounter, CHANNELID)) { + case KHR_DF_CHANNEL_RGBSDA_DEPTH: + case KHR_DF_CHANNEL_RGBSDA_STENCIL: + isDepthStencil = true; + break; + default: + break; } } - 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; + + // Check for mixed channels + if (!isDepthStencil) { + for (uint32_t i = 0; i < numSamples; ++i) { + const bool isSigned = (KHR_DFDSVAL(BDFDB, i, QUALIFIERS) & KHR_DF_SAMPLE_DATATYPE_SIGNED) != 0; + const bool isFloat = (KHR_DFDSVAL(BDFDB, i, QUALIFIERS) & KHR_DF_SAMPLE_DATATYPE_FLOAT) != 0; + + if (isSigned != hasSigned) + return i_UNSUPPORTED_MIXED_CHANNELS; + if (isFloat != hasFloat) + return i_UNSUPPORTED_MIXED_CHANNELS; + + // Note: We don't check for inconsistent normalization, because + // channels composed of multiple samples will have 0 in the + // lower/upper range. Single bit channels are also ambiguous. + // This heuristic should handle 64-bit integers, too. + } + } + + /* 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 (uint32_t 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_DEPTH: + sampleChannelPtr = R; + break; + case KHR_DF_CHANNEL_RGBSDA_STENCIL: + sampleChannelPtr = G; + 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 (uint32_t 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_DEPTH: + sampleChannelPtr = R; + break; + case KHR_DF_CHANNEL_RGBSDA_STENCIL: + sampleChannelPtr = G; + 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; + } + } } } 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 i_UNSUPPORTED_CHANNEL_TYPES; } + + if (isDepthStencil) { + /* For Depth/Stencil formats wordBytes is determined by the required alignment of */ + /* the larger channel. */ + uint32_t largerSize = R->size > G->size ? R->size : G->size; + *wordBytes = bit_ceil(largerSize); + } + return result; } diff --git a/thirdparty/libktx/lib/dfdutils/printdfd.c b/thirdparty/libktx/lib/dfdutils/printdfd.c index 36d3d2c50d4..bfdd33ba04d 100644 --- a/thirdparty/libktx/lib/dfdutils/printdfd.c +++ b/thirdparty/libktx/lib/dfdutils/printdfd.c @@ -15,83 +15,1011 @@ * Author: Andrew Garrard */ +#include +#include #include +#include #include #include "dfd.h" +enum { + // These constraints are not mandated by the spec and only used as a + // reasonable upper limit to stop parsing garbage data during print + MAX_NUM_BDFD_SAMPLES = 16, + MAX_NUM_DFD_BLOCKS = 10, +}; + +const char* dfdToStringVendorID(khr_df_vendorid_e value) { + switch (value) { + case KHR_DF_VENDORID_KHRONOS: + return "KHR_DF_VENDORID_KHRONOS"; + + case KHR_DF_VENDORID_MAX: + // These enum values are not meant for string representation. Ignore + break; + } + return NULL; +} + +const char* dfdToStringDescriptorType(khr_df_khr_descriptortype_e value) { + switch (value) { + case KHR_DF_KHR_DESCRIPTORTYPE_BASICFORMAT: + return "KHR_DF_KHR_DESCRIPTORTYPE_BASICFORMAT"; + case KHR_DF_KHR_DESCRIPTORTYPE_ADDITIONAL_PLANES: + return "KHR_DF_KHR_DESCRIPTORTYPE_ADDITIONAL_PLANES"; + case KHR_DF_KHR_DESCRIPTORTYPE_ADDITIONAL_DIMENSIONS: + return "KHR_DF_KHR_DESCRIPTORTYPE_ADDITIONAL_DIMENSIONS"; + + case KHR_DF_KHR_DESCRIPTORTYPE_NEEDED_FOR_WRITE_BIT: + case KHR_DF_KHR_DESCRIPTORTYPE_NEEDED_FOR_DECODE_BIT: + case KHR_DF_KHR_DESCRIPTORTYPE_MAX: + // These enum values are not meant for string representation. Ignore + break; + } + return NULL; +} + +const char* dfdToStringVersionNumber(khr_df_versionnumber_e value) { + switch (value) { + case KHR_DF_VERSIONNUMBER_1_1: + // case KHR_DF_VERSIONNUMBER_1_0: // Fallthrough, Matching values + return "KHR_DF_VERSIONNUMBER_1_1"; + case KHR_DF_VERSIONNUMBER_1_2: + return "KHR_DF_VERSIONNUMBER_1_2"; + case KHR_DF_VERSIONNUMBER_1_3: + return "KHR_DF_VERSIONNUMBER_1_3"; + + // case KHR_DF_VERSIONNUMBER_LATEST: // Fallthrough, Matching values + case KHR_DF_VERSIONNUMBER_MAX: + // These enum values are not meant for string representation. Ignore + break; + } + return NULL; +} + +const char* dfdToStringFlagsBit(uint32_t bit_index, bool bit_value) { + switch (bit_index) { + case 0: + return bit_value ? "KHR_DF_FLAG_ALPHA_PREMULTIPLIED" : "KHR_DF_FLAG_ALPHA_STRAIGHT"; + default: + return NULL; + } +} + +const char* dfdToStringTransferFunction(khr_df_transfer_e value) { + switch (value) { + case KHR_DF_TRANSFER_UNSPECIFIED: + return "KHR_DF_TRANSFER_UNSPECIFIED"; + case KHR_DF_TRANSFER_LINEAR: + return "KHR_DF_TRANSFER_LINEAR"; + case KHR_DF_TRANSFER_SRGB: + return "KHR_DF_TRANSFER_SRGB"; + case KHR_DF_TRANSFER_ITU: + return "KHR_DF_TRANSFER_ITU"; + case KHR_DF_TRANSFER_NTSC: + // case KHR_DF_TRANSFER_SMTPE170M: // Fallthrough, Matching values + return "KHR_DF_TRANSFER_NTSC"; + case KHR_DF_TRANSFER_SLOG: + return "KHR_DF_TRANSFER_SLOG"; + case KHR_DF_TRANSFER_SLOG2: + return "KHR_DF_TRANSFER_SLOG2"; + case KHR_DF_TRANSFER_BT1886: + return "KHR_DF_TRANSFER_BT1886"; + case KHR_DF_TRANSFER_HLG_OETF: + return "KHR_DF_TRANSFER_HLG_OETF"; + case KHR_DF_TRANSFER_HLG_EOTF: + return "KHR_DF_TRANSFER_HLG_EOTF"; + case KHR_DF_TRANSFER_PQ_EOTF: + return "KHR_DF_TRANSFER_PQ_EOTF"; + case KHR_DF_TRANSFER_PQ_OETF: + return "KHR_DF_TRANSFER_PQ_OETF"; + case KHR_DF_TRANSFER_DCIP3: + return "KHR_DF_TRANSFER_DCIP3"; + case KHR_DF_TRANSFER_PAL_OETF: + return "KHR_DF_TRANSFER_PAL_OETF"; + case KHR_DF_TRANSFER_PAL625_EOTF: + return "KHR_DF_TRANSFER_PAL625_EOTF"; + case KHR_DF_TRANSFER_ST240: + return "KHR_DF_TRANSFER_ST240"; + case KHR_DF_TRANSFER_ACESCC: + return "KHR_DF_TRANSFER_ACESCC"; + case KHR_DF_TRANSFER_ACESCCT: + return "KHR_DF_TRANSFER_ACESCCT"; + case KHR_DF_TRANSFER_ADOBERGB: + return "KHR_DF_TRANSFER_ADOBERGB"; + + case KHR_DF_TRANSFER_MAX: + // These enum values are not meant for string representation. Ignore + break; + } + return NULL; +} + +const char* dfdToStringColorPrimaries(khr_df_primaries_e value) { + switch (value) { + case KHR_DF_PRIMARIES_UNSPECIFIED: + return "KHR_DF_PRIMARIES_UNSPECIFIED"; + case KHR_DF_PRIMARIES_BT709: + // case KHR_DF_PRIMARIES_SRGB: // Fallthrough, Matching values + return "KHR_DF_PRIMARIES_BT709"; + case KHR_DF_PRIMARIES_BT601_EBU: + return "KHR_DF_PRIMARIES_BT601_EBU"; + case KHR_DF_PRIMARIES_BT601_SMPTE: + return "KHR_DF_PRIMARIES_BT601_SMPTE"; + case KHR_DF_PRIMARIES_BT2020: + return "KHR_DF_PRIMARIES_BT2020"; + case KHR_DF_PRIMARIES_CIEXYZ: + return "KHR_DF_PRIMARIES_CIEXYZ"; + case KHR_DF_PRIMARIES_ACES: + return "KHR_DF_PRIMARIES_ACES"; + case KHR_DF_PRIMARIES_ACESCC: + return "KHR_DF_PRIMARIES_ACESCC"; + case KHR_DF_PRIMARIES_NTSC1953: + return "KHR_DF_PRIMARIES_NTSC1953"; + case KHR_DF_PRIMARIES_PAL525: + return "KHR_DF_PRIMARIES_PAL525"; + case KHR_DF_PRIMARIES_DISPLAYP3: + return "KHR_DF_PRIMARIES_DISPLAYP3"; + case KHR_DF_PRIMARIES_ADOBERGB: + return "KHR_DF_PRIMARIES_ADOBERGB"; + + case KHR_DF_PRIMARIES_MAX: + // These enum values are not meant for string representation. Ignore + break; + } + return NULL; +} + +const char* dfdToStringColorModel(khr_df_model_e value) { + switch (value) { + case KHR_DF_MODEL_UNSPECIFIED: + return "KHR_DF_MODEL_UNSPECIFIED"; + case KHR_DF_MODEL_RGBSDA: + return "KHR_DF_MODEL_RGBSDA"; + case KHR_DF_MODEL_YUVSDA: + return "KHR_DF_MODEL_YUVSDA"; + case KHR_DF_MODEL_YIQSDA: + return "KHR_DF_MODEL_YIQSDA"; + case KHR_DF_MODEL_LABSDA: + return "KHR_DF_MODEL_LABSDA"; + case KHR_DF_MODEL_CMYKA: + return "KHR_DF_MODEL_CMYKA"; + case KHR_DF_MODEL_XYZW: + return "KHR_DF_MODEL_XYZW"; + case KHR_DF_MODEL_HSVA_ANG: + return "KHR_DF_MODEL_HSVA_ANG"; + case KHR_DF_MODEL_HSLA_ANG: + return "KHR_DF_MODEL_HSLA_ANG"; + case KHR_DF_MODEL_HSVA_HEX: + return "KHR_DF_MODEL_HSVA_HEX"; + case KHR_DF_MODEL_HSLA_HEX: + return "KHR_DF_MODEL_HSLA_HEX"; + case KHR_DF_MODEL_YCGCOA: + return "KHR_DF_MODEL_YCGCOA"; + case KHR_DF_MODEL_YCCBCCRC: + return "KHR_DF_MODEL_YCCBCCRC"; + case KHR_DF_MODEL_ICTCP: + return "KHR_DF_MODEL_ICTCP"; + case KHR_DF_MODEL_CIEXYZ: + return "KHR_DF_MODEL_CIEXYZ"; + case KHR_DF_MODEL_CIEXYY: + return "KHR_DF_MODEL_CIEXYY"; + case KHR_DF_MODEL_BC1A: + // case KHR_DF_MODEL_DXT1A: // Fallthrough, Matching values + return "KHR_DF_MODEL_BC1A"; + case KHR_DF_MODEL_BC2: + // case KHR_DF_MODEL_DXT2: // Fallthrough, Matching values + // case KHR_DF_MODEL_DXT3: // Fallthrough, Matching values + return "KHR_DF_MODEL_BC2"; + case KHR_DF_MODEL_BC3: + // case KHR_DF_MODEL_DXT4: // Fallthrough, Matching values + // case KHR_DF_MODEL_DXT5: // Fallthrough, Matching values + return "KHR_DF_MODEL_BC3"; + case KHR_DF_MODEL_BC4: + return "KHR_DF_MODEL_BC4"; + case KHR_DF_MODEL_BC5: + return "KHR_DF_MODEL_BC5"; + case KHR_DF_MODEL_BC6H: + return "KHR_DF_MODEL_BC6H"; + case KHR_DF_MODEL_BC7: + return "KHR_DF_MODEL_BC7"; + case KHR_DF_MODEL_ETC1: + return "KHR_DF_MODEL_ETC1"; + case KHR_DF_MODEL_ETC2: + return "KHR_DF_MODEL_ETC2"; + case KHR_DF_MODEL_ASTC: + return "KHR_DF_MODEL_ASTC"; + case KHR_DF_MODEL_ETC1S: + return "KHR_DF_MODEL_ETC1S"; + case KHR_DF_MODEL_PVRTC: + return "KHR_DF_MODEL_PVRTC"; + case KHR_DF_MODEL_PVRTC2: + return "KHR_DF_MODEL_PVRTC2"; + case KHR_DF_MODEL_UASTC: + return "KHR_DF_MODEL_UASTC"; + + case KHR_DF_MODEL_MAX: + // These enum values are not meant for string representation. Ignore + break; + } + return NULL; +} + +const char* dfdToStringSampleDatatypeQualifiers(uint32_t bit_index, bool bit_value) { + if (!bit_value) + return NULL; + + switch (1u << bit_index) { + case KHR_DF_SAMPLE_DATATYPE_LINEAR: + return "KHR_DF_SAMPLE_DATATYPE_LINEAR"; + case KHR_DF_SAMPLE_DATATYPE_EXPONENT: + return "KHR_DF_SAMPLE_DATATYPE_EXPONENT"; + case KHR_DF_SAMPLE_DATATYPE_SIGNED: + return "KHR_DF_SAMPLE_DATATYPE_SIGNED"; + case KHR_DF_SAMPLE_DATATYPE_FLOAT: + return "KHR_DF_SAMPLE_DATATYPE_FLOAT"; + } + return NULL; +} + +const char* dfdToStringChannelId(khr_df_model_e model, khr_df_model_channels_e value) { + switch (model) { + case KHR_DF_MODEL_RGBSDA: + switch (value) { + case KHR_DF_CHANNEL_RGBSDA_RED: + return "KHR_DF_CHANNEL_RGBSDA_RED"; + case KHR_DF_CHANNEL_RGBSDA_GREEN: + return "KHR_DF_CHANNEL_RGBSDA_GREEN"; + case KHR_DF_CHANNEL_RGBSDA_BLUE: + return "KHR_DF_CHANNEL_RGBSDA_BLUE"; + case KHR_DF_CHANNEL_RGBSDA_STENCIL: + return "KHR_DF_CHANNEL_RGBSDA_STENCIL"; + case KHR_DF_CHANNEL_RGBSDA_DEPTH: + return "KHR_DF_CHANNEL_RGBSDA_DEPTH"; + case KHR_DF_CHANNEL_RGBSDA_ALPHA: + return "KHR_DF_CHANNEL_RGBSDA_ALPHA"; + default: + return NULL; + } + + case KHR_DF_MODEL_YUVSDA: + switch (value) { + case KHR_DF_CHANNEL_YUVSDA_Y: + return "KHR_DF_CHANNEL_YUVSDA_Y"; + case KHR_DF_CHANNEL_YUVSDA_U: + return "KHR_DF_CHANNEL_YUVSDA_U"; + case KHR_DF_CHANNEL_YUVSDA_V: + return "KHR_DF_CHANNEL_YUVSDA_V"; + case KHR_DF_CHANNEL_YUVSDA_STENCIL: + return "KHR_DF_CHANNEL_YUVSDA_STENCIL"; + case KHR_DF_CHANNEL_YUVSDA_DEPTH: + return "KHR_DF_CHANNEL_YUVSDA_DEPTH"; + case KHR_DF_CHANNEL_YUVSDA_ALPHA: + return "KHR_DF_CHANNEL_YUVSDA_ALPHA"; + default: + return NULL; + } + + case KHR_DF_MODEL_YIQSDA: + switch (value) { + case KHR_DF_CHANNEL_YIQSDA_Y: + return "KHR_DF_CHANNEL_YIQSDA_Y"; + case KHR_DF_CHANNEL_YIQSDA_I: + return "KHR_DF_CHANNEL_YIQSDA_I"; + case KHR_DF_CHANNEL_YIQSDA_Q: + return "KHR_DF_CHANNEL_YIQSDA_Q"; + case KHR_DF_CHANNEL_YIQSDA_STENCIL: + return "KHR_DF_CHANNEL_YIQSDA_STENCIL"; + case KHR_DF_CHANNEL_YIQSDA_DEPTH: + return "KHR_DF_CHANNEL_YIQSDA_DEPTH"; + case KHR_DF_CHANNEL_YIQSDA_ALPHA: + return "KHR_DF_CHANNEL_YIQSDA_ALPHA"; + default: + return NULL; + } + + case KHR_DF_MODEL_LABSDA: + switch (value) { + case KHR_DF_CHANNEL_LABSDA_L: + return "KHR_DF_CHANNEL_LABSDA_L"; + case KHR_DF_CHANNEL_LABSDA_A: + return "KHR_DF_CHANNEL_LABSDA_A"; + case KHR_DF_CHANNEL_LABSDA_B: + return "KHR_DF_CHANNEL_LABSDA_B"; + case KHR_DF_CHANNEL_LABSDA_STENCIL: + return "KHR_DF_CHANNEL_LABSDA_STENCIL"; + case KHR_DF_CHANNEL_LABSDA_DEPTH: + return "KHR_DF_CHANNEL_LABSDA_DEPTH"; + case KHR_DF_CHANNEL_LABSDA_ALPHA: + return "KHR_DF_CHANNEL_LABSDA_ALPHA"; + default: + return NULL; + } + + case KHR_DF_MODEL_CMYKA: + switch (value) { + case KHR_DF_CHANNEL_CMYKSDA_CYAN: + return "KHR_DF_CHANNEL_CMYKSDA_CYAN"; + case KHR_DF_CHANNEL_CMYKSDA_MAGENTA: + return "KHR_DF_CHANNEL_CMYKSDA_MAGENTA"; + case KHR_DF_CHANNEL_CMYKSDA_YELLOW: + return "KHR_DF_CHANNEL_CMYKSDA_YELLOW"; + case KHR_DF_CHANNEL_CMYKSDA_BLACK: + return "KHR_DF_CHANNEL_CMYKSDA_BLACK"; + case KHR_DF_CHANNEL_CMYKSDA_ALPHA: + return "KHR_DF_CHANNEL_CMYKSDA_ALPHA"; + default: + return NULL; + } + + case KHR_DF_MODEL_XYZW: + switch (value) { + case KHR_DF_CHANNEL_XYZW_X: + return "KHR_DF_CHANNEL_XYZW_X"; + case KHR_DF_CHANNEL_XYZW_Y: + return "KHR_DF_CHANNEL_XYZW_Y"; + case KHR_DF_CHANNEL_XYZW_Z: + return "KHR_DF_CHANNEL_XYZW_Z"; + case KHR_DF_CHANNEL_XYZW_W: + return "KHR_DF_CHANNEL_XYZW_W"; + default: + return NULL; + } + + case KHR_DF_MODEL_HSVA_ANG: + switch (value) { + case KHR_DF_CHANNEL_HSVA_ANG_VALUE: + return "KHR_DF_CHANNEL_HSVA_ANG_VALUE"; + case KHR_DF_CHANNEL_HSVA_ANG_SATURATION: + return "KHR_DF_CHANNEL_HSVA_ANG_SATURATION"; + case KHR_DF_CHANNEL_HSVA_ANG_HUE: + return "KHR_DF_CHANNEL_HSVA_ANG_HUE"; + case KHR_DF_CHANNEL_HSVA_ANG_ALPHA: + return "KHR_DF_CHANNEL_HSVA_ANG_ALPHA"; + default: + return NULL; + } + + case KHR_DF_MODEL_HSLA_ANG: + switch (value) { + case KHR_DF_CHANNEL_HSLA_ANG_LIGHTNESS: + return "KHR_DF_CHANNEL_HSLA_ANG_LIGHTNESS"; + case KHR_DF_CHANNEL_HSLA_ANG_SATURATION: + return "KHR_DF_CHANNEL_HSLA_ANG_SATURATION"; + case KHR_DF_CHANNEL_HSLA_ANG_HUE: + return "KHR_DF_CHANNEL_HSLA_ANG_HUE"; + case KHR_DF_CHANNEL_HSLA_ANG_ALPHA: + return "KHR_DF_CHANNEL_HSLA_ANG_ALPHA"; + default: + return NULL; + } + + case KHR_DF_MODEL_HSVA_HEX: + switch (value) { + case KHR_DF_CHANNEL_HSVA_HEX_VALUE: + return "KHR_DF_CHANNEL_HSVA_HEX_VALUE"; + case KHR_DF_CHANNEL_HSVA_HEX_SATURATION: + return "KHR_DF_CHANNEL_HSVA_HEX_SATURATION"; + case KHR_DF_CHANNEL_HSVA_HEX_HUE: + return "KHR_DF_CHANNEL_HSVA_HEX_HUE"; + case KHR_DF_CHANNEL_HSVA_HEX_ALPHA: + return "KHR_DF_CHANNEL_HSVA_HEX_ALPHA"; + default: + return NULL; + } + + case KHR_DF_MODEL_HSLA_HEX: + switch (value) { + case KHR_DF_CHANNEL_HSLA_HEX_LIGHTNESS: + return "KHR_DF_CHANNEL_HSLA_HEX_LIGHTNESS"; + case KHR_DF_CHANNEL_HSLA_HEX_SATURATION: + return "KHR_DF_CHANNEL_HSLA_HEX_SATURATION"; + case KHR_DF_CHANNEL_HSLA_HEX_HUE: + return "KHR_DF_CHANNEL_HSLA_HEX_HUE"; + case KHR_DF_CHANNEL_HSLA_HEX_ALPHA: + return "KHR_DF_CHANNEL_HSLA_HEX_ALPHA"; + default: + return NULL; + } + + case KHR_DF_MODEL_YCGCOA: + switch (value) { + case KHR_DF_CHANNEL_YCGCOA_Y: + return "KHR_DF_CHANNEL_YCGCOA_Y"; + case KHR_DF_CHANNEL_YCGCOA_CG: + return "KHR_DF_CHANNEL_YCGCOA_CG"; + case KHR_DF_CHANNEL_YCGCOA_CO: + return "KHR_DF_CHANNEL_YCGCOA_CO"; + case KHR_DF_CHANNEL_YCGCOA_ALPHA: + return "KHR_DF_CHANNEL_YCGCOA_ALPHA"; + default: + return NULL; + } + + case KHR_DF_MODEL_CIEXYZ: + switch (value) { + case KHR_DF_CHANNEL_CIEXYZ_X: + return "KHR_DF_CHANNEL_CIEXYZ_X"; + case KHR_DF_CHANNEL_CIEXYZ_Y: + return "KHR_DF_CHANNEL_CIEXYZ_Y"; + case KHR_DF_CHANNEL_CIEXYZ_Z: + return "KHR_DF_CHANNEL_CIEXYZ_Z"; + default: + return NULL; + } + + case KHR_DF_MODEL_CIEXYY: + switch (value) { + case KHR_DF_CHANNEL_CIEXYY_X: + return "KHR_DF_CHANNEL_CIEXYY_X"; + case KHR_DF_CHANNEL_CIEXYY_YCHROMA: + return "KHR_DF_CHANNEL_CIEXYY_YCHROMA"; + case KHR_DF_CHANNEL_CIEXYY_YLUMA: + return "KHR_DF_CHANNEL_CIEXYY_YLUMA"; + default: + return NULL; + } + + case KHR_DF_MODEL_BC1A: + switch (value) { + case KHR_DF_CHANNEL_BC1A_COLOR: + return "KHR_DF_CHANNEL_BC1A_COLOR"; + case KHR_DF_CHANNEL_BC1A_ALPHA: + return "KHR_DF_CHANNEL_BC1A_ALPHA"; + default: + return NULL; + } + + case KHR_DF_MODEL_BC2: + switch (value) { + case KHR_DF_CHANNEL_BC2_COLOR: + return "KHR_DF_CHANNEL_BC2_COLOR"; + case KHR_DF_CHANNEL_BC2_ALPHA: + return "KHR_DF_CHANNEL_BC2_ALPHA"; + default: + return NULL; + } + + case KHR_DF_MODEL_BC3: + switch (value) { + case KHR_DF_CHANNEL_BC3_COLOR: + return "KHR_DF_CHANNEL_BC3_COLOR"; + case KHR_DF_CHANNEL_BC3_ALPHA: + return "KHR_DF_CHANNEL_BC3_ALPHA"; + default: + return NULL; + } + + case KHR_DF_MODEL_BC4: + switch (value) { + case KHR_DF_CHANNEL_BC4_DATA: + return "KHR_DF_CHANNEL_BC4_DATA"; + default: + return NULL; + } + + case KHR_DF_MODEL_BC5: + switch (value) { + case KHR_DF_CHANNEL_BC5_RED: + return "KHR_DF_CHANNEL_BC5_RED"; + case KHR_DF_CHANNEL_BC5_GREEN: + return "KHR_DF_CHANNEL_BC5_GREEN"; + default: + return NULL; + } + + case KHR_DF_MODEL_BC6H: + switch (value) { + case KHR_DF_CHANNEL_BC6H_COLOR: + return "KHR_DF_CHANNEL_BC6H_COLOR"; + default: + return NULL; + } + + case KHR_DF_MODEL_BC7: + switch (value) { + case KHR_DF_CHANNEL_BC7_COLOR: + return "KHR_DF_CHANNEL_BC7_COLOR"; + default: + return NULL; + } + + case KHR_DF_MODEL_ETC1: + switch (value) { + case KHR_DF_CHANNEL_ETC1_COLOR: + return "KHR_DF_CHANNEL_ETC1_COLOR"; + default: + return NULL; + } + + case KHR_DF_MODEL_ETC2: + switch (value) { + case KHR_DF_CHANNEL_ETC2_RED: + return "KHR_DF_CHANNEL_ETC2_RED"; + case KHR_DF_CHANNEL_ETC2_GREEN: + return "KHR_DF_CHANNEL_ETC2_GREEN"; + case KHR_DF_CHANNEL_ETC2_COLOR: + return "KHR_DF_CHANNEL_ETC2_COLOR"; + case KHR_DF_CHANNEL_ETC2_ALPHA: + return "KHR_DF_CHANNEL_ETC2_ALPHA"; + default: + return NULL; + } + + case KHR_DF_MODEL_ASTC: + switch (value) { + case KHR_DF_CHANNEL_ASTC_DATA: + return "KHR_DF_CHANNEL_ASTC_DATA"; + default: + return NULL; + } + + case KHR_DF_MODEL_ETC1S: + switch (value) { + case KHR_DF_CHANNEL_ETC1S_RGB: + return "KHR_DF_CHANNEL_ETC1S_RGB"; + case KHR_DF_CHANNEL_ETC1S_RRR: + return "KHR_DF_CHANNEL_ETC1S_RRR"; + case KHR_DF_CHANNEL_ETC1S_GGG: + return "KHR_DF_CHANNEL_ETC1S_GGG"; + case KHR_DF_CHANNEL_ETC1S_AAA: + return "KHR_DF_CHANNEL_ETC1S_AAA"; + default: + return NULL; + } + + case KHR_DF_MODEL_PVRTC: + switch (value) { + case KHR_DF_CHANNEL_PVRTC_COLOR: + return "KHR_DF_CHANNEL_PVRTC_COLOR"; + default: + return NULL; + } + + case KHR_DF_MODEL_PVRTC2: + switch (value) { + case KHR_DF_CHANNEL_PVRTC2_COLOR: + return "KHR_DF_CHANNEL_PVRTC2_COLOR"; + default: + return NULL; + } + + case KHR_DF_MODEL_UASTC: + switch (value) { + case KHR_DF_CHANNEL_UASTC_RGB: + return "KHR_DF_CHANNEL_UASTC_RGB"; + case KHR_DF_CHANNEL_UASTC_RGBA: + return "KHR_DF_CHANNEL_UASTC_RGBA"; + case KHR_DF_CHANNEL_UASTC_RRR: + return "KHR_DF_CHANNEL_UASTC_RRR"; + case KHR_DF_CHANNEL_UASTC_RRRG: + return "KHR_DF_CHANNEL_UASTC_RRRG"; + case KHR_DF_CHANNEL_UASTC_RG: + return "KHR_DF_CHANNEL_UASTC_RG"; + default: + return NULL; + } + + default: + break; + } + + switch (value) { + case KHR_DF_CHANNEL_UNSPECIFIED_0: + return "KHR_DF_CHANNEL_UNSPECIFIED_0"; + case KHR_DF_CHANNEL_UNSPECIFIED_1: + return "KHR_DF_CHANNEL_UNSPECIFIED_1"; + case KHR_DF_CHANNEL_UNSPECIFIED_2: + return "KHR_DF_CHANNEL_UNSPECIFIED_2"; + case KHR_DF_CHANNEL_UNSPECIFIED_3: + return "KHR_DF_CHANNEL_UNSPECIFIED_3"; + case KHR_DF_CHANNEL_UNSPECIFIED_4: + return "KHR_DF_CHANNEL_UNSPECIFIED_4"; + case KHR_DF_CHANNEL_UNSPECIFIED_5: + return "KHR_DF_CHANNEL_UNSPECIFIED_5"; + case KHR_DF_CHANNEL_UNSPECIFIED_6: + return "KHR_DF_CHANNEL_UNSPECIFIED_6"; + case KHR_DF_CHANNEL_UNSPECIFIED_7: + return "KHR_DF_CHANNEL_UNSPECIFIED_7"; + case KHR_DF_CHANNEL_UNSPECIFIED_8: + return "KHR_DF_CHANNEL_UNSPECIFIED_8"; + case KHR_DF_CHANNEL_UNSPECIFIED_9: + return "KHR_DF_CHANNEL_UNSPECIFIED_9"; + case KHR_DF_CHANNEL_UNSPECIFIED_10: + return "KHR_DF_CHANNEL_UNSPECIFIED_10"; + case KHR_DF_CHANNEL_UNSPECIFIED_11: + return "KHR_DF_CHANNEL_UNSPECIFIED_11"; + case KHR_DF_CHANNEL_UNSPECIFIED_12: + return "KHR_DF_CHANNEL_UNSPECIFIED_12"; + case KHR_DF_CHANNEL_UNSPECIFIED_13: + return "KHR_DF_CHANNEL_UNSPECIFIED_13"; + case KHR_DF_CHANNEL_UNSPECIFIED_14: + return "KHR_DF_CHANNEL_UNSPECIFIED_14"; + case KHR_DF_CHANNEL_UNSPECIFIED_15: + return "KHR_DF_CHANNEL_UNSPECIFIED_15"; + default: + break; + } + + return NULL; +} + +/** + * @internal + */ +static void printFlagBits(uint32_t flags, const char*(*toStringFn)(uint32_t, bool)) { + bool first = true; + for (uint32_t bit_index = 0; bit_index < 32; ++bit_index) { + uint32_t bit_mask = 1u << bit_index; + bool bit_value = (bit_mask & (uint32_t) flags) != 0; + + const char* comma = first ? "" : ", "; + const char* str = toStringFn(bit_index, bit_value); + if (str) { + printf("%s%s", comma, str); + first = false; + } else if (bit_value) { + printf("%s%u", comma, bit_mask); + first = false; + } + } +} + +/** + * @internal + */ +static void printFlagBitsJSON(uint32_t indent, const char* nl, uint32_t flags, const char*(*toStringFn)(uint32_t, bool)) { + bool first = true; + for (uint32_t bit_index = 0; bit_index < 32; ++bit_index) { + uint32_t bit_mask = 1u << bit_index; + bool bit_value = (bit_mask & (uint32_t) flags) != 0; + + const char* str = toStringFn(bit_index, bit_value); + if (str) { + printf("%s%s%*s\"%s\"", first ? "" : ",", first ? "" : nl, indent, "", str); + first = false; + } else if (bit_value) { + printf("%s%s%*s%u", first ? "" : ",", first ? "" : nl, indent, "", bit_mask); + first = false; + } + } + if (!first) + printf("%s", nl); +} + /** * @~English * @brief Print a human-readable interpretation of a data format descriptor. * * @param DFD Pointer to a data format descriptor. + * @param dataSize The maximum size that can be considered as part of the DFD. **/ -void printDFD(uint32_t *DFD) +void printDFD(uint32_t *DFD, uint32_t dataSize) { - 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)); +#define PRINT_ENUM(VALUE, TO_STRING_FN) { \ + int value = VALUE; \ + const char* str = TO_STRING_FN(value); \ + if (str) \ + printf("%s", str); \ + else \ + printf("%u", value); \ } + + const uint32_t sizeof_dfdTotalSize = sizeof(uint32_t); + const uint32_t sizeof_DFDBHeader = sizeof(uint32_t) * 2; + const uint32_t sizeof_BDFD = sizeof(uint32_t) * KHR_DF_WORD_SAMPLESTART; + const uint32_t sizeof_BDFDSample = sizeof(uint32_t) * KHR_DF_WORD_SAMPLEWORDS; + + uint32_t dfdTotalSize = dataSize >= sizeof_dfdTotalSize ? DFD[0] : 0; + uint32_t remainingSize = dfdTotalSize < dataSize ? dfdTotalSize : dataSize; + if (remainingSize < sizeof_dfdTotalSize) + return; // Invalid DFD: dfdTotalSize must be present + + uint32_t* block = DFD + 1; + remainingSize -= sizeof_dfdTotalSize; + + printf("DFD total bytes: %u\n", dfdTotalSize); + + for (int i = 0; i < MAX_NUM_DFD_BLOCKS; ++i) { // At most only iterate MAX_NUM_DFD_BLOCKS block + if (remainingSize < sizeof_DFDBHeader) + break; // Invalid DFD: Missing or partial block header + + const khr_df_vendorid_e vendorID = KHR_DFDVAL(block, VENDORID); + const khr_df_khr_descriptortype_e descriptorType = KHR_DFDVAL(block, DESCRIPTORTYPE); + const khr_df_versionnumber_e versionNumber = KHR_DFDVAL(block, VERSIONNUMBER); + const uint32_t blockSize = KHR_DFDVAL(block, DESCRIPTORBLOCKSIZE); + + printf("Vendor ID: "); + PRINT_ENUM(vendorID, dfdToStringVendorID); + printf("\nDescriptor type: "); + PRINT_ENUM(descriptorType, dfdToStringDescriptorType); + printf("\nVersion: "); + PRINT_ENUM(versionNumber, dfdToStringVersionNumber); + printf("\nDescriptor block size: %u", blockSize); + printf("\n"); + + if (vendorID == KHR_DF_VENDORID_KHRONOS && descriptorType == KHR_DF_KHR_DESCRIPTORTYPE_BASICFORMAT) { + if (remainingSize < sizeof_BDFD) + break; // Invalid DFD: Missing or partial basic DFD block + + const int model = KHR_DFDVAL(block, MODEL); + + khr_df_flags_e flags = KHR_DFDVAL(block, FLAGS); + printf("Flags: 0x%X (", flags); + printFlagBits(flags, dfdToStringFlagsBit); + printf(")\nTransfer: "); + PRINT_ENUM(KHR_DFDVAL(block, TRANSFER), dfdToStringTransferFunction); + printf("\nPrimaries: "); + PRINT_ENUM(KHR_DFDVAL(block, PRIMARIES), dfdToStringColorPrimaries); + printf("\nModel: "); + PRINT_ENUM(model, dfdToStringColorModel); + printf("\n"); + + printf("Dimensions: %u, %u, %u, %u\n", + KHR_DFDVAL(block, TEXELBLOCKDIMENSION0) + 1, + KHR_DFDVAL(block, TEXELBLOCKDIMENSION1) + 1, + KHR_DFDVAL(block, TEXELBLOCKDIMENSION2) + 1, + KHR_DFDVAL(block, TEXELBLOCKDIMENSION3) + 1); + printf("Plane bytes: %u, %u, %u, %u, %u, %u, %u, %u\n", + KHR_DFDVAL(block, BYTESPLANE0), + KHR_DFDVAL(block, BYTESPLANE1), + KHR_DFDVAL(block, BYTESPLANE2), + KHR_DFDVAL(block, BYTESPLANE3), + KHR_DFDVAL(block, BYTESPLANE4), + KHR_DFDVAL(block, BYTESPLANE5), + KHR_DFDVAL(block, BYTESPLANE6), + KHR_DFDVAL(block, BYTESPLANE7)); + + int samples = (blockSize - sizeof_BDFD) / sizeof_BDFDSample; + if (samples > MAX_NUM_BDFD_SAMPLES) + samples = MAX_NUM_BDFD_SAMPLES; // Too many BDFD samples + for (int sample = 0; sample < samples; ++sample) { + if (remainingSize < sizeof_BDFD + (sample + 1) * sizeof_BDFDSample) + break; // Invalid DFD: Missing or partial basic DFD sample + + khr_df_model_channels_e channelType = KHR_DFDSVAL(block, sample, CHANNELID); + printf("Sample %u:\n", sample); + + khr_df_sample_datatype_qualifiers_e qualifiers = KHR_DFDSVAL(block, sample, QUALIFIERS); + printf(" Qualifiers: 0x%X (", qualifiers); + printFlagBits(qualifiers, dfdToStringSampleDatatypeQualifiers); + printf(")\n"); + printf(" Channel Type: 0x%X", channelType); + { + const char* str = dfdToStringChannelId(model, channelType); + if (str) + printf(" (%s)\n", str); + else + printf(" (%u)\n", channelType); + } + printf(" Length: %u bits Offset: %u\n", + KHR_DFDSVAL(block, sample, BITLENGTH) + 1, + KHR_DFDSVAL(block, sample, BITOFFSET)); + printf(" Position: %u, %u, %u, %u\n", + KHR_DFDSVAL(block, sample, SAMPLEPOSITION0), + KHR_DFDSVAL(block, sample, SAMPLEPOSITION1), + KHR_DFDSVAL(block, sample, SAMPLEPOSITION2), + KHR_DFDSVAL(block, sample, SAMPLEPOSITION3)); + printf(" Lower: 0x%08x\n Upper: 0x%08x\n", + KHR_DFDSVAL(block, sample, SAMPLELOWER), + KHR_DFDSVAL(block, sample, SAMPLEUPPER)); + } + } else if (vendorID == KHR_DF_VENDORID_KHRONOS && descriptorType == KHR_DF_KHR_DESCRIPTORTYPE_ADDITIONAL_DIMENSIONS) { + // TODO: Implement DFD print for ADDITIONAL_DIMENSIONS + } else if (vendorID == KHR_DF_VENDORID_KHRONOS && descriptorType == KHR_DF_KHR_DESCRIPTORTYPE_ADDITIONAL_PLANES) { + // TODO: Implement DFD print for ADDITIONAL_PLANES + } else { + printf("Unknown block\n"); + } + + const uint32_t advance = sizeof_DFDBHeader > blockSize ? sizeof_DFDBHeader : blockSize; + if (advance > remainingSize) + break; + remainingSize -= advance; + block += advance / 4; + } +#undef PRINT_ENUM +} + +/** + * @~English + * @brief Print a JSON interpretation of a data format descriptor. + * + * @param DFD Pointer to a data format descriptor. + * @param dataSize The maximum size that can be considered as part of the DFD. + * @param base_indent The number of indentations to include at the front of every line + * @param indent_width The number of spaces to add with each nested scope + * @param minified Specifies whether the JSON output should be minified + **/ +void printDFDJSON(uint32_t* DFD, uint32_t dataSize, uint32_t base_indent, uint32_t indent_width, bool minified) +{ + if (minified) { + base_indent = 0; + indent_width = 0; + } + const char* space = minified ? "" : " "; + const char* nl = minified ? "" : "\n"; + +#define LENGTH_OF_INDENT(INDENT) ((base_indent + INDENT) * indent_width) + +/** Prints an enum as string or number */ +#define PRINT_ENUM(INDENT, NAME, VALUE, TO_STRING_FN, COMMA) { \ + int value = VALUE; \ + printf("%*s\"" NAME "\":%s", LENGTH_OF_INDENT(INDENT), "", space); \ + const char* str = TO_STRING_FN(value); \ + if (str) \ + printf("\"%s\"", str); \ + else \ + printf("%u", value); \ + printf(COMMA "%s", nl); \ + } + +/** Prints an enum as string or number if the to string function fails with a trailing comma*/ +#define PRINT_ENUM_C(INDENT, NAME, VALUE, TO_STRING_FN) \ + PRINT_ENUM(INDENT, NAME, VALUE, TO_STRING_FN, ",") + +/** Prints an enum as string or number if the to string function fails without a trailing comma*/ +#define PRINT_ENUM_E(INDENT, NAME, VALUE, TO_STRING_FN) \ + PRINT_ENUM(INDENT, NAME, VALUE, TO_STRING_FN, "") + +#define PRINT_INDENT(INDENT, FMT, ...) { \ + printf("%*s" FMT, LENGTH_OF_INDENT(INDENT), "", __VA_ARGS__); \ + } + +#define PRINT_INDENT_NOARG(INDENT, FMT) { \ + printf("%*s" FMT, LENGTH_OF_INDENT(INDENT), ""); \ + } + + const uint32_t sizeof_dfdTotalSize = sizeof(uint32_t); + const uint32_t sizeof_DFDBHeader = sizeof(uint32_t) * 2; + const uint32_t sizeof_BDFD = sizeof(uint32_t) * KHR_DF_WORD_SAMPLESTART; + const uint32_t sizeof_BDFDSample = sizeof(uint32_t) * KHR_DF_WORD_SAMPLEWORDS; + + uint32_t dfdTotalSize = dataSize >= sizeof_dfdTotalSize ? DFD[0] : 0; + PRINT_INDENT(0, "\"totalSize\":%s%u,%s", space, dfdTotalSize, nl) + + uint32_t remainingSize = dfdTotalSize < dataSize ? dfdTotalSize : dataSize; + if (remainingSize < sizeof_dfdTotalSize) { + PRINT_INDENT(0, "\"blocks\":%s[]%s", space, nl) // Print empty blocks to confirm to the json scheme + return; // Invalid DFD: dfdTotalSize must be present + } + + uint32_t* block = DFD + 1; + remainingSize -= sizeof_dfdTotalSize; + PRINT_INDENT(0, "\"blocks\":%s[", space) + + for (int i = 0; i < MAX_NUM_DFD_BLOCKS; ++i) { // At most only iterate MAX_NUM_DFD_BLOCKS block + if (remainingSize < sizeof_DFDBHeader) + break; // Invalid DFD: Missing or partial block header + + const khr_df_vendorid_e vendorID = KHR_DFDVAL(block, VENDORID); + const khr_df_khr_descriptortype_e descriptorType = KHR_DFDVAL(block, DESCRIPTORTYPE); + const khr_df_versionnumber_e versionNumber = KHR_DFDVAL(block, VERSIONNUMBER); + const uint32_t blockSize = KHR_DFDVAL(block, DESCRIPTORBLOCKSIZE); + + const int model = KHR_DFDVAL(block, MODEL); + + if (i == 0) { + printf("%s", nl); + } else { + printf(",%s", nl); + } + PRINT_INDENT(1, "{%s", nl) + PRINT_ENUM_C(2, "vendorId", vendorID, dfdToStringVendorID); + PRINT_ENUM_C(2, "descriptorType", descriptorType, dfdToStringDescriptorType); + PRINT_ENUM_C(2, "versionNumber", versionNumber, dfdToStringVersionNumber); + PRINT_INDENT(2, "\"descriptorBlockSize\":%s%u", space, blockSize) + + if (vendorID == KHR_DF_VENDORID_KHRONOS && descriptorType == KHR_DF_KHR_DESCRIPTORTYPE_BASICFORMAT) { + if (remainingSize < sizeof_BDFD) { + // Invalid DFD: Missing or partial basic DFD block + printf("%s", nl); + PRINT_INDENT(1, "}%s", nl) // End of block + break; + } + + printf(",%s", nl); + PRINT_INDENT(2, "\"flags\":%s[%s", space, nl) + khr_df_flags_e flags = KHR_DFDVAL(block, FLAGS); + printFlagBitsJSON(LENGTH_OF_INDENT(3), nl, flags, dfdToStringFlagsBit); + PRINT_INDENT(2, "],%s", nl) + + PRINT_ENUM_C(2, "transferFunction", KHR_DFDVAL(block, TRANSFER), dfdToStringTransferFunction); + PRINT_ENUM_C(2, "colorPrimaries", KHR_DFDVAL(block, PRIMARIES), dfdToStringColorPrimaries); + PRINT_ENUM_C(2, "colorModel", model, dfdToStringColorModel); + PRINT_INDENT(2, "\"texelBlockDimension\":%s[%u,%s%u,%s%u,%s%u],%s", space, + KHR_DFDVAL(block, TEXELBLOCKDIMENSION0) + 1, space, + KHR_DFDVAL(block, TEXELBLOCKDIMENSION1) + 1, space, + KHR_DFDVAL(block, TEXELBLOCKDIMENSION2) + 1, space, + KHR_DFDVAL(block, TEXELBLOCKDIMENSION3) + 1, nl) + PRINT_INDENT(2, "\"bytesPlane\":%s[%u,%s%u,%s%u,%s%u,%s%u,%s%u,%s%u,%s%u],%s", space, + KHR_DFDVAL(block, BYTESPLANE0), space, + KHR_DFDVAL(block, BYTESPLANE1), space, + KHR_DFDVAL(block, BYTESPLANE2), space, + KHR_DFDVAL(block, BYTESPLANE3), space, + KHR_DFDVAL(block, BYTESPLANE4), space, + KHR_DFDVAL(block, BYTESPLANE5), space, + KHR_DFDVAL(block, BYTESPLANE6), space, + KHR_DFDVAL(block, BYTESPLANE7), nl) + + PRINT_INDENT(2, "\"samples\":%s[%s", space, nl) + int samples = (blockSize - sizeof_BDFD) / sizeof_BDFDSample; + if (samples > MAX_NUM_BDFD_SAMPLES) + samples = MAX_NUM_BDFD_SAMPLES; + for (int sample = 0; sample < samples; ++sample) { + if (remainingSize < sizeof_BDFD + (sample + 1) * sizeof_BDFDSample) + break; // Invalid DFD: Missing or partial basic DFD sample + + if (sample != 0) + printf(",%s", nl); + PRINT_INDENT(3, "{%s", nl) + + khr_df_sample_datatype_qualifiers_e qualifiers = KHR_DFDSVAL(block, sample, QUALIFIERS); + if (qualifiers == 0) { + PRINT_INDENT(4, "\"qualifiers\":%s[],%s", space, nl) + + } else { + PRINT_INDENT(4, "\"qualifiers\":%s[%s", space, nl) + printFlagBitsJSON(LENGTH_OF_INDENT(5), nl, qualifiers, dfdToStringSampleDatatypeQualifiers); + PRINT_INDENT(4, "],%s", nl) + } + + khr_df_model_channels_e channelType = KHR_DFDSVAL(block, sample, CHANNELID); + const char* channelStr = dfdToStringChannelId(model, channelType); + if (channelStr) + PRINT_INDENT(4, "\"channelType\":%s\"%s\",%s", space, channelStr, nl) + else + PRINT_INDENT(4, "\"channelType\":%s%u,%s", space, channelType, nl) + + PRINT_INDENT(4, "\"bitLength\":%s%u,%s", space, KHR_DFDSVAL(block, sample, BITLENGTH), nl) + PRINT_INDENT(4, "\"bitOffset\":%s%u,%s", space, KHR_DFDSVAL(block, sample, BITOFFSET), nl) + PRINT_INDENT(4, "\"samplePosition\":%s[%u,%s%u,%s%u,%s%u],%s", space, + KHR_DFDSVAL(block, sample, SAMPLEPOSITION0), space, + KHR_DFDSVAL(block, sample, SAMPLEPOSITION1), space, + KHR_DFDSVAL(block, sample, SAMPLEPOSITION2), space, + KHR_DFDSVAL(block, sample, SAMPLEPOSITION3), nl) + + if (qualifiers & KHR_DF_SAMPLE_DATATYPE_SIGNED) { + PRINT_INDENT(4, "\"sampleLower\":%s%d,%s", space, KHR_DFDSVAL(block, sample, SAMPLELOWER), nl) + PRINT_INDENT(4, "\"sampleUpper\":%s%d%s", space, KHR_DFDSVAL(block, sample, SAMPLEUPPER), nl) + } else { + PRINT_INDENT(4, "\"sampleLower\":%s%u,%s", space, (unsigned int) KHR_DFDSVAL(block, sample, SAMPLELOWER), nl) + PRINT_INDENT(4, "\"sampleUpper\":%s%u%s", space, (unsigned int) KHR_DFDSVAL(block, sample, SAMPLEUPPER), nl) + } + + PRINT_INDENT_NOARG(3, "}") + } + printf("%s", nl); + PRINT_INDENT(2, "]%s", nl) // End of samples + } else if (vendorID == KHR_DF_VENDORID_KHRONOS && descriptorType == KHR_DF_KHR_DESCRIPTORTYPE_ADDITIONAL_DIMENSIONS) { + printf("%s", nl); + // printf(",%s", nl); // If there is extra member printed + // TODO: Implement DFD print for ADDITIONAL_DIMENSIONS + } else if (vendorID == KHR_DF_VENDORID_KHRONOS && descriptorType == KHR_DF_KHR_DESCRIPTORTYPE_ADDITIONAL_PLANES) { + printf("%s", nl); + // printf(",%s", nl); // If there is extra member printed + // TODO: Implement DFD print for ADDITIONAL_PLANES + } else { + printf("%s", nl); + // printf(",%s", nl); // If there is extra member printed + // TODO: What to do with unknown blocks for json? + // Unknown block data in binary? + } + + PRINT_INDENT_NOARG(1, "}") // End of block + + const uint32_t advance = sizeof_DFDBHeader > blockSize ? sizeof_DFDBHeader : blockSize; + if (advance > remainingSize) + break; + remainingSize -= advance; + block += advance / 4; + } + printf("%s", nl); + PRINT_INDENT(0, "]%s", nl) // End of blocks + +#undef PRINT_ENUM +#undef PRINT_ENUM_C +#undef PRINT_ENUM_E +#undef PRINT_INDENT +#undef PRINT_INDENT_NOARG } diff --git a/thirdparty/libktx/lib/dfdutils/vk2dfd.inl b/thirdparty/libktx/lib/dfdutils/vk2dfd.inl index 4ae1e6d5e1d..25c7a2c238f 100644 --- a/thirdparty/libktx/lib/dfdutils/vk2dfd.inl +++ b/thirdparty/libktx/lib/dfdutils/vk2dfd.inl @@ -5,9 +5,6 @@ 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); @@ -222,6 +219,9 @@ 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_D16_UNORM_S8_UINT: return createDFDDepthStencil(16,8,4); +case VK_FORMAT_D24_UNORM_S8_UINT: return createDFDDepthStencil(24,8,4); +case VK_FORMAT_D32_SFLOAT_S8_UINT: return createDFDDepthStencil(32,8,8); 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); @@ -276,6 +276,92 @@ case VK_FORMAT_ASTC_12x10_UNORM_BLOCK: return createDFDCompressed(c_ASTC, 12, 10 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_G8B8G8R8_422_UNORM: { + int channels[] = {0, 1, 0, 2}; int bits[] = {8, 8, 8, 8}; int paddings[] = {0, 0, 0, 0}; + int position_xs[] = {64, 64, 192, 64}; int position_ys[] = {128, 128, 128, 128}; + return createDFD422(0, 4, bits, paddings, channels, position_xs, position_ys, s_UNORM); +} +case VK_FORMAT_B8G8R8G8_422_UNORM: { + int channels[] = {1, 0, 2, 0}; int bits[] = {8, 8, 8, 8}; int paddings[] = {0, 0, 0, 0}; + int position_xs[] = {64, 64, 64, 192}; int position_ys[] = {128, 128, 128, 128}; + return createDFD422(0, 4, bits, paddings, channels, position_xs, position_ys, s_UNORM); +} +case VK_FORMAT_R10X6_UNORM_PACK16: { + int channels[] = {0}; int bits[] = {10}; int paddings[] = {6}; + return createDFDPackedPadded(0, 1, bits, paddings, channels, s_UNORM); +} +case VK_FORMAT_R10X6G10X6_UNORM_2PACK16: { + int channels[] = {0, 1}; int bits[] = {10, 10}; int paddings[] = {6, 6}; + return createDFDPackedPadded(0, 2, bits, paddings, channels, s_UNORM); +} +case VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16: { + int channels[] = {0, 1, 2, 3}; int bits[] = {10, 10, 10, 10}; int paddings[] = {6, 6, 6, 6}; + return createDFDPackedPadded(0, 4, bits, paddings, channels, s_UNORM); +} +case VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16: { + int channels[] = {0, 1, 0, 2}; int bits[] = {10, 10, 10, 10}; int paddings[] = {6, 6, 6, 6}; + int position_xs[] = {64, 64, 192, 64}; int position_ys[] = {128, 128, 128, 128}; + return createDFD422(0, 4, bits, paddings, channels, position_xs, position_ys, s_UNORM); +} +case VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16: { + int channels[] = {1, 0, 2, 0}; int bits[] = {10, 10, 10, 10}; int paddings[] = {6, 6, 6, 6}; + int position_xs[] = {64, 64, 64, 192}; int position_ys[] = {128, 128, 128, 128}; + return createDFD422(0, 4, bits, paddings, channels, position_xs, position_ys, s_UNORM); +} +case VK_FORMAT_R12X4_UNORM_PACK16: { + int channels[] = {0}; int bits[] = {12}; int paddings[] = {4}; + return createDFDPackedPadded(0, 1, bits, paddings, channels, s_UNORM); +} +case VK_FORMAT_R12X4G12X4_UNORM_2PACK16: { + int channels[] = {0, 1}; int bits[] = {12, 12}; int paddings[] = {4, 4}; + return createDFDPackedPadded(0, 2, bits, paddings, channels, s_UNORM); +} +case VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16: { + int channels[] = {0, 1, 2, 3}; int bits[] = {12, 12, 12, 12}; int paddings[] = {4, 4, 4, 4}; + return createDFDPackedPadded(0, 4, bits, paddings, channels, s_UNORM); +} +case VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16: { + int channels[] = {0, 1, 0, 2}; int bits[] = {12, 12, 12, 12}; int paddings[] = {4, 4, 4, 4}; + int position_xs[] = {64, 64, 192, 64}; int position_ys[] = {128, 128, 128, 128}; + return createDFD422(0, 4, bits, paddings, channels, position_xs, position_ys, s_UNORM); +} +case VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16: { + int channels[] = {1, 0, 2, 0}; int bits[] = {12, 12, 12, 12}; int paddings[] = {4, 4, 4, 4}; + int position_xs[] = {64, 64, 64, 192}; int position_ys[] = {128, 128, 128, 128}; + return createDFD422(0, 4, bits, paddings, channels, position_xs, position_ys, s_UNORM); +} +case VK_FORMAT_G16B16G16R16_422_UNORM: { + int channels[] = {0, 1, 0, 2}; int bits[] = {16, 16, 16, 16}; int paddings[] = {0, 0, 0, 0}; + int position_xs[] = {64, 64, 192, 64}; int position_ys[] = {128, 128, 128, 128}; + return createDFD422(0, 4, bits, paddings, channels, position_xs, position_ys, s_UNORM); +} +case VK_FORMAT_B16G16R16G16_422_UNORM: { + int channels[] = {1, 0, 2, 0}; int bits[] = {16, 16, 16, 16}; int paddings[] = {0, 0, 0, 0}; + int position_xs[] = {64, 64, 64, 192}; int position_ys[] = {128, 128, 128, 128}; + return createDFD422(0, 4, bits, paddings, channels, position_xs, position_ys, s_UNORM); +} +case VK_FORMAT_A4R4G4B4_UNORM_PACK16: { + 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: { + int channels[] = {0,1,2,3}; int bits[] = {4,4,4,4}; + return createDFDPacked(0, 4, bits, channels, s_UNORM); +} +case VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK: return createDFDCompressed(c_ASTC, 4, 4, 1, s_SFLOAT); +case VK_FORMAT_ASTC_5x4_SFLOAT_BLOCK: return createDFDCompressed(c_ASTC, 5, 4, 1, s_SFLOAT); +case VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK: return createDFDCompressed(c_ASTC, 5, 5, 1, s_SFLOAT); +case VK_FORMAT_ASTC_6x5_SFLOAT_BLOCK: return createDFDCompressed(c_ASTC, 6, 5, 1, s_SFLOAT); +case VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK: return createDFDCompressed(c_ASTC, 6, 6, 1, s_SFLOAT); +case VK_FORMAT_ASTC_8x5_SFLOAT_BLOCK: return createDFDCompressed(c_ASTC, 8, 5, 1, s_SFLOAT); +case VK_FORMAT_ASTC_8x6_SFLOAT_BLOCK: return createDFDCompressed(c_ASTC, 8, 6, 1, s_SFLOAT); +case VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK: return createDFDCompressed(c_ASTC, 8, 8, 1, s_SFLOAT); +case VK_FORMAT_ASTC_10x5_SFLOAT_BLOCK: return createDFDCompressed(c_ASTC, 10, 5, 1, s_SFLOAT); +case VK_FORMAT_ASTC_10x6_SFLOAT_BLOCK: return createDFDCompressed(c_ASTC, 10, 6, 1, s_SFLOAT); +case VK_FORMAT_ASTC_10x8_SFLOAT_BLOCK: return createDFDCompressed(c_ASTC, 10, 8, 1, s_SFLOAT); +case VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK: return createDFDCompressed(c_ASTC, 10, 10, 1, s_SFLOAT); +case VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK: return createDFDCompressed(c_ASTC, 12, 10, 1, s_SFLOAT); +case VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK: return createDFDCompressed(c_ASTC, 12, 12, 1, s_SFLOAT); 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); @@ -284,20 +370,6 @@ case VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG: return createDFDCompressed(c_PVRTC, 8 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); @@ -330,11 +402,8 @@ case VK_FORMAT_ASTC_6x6x6_UNORM_BLOCK_EXT: return createDFDCompressed(c_ASTC, 6, 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}; +case VK_FORMAT_A1B5G5R5_UNORM_PACK16_KHR: { + int channels[] = {0,1,2,3}; int bits[] = {5,5,5,1}; return createDFDPacked(0, 4, bits, channels, s_UNORM); } +case VK_FORMAT_A8_UNORM_KHR: return createDFDAlpha(0, 1, s_UNORM); diff --git a/thirdparty/libktx/lib/filestream.c b/thirdparty/libktx/lib/filestream.c index b1e0eba7c6f..31f964b9fc0 100644 --- a/thirdparty/libktx/lib/filestream.c +++ b/thirdparty/libktx/lib/filestream.c @@ -307,15 +307,17 @@ KTX_error_code ktxFileStream_getsize(ktxStream* str, ktx_size_t* size) 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. + // 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 + // Bug in VS2013 msvcrt. fflush on FILE open for READ changes file offset + // to 4096. + if (str->data.file->_flag & _IOWRT) + (void)fflush(str->data.file); +#else (void)fflush(str->data.file); +#endif statret = fstat(fileno(str->data.file), &statbuf); if (statret < 0) { switch (errno) { diff --git a/thirdparty/libktx/lib/formatsize.h b/thirdparty/libktx/lib/formatsize.h index 7112a3a90d7..149ff18d61f 100644 --- a/thirdparty/libktx/lib/formatsize.h +++ b/thirdparty/libktx/lib/formatsize.h @@ -27,6 +27,7 @@ typedef enum ktxFormatSizeFlagBits { KTX_FORMAT_SIZE_PALETTIZED_BIT = 0x00000004, KTX_FORMAT_SIZE_DEPTH_BIT = 0x00000008, KTX_FORMAT_SIZE_STENCIL_BIT = 0x00000010, + KTX_FORMAT_SIZE_YUVSDA_BIT = 0x00000020, } ktxFormatSizeFlagBits; typedef ktx_uint32_t ktxFormatSizeFlags; diff --git a/thirdparty/libktx/lib/gl_format.h b/thirdparty/libktx/lib/gl_format.h index 2381505a68c..3986bc430c2 100644 --- a/thirdparty/libktx/lib/gl_format.h +++ b/thirdparty/libktx/lib/gl_format.h @@ -92,9 +92,9 @@ MODIFICATIONS for use in libktx #include "vkformat_enum.h" #if defined(_WIN32) && !defined(__MINGW32__) -#ifndef NOMINMAX +#if !defined(NOMINMAX) #define NOMINMAX -#endif +#endif // !defined(NOMINMAX) #ifndef __cplusplus #undef inline #define inline __inline diff --git a/thirdparty/libktx/lib/hashlist.c b/thirdparty/libktx/lib/hashlist.c index 0ca89fc561b..acfe41e5fce 100644 --- a/thirdparty/libktx/lib/hashlist.c +++ b/thirdparty/libktx/lib/hashlist.c @@ -525,14 +525,38 @@ ktxHashList_Deserialize(ktxHashList* pHead, unsigned int kvdLen, void* pKvd) result = KTX_SUCCESS; while (result == KTX_SUCCESS && src < (char *)pKvd + kvdLen) { + if (src + 6 > (char *)pKvd + kvdLen) { + // Not enough space for another entry + return KTX_FILE_DATA_ERROR; + } + char* key; unsigned int keyLen, valueLen; void* value; ktx_uint32_t keyAndValueByteSize = *((ktx_uint32_t*)src); + if (src + 4 + keyAndValueByteSize > (char *)pKvd + kvdLen) { + // Not enough space for this entry + return KTX_FILE_DATA_ERROR; + } + src += sizeof(keyAndValueByteSize); key = src; - keyLen = (unsigned int)strlen(key) + 1; + keyLen = 0; + + while (keyLen < keyAndValueByteSize && key[keyLen] != '\0') keyLen++; + + if (key[keyLen] != '\0') { + // Missing NULL terminator + return KTX_FILE_DATA_ERROR; + } + + if (keyLen >= 3 && key[0] == '\xEF' && key[1] == '\xBB' && key[2] == '\xBF') { + // Forbidden BOM + return KTX_FILE_DATA_ERROR; + } + + keyLen += 1; value = key + keyLen; valueLen = keyAndValueByteSize - keyLen; diff --git a/thirdparty/libktx/lib/ktxint.h b/thirdparty/libktx/lib/ktxint.h index 03c9945ce78..fdfec56dcb6 100644 --- a/thirdparty/libktx/lib/ktxint.h +++ b/thirdparty/libktx/lib/ktxint.h @@ -1,7 +1,7 @@ /* -*- tab-width: 4; -*- */ /* vi: set sw=2 ts=4 expandtab: */ -/* $Id: e36ad79b5eac8ea237d6a05602c71aadab575519 $ */ +/* $Id$ */ /* * Copyright 2010-2020 The Khronos Group Inc. @@ -29,6 +29,9 @@ #ifndef MAX #define MAX(x, y) (((x) > (y)) ? (x) : (y)) #endif +#ifndef MIN +#define MIN(x, y) (((x) < (y)) ? (x) : (y)) +#endif #define QUOTE(x) #x #define STR(x) QUOTE(x) @@ -211,6 +214,37 @@ KTX_error_code _ktxUnpackETC(const GLubyte* srcETC, const GLenum srcFormat, GLenum* format, GLenum* internalFormat, GLenum* type, GLint R16Formats, GLboolean supportsSRGB); +/* + * @internal + * ktxCompressZLIBBounds + * + * Returns upper bound for compresses data using miniz (ZLIB) + */ +ktx_size_t ktxCompressZLIBBounds(ktx_size_t srcLength); + +/* + * @internal + * ktxCompressZLIBInt + * + * Compresses data using miniz (ZLIB) + */ +KTX_error_code ktxCompressZLIBInt(unsigned char* pDest, + ktx_size_t* pDestLength, + const unsigned char* pSrc, + ktx_size_t srcLength, + ktx_uint32_t level); + +/* + * @internal + * ktxUncompressZLIBInt + * + * Uncompresses data using miniz (ZLIB) + */ +KTX_error_code ktxUncompressZLIBInt(unsigned char* pDest, + ktx_size_t* pDestLength, + const unsigned char* pSrc, + ktx_size_t srcLength); + /* * Pad nbytes to next multiple of n */ @@ -257,7 +291,55 @@ KTX_error_code _ktxUnpackETC(const GLubyte* srcETC, const GLenum srcFormat, ====================================== */ -void printKTX2Info2(ktxStream* src, KTX_header2* header); +KTX_error_code printKTX2Info2(ktxStream* src, KTX_header2* header); + +/* + * fopen a file identified by a UTF-8 path. + */ +#if defined(_WIN32) +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#ifndef NOMINMAX +#define NOMINMAX +#endif +#include +#include +#include +#include + +// For Windows, we convert the UTF-8 path and mode to UTF-16 path and use +// _wfopen which correctly handles unicode characters. +static inline FILE* ktxFOpenUTF8(char const* path, char const* mode) { + int wpLen = MultiByteToWideChar(CP_UTF8, 0, path, -1, NULL, 0); + int wmLen = MultiByteToWideChar(CP_UTF8, 0, mode, -1, NULL, 0); + FILE* fp = NULL; + if (wpLen > 0 && wmLen > 0) + { + wchar_t* wpath = (wchar_t*)malloc(wpLen * sizeof(wchar_t)); + wchar_t* wmode = (wchar_t*)malloc(wmLen * sizeof(wchar_t)); + MultiByteToWideChar(CP_UTF8, 0, path, -1, wpath, wpLen); + MultiByteToWideChar(CP_UTF8, 0, mode, -1, wmode, wmLen); + // Returned errno_t value is also set in the global errno. + // Apps use that for error detail as libktx only returns + // KTX_FILE_OPEN_FAILED. + (void)_wfopen_s(&fp, wpath, wmode); + free(wpath); + free(wmode); + return fp; + } else { + assert(KTX_FALSE + && "ktxFOpenUTF8 called with zero length path or mode."); + return NULL; + } +} +#else +// For other platforms there is no need for any conversion, they +// support UTF-8 natively. +static inline FILE* ktxFOpenUTF8(char const* path, char const* mode) { + return fopen(path, mode); +} +#endif #ifdef __cplusplus } diff --git a/thirdparty/libktx/lib/miniz_wrapper.cpp b/thirdparty/libktx/lib/miniz_wrapper.cpp new file mode 100644 index 00000000000..cbd7da540af --- /dev/null +++ b/thirdparty/libktx/lib/miniz_wrapper.cpp @@ -0,0 +1,149 @@ +/* -*- tab-width: 4; -*- */ +/* vi: set sw=2 ts=4 expandtab: */ + +/* + * Copyright 2023-2023 The Khronos Group Inc. + * Copyright 2023-2023 RasterGrid Kft. + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @internal + * @file miniz_wrapper.c + * @~English + * + * @brief Wrapper functions for ZLIB compression/decompression using miniz. + * + * @author Daniel Rakos, RasterGrid + */ + +#include "ktx.h" +#include "ktxint.h" + +#include + +#if !KTX_FEATURE_WRITE +// The reader does not link with the basisu components that already include a +// definition of miniz so we include it here explicitly. +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wextra" +#pragma GCC diagnostic ignored "-Wmisleading-indentation" +#endif +#include "encoder/basisu_miniz.h" +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif +#else +// Otherwise we only declare the interfaces and link with the basisu version. +// This is needed because while miniz is defined as a header in basisu it's +// not declaring the functions as static or inline, hence causing multiple +// conflicting definitions at link-time. +namespace buminiz { + typedef unsigned long mz_ulong; + enum { MZ_OK = 0, MZ_STREAM_END = 1, MZ_NEED_DICT = 2, MZ_ERRNO = -1, MZ_STREAM_ERROR = -2, MZ_DATA_ERROR = -3, MZ_MEM_ERROR = -4, MZ_BUF_ERROR = -5, MZ_VERSION_ERROR = -6, MZ_PARAM_ERROR = -10000 }; + mz_ulong mz_compressBound(mz_ulong source_len); + int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len, int level); + int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len); +} +#endif + +using namespace buminiz; + +extern "C" { + +/** + * @internal + * @~English + * @brief Returns upper bound for compresses data using miniz (ZLIB). + * + * @param srcLength source data length + * + * @author Daniel Rakos, RasterGrid + */ +ktx_size_t ktxCompressZLIBBounds(ktx_size_t srcLength) { + return mz_compressBound((mz_ulong)srcLength); +} + +/** + * @internal + * @~English + * @brief Compresses data using miniz (ZLIB) + * + * @param pDest destination data buffer + * @param pDestLength destination data buffer size + * (filled with written byte count on success) + * @param pSrc source data buffer + * @param srcLength source data size + * @param level compression level (between 1 and 9) + * + * @author Daniel Rakos, RasterGrid + */ +KTX_error_code ktxCompressZLIBInt(unsigned char* pDest, + ktx_size_t* pDestLength, + const unsigned char* pSrc, + ktx_size_t srcLength, + ktx_uint32_t level) { + if ((srcLength | *pDestLength) > 0xFFFFFFFFU) return KTX_INVALID_VALUE; + mz_ulong mzCompressedSize = (mz_ulong)*pDestLength; + int status = mz_compress2(pDest, &mzCompressedSize, pSrc, (mz_ulong)srcLength, level); + switch (status) { + case MZ_OK: + *pDestLength = mzCompressedSize; + return KTX_SUCCESS; + case MZ_PARAM_ERROR: + return KTX_INVALID_VALUE; + case MZ_BUF_ERROR: +#ifdef DEBUG + assert(false && "Deflate dstSize too small."); +#endif + return KTX_OUT_OF_MEMORY; + case MZ_MEM_ERROR: +#ifdef DEBUG + assert(false && "Deflate workspace too small."); +#endif + return KTX_OUT_OF_MEMORY; + default: + // The remaining errors look like they should only + // occur during decompression but just in case. +#ifdef DEBUG + assert(true); +#endif + return KTX_INVALID_OPERATION; + } +} + +/** + * @internal + * @~English + * @brief Uncompresses data using miniz (ZLIB) + * + * @param pDest destination data buffer + * @param pDestLength destination data buffer size + * (filled with written byte count on success) + * @param pSrc source data buffer + * @param srcLength source data size + * + * @author Daniel Rakos, RasterGrid + */ +KTX_error_code ktxUncompressZLIBInt(unsigned char* pDest, + ktx_size_t* pDestLength, + const unsigned char* pSrc, + ktx_size_t srcLength) { + if ((srcLength | *pDestLength) > 0xFFFFFFFFU) return KTX_INVALID_VALUE; + mz_ulong mzUncompressedSize = (mz_ulong)*pDestLength; + int status = mz_uncompress(pDest, &mzUncompressedSize, pSrc, (mz_ulong)srcLength); + switch (status) { + case MZ_OK: + *pDestLength = mzUncompressedSize; + return KTX_SUCCESS; + case MZ_BUF_ERROR: + return KTX_DECOMPRESS_LENGTH_ERROR; // buffer too small + case MZ_MEM_ERROR: + return KTX_OUT_OF_MEMORY; + default: + return KTX_FILE_DATA_ERROR; + } +} + +} diff --git a/thirdparty/libktx/lib/swap.c b/thirdparty/libktx/lib/swap.c index 3fdeb4f3a46..02ea6de2d8d 100644 --- a/thirdparty/libktx/lib/swap.c +++ b/thirdparty/libktx/lib/swap.c @@ -1,7 +1,7 @@ /* -*- tab-width: 4; -*- */ /* vi: set sw=2 ts=4 expandtab: */ -/* $Id: 02ea6de2d8db512ca3af08f48b98ab5f6c35e7e5 $ */ +/* $Id$ */ /* * Copyright 2010-2020 The Khronos Group Inc. diff --git a/thirdparty/libktx/lib/texture.c b/thirdparty/libktx/lib/texture.c index 35619a3e73f..76821e195b3 100644 --- a/thirdparty/libktx/lib/texture.c +++ b/thirdparty/libktx/lib/texture.c @@ -8,7 +8,7 @@ /** * @internal - * @file writer.c + * @file texture.c * @~English * * @brief ktxTexture implementation. @@ -305,10 +305,13 @@ ktxDetermineFileType_(ktxStream* pStream, ktxFileType_* pFileType, /** * @memberof ktxTexture * @~English - * @brief Construct (initialize) a ktx1 or ktx2 texture according to the stream + * @brief Create a ktx1 or ktx2 texture according to the stream * data. * - * @copydetails ktxTexture_CreateFromStdioStream + * See @ref ktxTexture1::ktxTexture1_CreateFromStream + * "ktxTexture1_CreateFromStream" or + * @ref ktxTexture2::ktxTexture2_CreateFromStream + * "ktxTexture2_CreateFromStream" for details. */ KTX_error_code ktxTexture_CreateFromStream(ktxStream* pStream, @@ -359,7 +362,10 @@ ktxTexture_CreateFromStream(ktxStream* pStream, * @brief Create a ktxTexture1 or ktxTexture2 from a stdio stream according * to the stream data. * - * @copydetails ktxTexture1_CreateFromStdioStream() + * See @ref ktxTexture1::ktxTexture1_CreateFromStdioStream + * "ktxTexture1_CreateFromStdioStream" or + * @ref ktxTexture2::ktxTexture2_CreateFromStdioStream + * "ktxTexture2_CreateFromStdioStream" for details. */ KTX_error_code ktxTexture_CreateFromStdioStream(FILE* stdioStream, @@ -385,29 +391,10 @@ ktxTexture_CreateFromStdioStream(FILE* stdioStream, * @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(). + * See @ref ktxTexture1::ktxTexture1_CreateFromNamedFile + * "ktxTexture1_CreateFromNamedFile" or + * @ref ktxTexture2::ktxTexture2_CreateFromNamedFile + * "ktxTexture2_CreateFromNamedFile" for details. */ KTX_error_code ktxTexture_CreateFromNamedFile(const char* const filename, @@ -421,7 +408,7 @@ ktxTexture_CreateFromNamedFile(const char* const filename, if (filename == NULL || newTex == NULL) return KTX_INVALID_VALUE; - file = fopen(filename, "rb"); + file = ktxFOpenUTF8(filename, "rb"); if (!file) return KTX_FILE_OPEN_FAILED; @@ -438,29 +425,10 @@ ktxTexture_CreateFromNamedFile(const char* const filename, * @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(). + * See @ref ktxTexture1::ktxTexture1_CreateFromMemory + * "ktxTexture1_CreateFromMemory" or + * @ref ktxTexture2::ktxTexture2_CreateFromMemory + * "ktxTexture2_CreateFromMemory" for details. */ KTX_error_code ktxTexture_CreateFromMemory(const ktx_uint8_t* bytes, ktx_size_t size, @@ -567,7 +535,7 @@ ktxTexture_calcImageSize(ktxTexture* This, ktx_uint32_t level, 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); + blockCount.y = MAX(prtctd->_formatSize.minBlocksY, blockCount.y); blockSizeInBytes = prtctd->_formatSize.blockSizeInBits / 8; @@ -726,8 +694,10 @@ ktxTexture_layerSize(ktxTexture* This, ktx_uint32_t level, ktx_size_t imageSize, layerSize; assert (This != NULL); + assert (prtctd->_formatSize.blockDepth != 0); - blockCountZ = MAX(1, (This->baseDepth / prtctd->_formatSize.blockDepth) >> level); + blockCountZ = ((This->baseDepth >> level) + prtctd->_formatSize.blockDepth - 1) / prtctd->_formatSize.blockDepth; + blockCountZ = MAX(1, blockCountZ); imageSize = ktxTexture_calcImageSize(This, level, fv); layerSize = imageSize * blockCountZ; if (fv == KTX_FORMAT_VERSION_ONE && KTX_GL_UNPACK_ALIGNMENT != 4) { diff --git a/thirdparty/libktx/lib/texture1.c b/thirdparty/libktx/lib/texture1.c index 8420f402b29..1591f3b6dcd 100644 --- a/thirdparty/libktx/lib/texture1.c +++ b/thirdparty/libktx/lib/texture1.c @@ -458,6 +458,9 @@ ktxTexture1_constructFromStdioStream(ktxTexture1* This, FILE* stdioStream, * @memberof ktxTexture1 @private * @brief Construct a ktxTexture1 from a named KTX file. * + * The file name must be encoded in utf-8. On Windows convert unicode names + * to utf-8 with @c WideCharToMultiByte(CP_UTF8, ...) before calling. + * * See ktxTextureInt_constructFromStream for details. * * @param[in] This pointer to a ktxTextureInt-sized block of memory to @@ -484,7 +487,7 @@ ktxTexture1_constructFromNamedFile(ktxTexture1* This, if (This == NULL || filename == NULL) return KTX_INVALID_VALUE; - file = fopen(filename, "rb"); + file = ktxFOpenUTF8(filename, "rb"); if (!file) return KTX_FILE_OPEN_FAILED; @@ -614,7 +617,7 @@ ktxTexture1_Create(ktxTextureCreateInfo* createInfo, * @~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 + * The address of a newly created texture 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, @@ -673,14 +676,17 @@ ktxTexture1_CreateFromStdioStream(FILE* stdioStream, 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 + * The address of a newly created texture reflecting the contents of the * file is written to the location pointed at by @p newTex. * + * The file name must be encoded in utf-8. On Windows convert unicode names + * to utf-8 with @c WideCharToMultiByte(CP_UTF8, ...) before calling. + * * 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 @@ -700,7 +706,7 @@ ktxTexture1_CreateFromStdioStream(FILE* stdioStream, * @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(). + * For other exceptions, see ktxTexture1_CreateFromStdioStream(). */ KTX_error_code ktxTexture1_CreateFromNamedFile(const char* const filename, @@ -731,7 +737,7 @@ ktxTexture1_CreateFromNamedFile(const char* const filename, * @~English * @brief Create a ktxTexture1 from KTX-formatted data in memory. * - * The address of a newly created ktxTexture1 reflecting the contents of the + * The address of a newly created texture 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, @@ -753,7 +759,7 @@ ktxTexture1_CreateFromNamedFile(const char* const filename, * * @exception KTX_INVALID_VALUE Either @p bytes is NULL or @p size is 0. * - * For other exceptions, see ktxTexture_CreateFromStdioStream(). + * For other exceptions, see ktxTexture1_CreateFromStdioStream(). */ KTX_error_code ktxTexture1_CreateFromMemory(const ktx_uint8_t* bytes, ktx_size_t size, @@ -784,7 +790,7 @@ ktxTexture1_CreateFromMemory(const ktx_uint8_t* bytes, ktx_size_t size, * @~English * @brief Create a ktxTexture1 from KTX-formatted data from a `ktxStream`. * - * The address of a newly created ktxTexture1 reflecting the contents of the + * The address of a newly created texture 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, @@ -796,19 +802,17 @@ ktxTexture1_CreateFromMemory(const ktx_uint8_t* bytes, ktx_size_t size, * 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] pStream 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(). + * For exceptions, see ktxTexture1_CreateFromStdioStream(). */ KTX_error_code -ktxTexture1_CreateFromStream(ktxStream* stream, +ktxTexture1_CreateFromStream(ktxStream* pStream, ktxTextureCreateFlags createFlags, ktxTexture1** newTex) { @@ -820,7 +824,7 @@ ktxTexture1_CreateFromStream(ktxStream* stream, if (tex == NULL) return KTX_OUT_OF_MEMORY; - result = ktxTexture1_constructFromStream(tex, stream, createFlags); + result = ktxTexture1_constructFromStream(tex, pStream, createFlags); if (result == KTX_SUCCESS) *newTex = (ktxTexture1*)tex; else { @@ -1044,9 +1048,9 @@ ktxTexture1_glTypeSize(ktxTexture1* This) * @~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 is almost identical to @ref ktxTexture::ktxTexture_IterateLevelFaces + * "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 @@ -1114,11 +1118,12 @@ ktxTexture1_IterateLevels(ktxTexture1* This, PFNKTXITERCB iterCb, void* userdata * @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 operates similarly to @ref ktxTexture::ktxTexture_IterateLevelFaces + * "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. diff --git a/thirdparty/libktx/lib/texture2.c b/thirdparty/libktx/lib/texture2.c index afbe7dcbfee..173e5026d9f 100644 --- a/thirdparty/libktx/lib/texture2.c +++ b/thirdparty/libktx/lib/texture2.c @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -293,6 +294,10 @@ ktxFormatSize_initFromDfd(ktxFormatSize* This, ktx_uint32_t* pDfd) return false; if (result & i_PACKED_FORMAT_BIT) This->flags |= KTX_FORMAT_SIZE_PACKED_BIT; + if (result & i_COMPRESSED_FORMAT_BIT) + This->flags |= KTX_FORMAT_SIZE_COMPRESSED_BIT; + if (result & i_YUVSDA_FORMAT_BIT) + This->flags |= KTX_FORMAT_SIZE_YUVSDA_BIT; } } if (This->blockSizeInBits == 0) { @@ -325,20 +330,7 @@ ktxFormatSize_initFromDfd(ktxFormatSize* This, ktx_uint32_t* pDfd) 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); - } + return vk2dfd(vkFormat); } /** @@ -419,7 +411,7 @@ ktxTexture2_construct(ktxTexture2* This, ktxTextureCreateInfo* createInfo, if (!This->pDfd) return KTX_OUT_OF_MEMORY; memcpy(This->pDfd, createInfo->pDfd, *createInfo->pDfd); - if (ktxFormatSize_initFromDfd(&formatSize, This->pDfd)) { + if (!ktxFormatSize_initFromDfd(&formatSize, This->pDfd)) { result = KTX_UNSUPPORTED_TEXTURE_TYPE; goto cleanup; } @@ -437,15 +429,26 @@ ktxTexture2_construct(ktxTexture2* This, ktxTextureCreateInfo* createInfo, // Ideally we'd set all these things in ktxFormatSize_initFromDfd // but This->_protected is not allocated until ktxTexture_construct; - if (This->isCompressed) + if (This->isCompressed && (formatSize.flags & KTX_FORMAT_SIZE_YUVSDA_BIT) == 0) { 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) + } else if (formatSize.flags & (KTX_FORMAT_SIZE_DEPTH_BIT | KTX_FORMAT_SIZE_STENCIL_BIT)) { + switch (createInfo->vkFormat) { + case VK_FORMAT_S8_UINT: + This->_protected->_typeSize = 1; + break; + case VK_FORMAT_D16_UNORM: // [[fallthrough]]; + case VK_FORMAT_D16_UNORM_S8_UINT: This->_protected->_typeSize = 2; - else + break; + case VK_FORMAT_X8_D24_UNORM_PACK32: // [[fallthrough]]; + case VK_FORMAT_D24_UNORM_S8_UINT: // [[fallthrough]]; + case VK_FORMAT_D32_SFLOAT: // [[fallthrough]]; + case VK_FORMAT_D32_SFLOAT_S8_UINT: This->_protected->_typeSize = 4; + break; + } + } else if (formatSize.flags & KTX_FORMAT_SIZE_PACKED_BIT) { + This->_protected->_typeSize = formatSize.blockSizeInBits / 8; } else { // Unpacked and uncompressed uint32_t numComponents; @@ -503,7 +506,7 @@ cleanup: * * @exception KTX_OUT_OF_MEMORY Not enough memory for the texture data. */ -static KTX_error_code +KTX_error_code ktxTexture2_constructCopy(ktxTexture2* This, ktxTexture2* orig) { KTX_error_code result; @@ -648,6 +651,7 @@ ktxTexture2_constructFromStreamAndHeader(ktxTexture2* This, ktxStream* pStream, KTX_error_code result; KTX_supplemental_info suppInfo; ktxStream* stream; + struct BDFD* pBDFD; ktx_size_t levelIndexSize; assert(pHeader != NULL && pStream != NULL); @@ -721,9 +725,21 @@ ktxTexture2_constructFromStreamAndHeader(ktxTexture2* This, ktxStream* pStream, for (ktx_uint32_t level = 0; level < This->numLevels; level++) { private->_levelIndex[level].byteOffset -= private->_firstLevelFileOffset; + if (This->supercompressionScheme == KTX_SS_NONE && + private->_levelIndex[level].byteLength != private->_levelIndex[level].uncompressedByteLength) { + // For non-supercompressed files the levels must have matching byte lengths + result = KTX_FILE_DATA_ERROR; + } } + if (result != KTX_SUCCESS) + goto cleanup; // Read DFD + if (pHeader->dataFormatDescriptor.byteOffset == 0 || pHeader->dataFormatDescriptor.byteLength < 16) { + // Missing or too small DFD + result = KTX_FILE_DATA_ERROR; + goto cleanup; + } This->pDfd = (ktx_uint32_t*)malloc(pHeader->dataFormatDescriptor.byteLength); if (!This->pDfd) { @@ -735,19 +751,87 @@ ktxTexture2_constructFromStreamAndHeader(ktxTexture2* This, ktxStream* pStream, if (result != KTX_SUCCESS) goto cleanup; + if (pHeader->dataFormatDescriptor.byteLength != This->pDfd[0]) { + // DFD byteLength does not match dfdTotalSize + result = KTX_FILE_DATA_ERROR; + goto cleanup; + } + pBDFD = (struct BDFD*)(This->pDfd + 1); + if (pBDFD->descriptorBlockSize < 24 || (pBDFD->descriptorBlockSize - 24) % 16 != 0) { + // BDFD has invalid size + result = KTX_FILE_DATA_ERROR; + goto cleanup; + } + if (pBDFD->transfer != KHR_DF_TRANSFER_LINEAR && pBDFD->transfer != KHR_DF_TRANSFER_SRGB) { + // Unsupported transfer function + result = KTX_FILE_DATA_ERROR; + 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) - { + if (This->supercompressionScheme == KTX_SS_BASIS_LZ && pBDFD->model != KHR_DF_MODEL_ETC1S) { result = KTX_FILE_DATA_ERROR; goto cleanup; } + // Check compatibility with the KHR_texture_basisu glTF extension, if needed. + if (createFlags & KTX_TEXTURE_CREATE_CHECK_GLTF_BASISU_BIT) { + uint32_t max_dim = MAX(MAX(pHeader->pixelWidth, pHeader->pixelHeight), pHeader->pixelDepth); + uint32_t full_mip_pyramid_level_count = 1 + (uint32_t)log2(max_dim); + if (pHeader->levelCount != 1 && pHeader->levelCount != full_mip_pyramid_level_count) { + // KHR_texture_basisu requires full mip pyramid or single mip level + result = KTX_FILE_DATA_ERROR; + goto cleanup; + } + if (This->numDimensions != 2 || This->isArray || This->isCubemap) { + // KHR_texture_basisu requires 2D textures. + result = KTX_FILE_DATA_ERROR; + goto cleanup; + } + if ((This->baseWidth % 4) != 0 || (This->baseHeight % 4) != 0) { + // KHR_texture_basisu requires width and height to be a multiple of 4. + result = KTX_FILE_DATA_ERROR; + goto cleanup; + } + if (pBDFD->model != KHR_DF_MODEL_ETC1S && pBDFD->model != KHR_DF_MODEL_UASTC) { + // KHR_texture_basisu requires BasisLZ or UASTC + result = KTX_FILE_DATA_ERROR; + goto cleanup; + } + if (pBDFD->model == KHR_DF_MODEL_UASTC && + This->supercompressionScheme != KTX_SS_NONE && + This->supercompressionScheme != KTX_SS_ZSTD) { + // KHR_texture_basisu only allows NONE and ZSTD supercompression for UASTC + result = KTX_FILE_DATA_ERROR; + goto cleanup; + } + } + + uint32_t sampleCount = KHR_DFDSAMPLECOUNT(This->pDfd + 1); + if (sampleCount == 0) { + // Invalid sample count + result = KTX_FILE_DATA_ERROR; + goto cleanup; + } + if (pBDFD->model == KHR_DF_MODEL_ETC1S || pBDFD->model == KHR_DF_MODEL_UASTC) { + if (sampleCount < 1 || sampleCount > 2 || (sampleCount == 2 && pBDFD->model == KHR_DF_MODEL_UASTC)) { + // Invalid sample count + result = KTX_FILE_DATA_ERROR; + goto cleanup; + } + if (pBDFD->texelBlockDimension0 != 3 || pBDFD->texelBlockDimension1 != 3 || + pBDFD->texelBlockDimension2 != 0 || pBDFD->texelBlockDimension3 != 0) { + // Texel block dimension must be 4x4x1x1 (offset by one) + result = KTX_FILE_DATA_ERROR; + goto cleanup; + } + } + This->_private->_requiredLevelAlignment = ktxTexture2_calcRequiredLevelAlignment(This); @@ -755,6 +839,12 @@ ktxTexture2_constructFromStreamAndHeader(ktxTexture2* This, ktxStream* pStream, ktxHashList_Construct(&This->kvDataHead); // Load KVData. if (pHeader->keyValueData.byteLength > 0) { + uint32_t expectedOffset = pHeader->dataFormatDescriptor.byteOffset + pHeader->dataFormatDescriptor.byteLength; + expectedOffset = (expectedOffset + 3) & ~0x3; // 4 byte aligned + if (pHeader->keyValueData.byteOffset != expectedOffset) { + result = KTX_FILE_DATA_ERROR; + goto cleanup; + } if (!(createFlags & KTX_TEXTURE_CREATE_SKIP_KVDATA_BIT)) { ktx_uint32_t kvdLen = pHeader->keyValueData.byteLength; ktx_uint8_t* pKvd; @@ -850,9 +940,30 @@ ktxTexture2_constructFromStreamAndHeader(ktxTexture2* This, ktxStream* pStream, } else { stream->skip(stream, pHeader->keyValueData.byteLength); } + } else if (pHeader->keyValueData.byteOffset != 0) { + // Non-zero KVD byteOffset with zero byteLength + result = KTX_FILE_DATA_ERROR; + goto cleanup; } if (pHeader->supercompressionGlobalData.byteLength > 0) { + switch (This->supercompressionScheme) { + case KTX_SS_BASIS_LZ: + break; + case KTX_SS_NONE: + case KTX_SS_ZSTD: + case KTX_SS_ZLIB: + // In these cases SGD is not allowed + result = KTX_FILE_DATA_ERROR; + break; + default: + // We don't support other supercompression schemes + result = KTX_UNSUPPORTED_FEATURE; + break; + } + if (result != KTX_SUCCESS) + goto cleanup; + // There could be padding here so seek to the next item. (void)stream->setpos(stream, pHeader->supercompressionGlobalData.byteOffset); @@ -871,6 +982,14 @@ ktxTexture2_constructFromStreamAndHeader(ktxTexture2* This, ktxStream* pStream, if (result != KTX_SUCCESS) goto cleanup; + } else if (pHeader->supercompressionGlobalData.byteOffset != 0) { + // Non-zero SGD byteOffset with zero byteLength + result = KTX_FILE_DATA_ERROR; + goto cleanup; + } else if (This->supercompressionScheme == KTX_SS_BASIS_LZ) { + // SGD is required for BasisLZ + result = KTX_FILE_DATA_ERROR; + goto cleanup; } // Calculate size of the image data. Level 0 is the last level in the data. @@ -982,6 +1101,9 @@ ktxTexture2_constructFromStdioStream(ktxTexture2* This, FILE* stdioStream, * @~English * @brief Construct a ktxTexture from a named KTX file. * + * The file name must be encoded in utf-8. On Windows convert unicode names + * to utf-8 with @c WideCharToMultiByte(CP_UTF8, ...) before calling. + * * See ktxTextureInt_constructFromStream for details. * * @param[in] This pointer to a ktxTextureInt-sized block of memory to @@ -1008,7 +1130,7 @@ ktxTexture2_constructFromNamedFile(ktxTexture2* This, if (This == NULL || filename == NULL) return KTX_INVALID_VALUE; - file = fopen(filename, "rb"); + file = ktxFOpenUTF8(filename, "rb"); if (!file) return KTX_FILE_OPEN_FAILED; @@ -1259,6 +1381,9 @@ ktxTexture2_CreateFromStdioStream(FILE* stdioStream, * The address of a newly created ktxTexture2 reflecting the contents of the * file is written to the location pointed at by @p newTex. * + * The file name must be encoded in utf-8. On Windows convert unicode names + * to utf-8 with @c WideCharToMultiByte(CP_UTF8, ...) before calling. + * * 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 @@ -1581,7 +1706,7 @@ ktxTexture2_calcPostInflationLevelAlignment(ktxTexture2* This) // Should actually work for none supercompressed but don't want to // encourage use of it. - assert(This->supercompressionScheme >= KTX_SS_ZSTD); + assert(This->supercompressionScheme != KTX_SS_NONE && This->supercompressionScheme != KTX_SS_BASIS_LZ); if (This->vkFormat != VK_FORMAT_UNDEFINED) alignment = lcm4(This->_protected->_formatSize.blockSizeInBits / 8); @@ -1834,15 +1959,17 @@ ktxTexture2_NeedsTranscoding(ktxTexture2* This) /** * @memberof ktxTexture2 * @~English - * @brief Return the total size in bytes of the uncompressed data of a ktxTexture2. + * @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. + * If supercompressionScheme == @c KTX_SS_NONE or + * @c KTX_SS_BASIS_LZ, returns the value of @c This->dataSize + * else if supercompressionScheme == @c KTX_SS_ZSTD or @c KTX_SS_ZLIB, 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. */ @@ -1854,6 +1981,7 @@ ktxTexture2_GetDataSizeUncompressed(ktxTexture2* This) case KTX_SS_NONE: return This->dataSize; case KTX_SS_ZSTD: + case KTX_SS_ZLIB: { ktx_size_t uncompressedSize = 0; ktx_uint32_t uncompressedLevelAlignment; @@ -1984,7 +2112,7 @@ ktxTexture2_IterateLevels(ktxTexture2* This, PFNKTXITERCB iterCb, void* userdata * * 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, + * while iterating. If supercompressionScheme == KTX_SS_ZSTD or KTX_SS_ZLIB, * 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. @@ -1992,8 +2120,8 @@ ktxTexture2_IterateLevels(ktxTexture2* This, PFNKTXITERCB iterCb, void* userdata * 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 + * Intended for use only when supercompressionScheme == KTX_SS_NONE, + * KTX_SS_ZSTD or KTX_SS_ZLIB. 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. @@ -2013,8 +2141,9 @@ ktxTexture2_IterateLevels(ktxTexture2* This, PFNKTXITERCB iterCb, void* userdata * this ktxTexture2's images have already * been loaded. * @exception KTX_INVALID_OPERATION - * supercompressionScheme != SUPERCOMPRESSION_NONE. - * and supercompressionScheme != SUPERCOMPRESSION_ZSTD. + * supercompressionScheme != KTX_SS_NONE, + * supercompressionScheme != KTX_SS_ZSTD, and + * supercompressionScheme != KTX_SS_ZLIB. * @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. @@ -2040,7 +2169,8 @@ ktxTexture2_IterateLoadLevelFaces(ktxTexture2* This, PFNKTXITERCB iterCb, return KTX_INVALID_OPERATION; if (This->supercompressionScheme != KTX_SS_NONE && - This->supercompressionScheme != KTX_SS_ZSTD) + This->supercompressionScheme != KTX_SS_ZSTD && + This->supercompressionScheme != KTX_SS_ZLIB) return KTX_INVALID_OPERATION; if (iterCb == NULL) @@ -2057,14 +2187,16 @@ ktxTexture2_IterateLoadLevelFaces(ktxTexture2* This, PFNKTXITERCB iterCb, dataBuf = malloc(dataSize); if (!dataBuf) return KTX_OUT_OF_MEMORY; - if (This->supercompressionScheme == KTX_SS_ZSTD) { + if (This->supercompressionScheme == KTX_SS_ZSTD || This->supercompressionScheme == KTX_SS_ZLIB) { uncompressedDataSize = levelIndex[0].uncompressedByteLength; uncompressedDataBuf = malloc(uncompressedDataSize); if (!uncompressedDataBuf) { result = KTX_OUT_OF_MEMORY; goto cleanup; } - dctx = ZSTD_createDCtx(); + if (This->supercompressionScheme == KTX_SS_ZSTD) { + dctx = ZSTD_createDCtx(); + } pData = uncompressedDataBuf; } else { pData = dataBuf; @@ -2107,21 +2239,34 @@ ktxTexture2_IterateLoadLevelFaces(ktxTexture2* This, PFNKTXITERCB iterCb, ZSTD_ErrorCode error = ZSTD_getErrorCode(levelSize); switch(error) { case ZSTD_error_dstSize_tooSmall: - return KTX_INVALID_VALUE; // inflatedDataCapacity too small. + return KTX_DECOMPRESS_LENGTH_ERROR; // inflatedDataCapacity too small. + case ZSTD_error_checksum_wrong: + return KTX_DECOMPRESS_CHECKSUM_ERROR; 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; + } else if (This->supercompressionScheme == KTX_SS_ZLIB) { + result = ktxUncompressZLIBInt(uncompressedDataBuf, + &uncompressedDataSize, + dataBuf, + levelSize); + if (result != KTX_SUCCESS) + return result; } + if (levelIndex[level].uncompressedByteLength != levelSize) + return KTX_DECOMPRESS_LENGTH_ERROR; + #if IS_BIG_ENDIAN switch (prtctd->_typeSize) { case 2: @@ -2188,16 +2333,23 @@ KTX_error_code ktxTexture2_inflateZstdInt(ktxTexture2* This, ktx_uint8_t* pDeflatedData, ktx_uint8_t* pInflatedData, ktx_size_t inflatedDataCapacity); + +KTX_error_code +ktxTexture2_inflateZLIBInt(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 will be inflated if supercompressionScheme == @c KTX_SS_ZSTD or + * @c KTX_SS_ZLIB. * 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(). + * with Zstd or ZLIB. See ktxTexture2\_GetDataSizeUncompressed(). * * The texture's levelIndex, dataSize, DFD and supercompressionScheme will * all be updated after successful inflation to reflect the inflated data. @@ -2248,7 +2400,7 @@ ktxTexture2_LoadImageData(ktxTexture2* This, pDest = pBuffer; } - if (This->supercompressionScheme == KTX_SS_ZSTD) { + if (This->supercompressionScheme == KTX_SS_ZSTD || This->supercompressionScheme == KTX_SS_ZLIB) { // Create buffer to hold deflated data. pDeflatedData = malloc(This->dataSize); if (pDeflatedData == NULL) @@ -2271,10 +2423,15 @@ ktxTexture2_LoadImageData(ktxTexture2* This, if (result != KTX_SUCCESS) return result; - if (This->supercompressionScheme == KTX_SS_ZSTD) { + if (This->supercompressionScheme == KTX_SS_ZSTD || This->supercompressionScheme == KTX_SS_ZLIB) { assert(pDeflatedData != NULL); - result = ktxTexture2_inflateZstdInt(This, pDeflatedData, pDest, - inflatedDataCapacity); + if (This->supercompressionScheme == KTX_SS_ZSTD) { + result = ktxTexture2_inflateZstdInt(This, pDeflatedData, pDest, + inflatedDataCapacity); + } else if (This->supercompressionScheme == KTX_SS_ZLIB) { + result = ktxTexture2_inflateZLIBInt(This, pDeflatedData, pDest, + inflatedDataCapacity); + } free(pDeflatedData); if (result != KTX_SUCCESS) { if (pBuffer == NULL) { @@ -2388,13 +2545,19 @@ ktxTexture2_inflateZstdInt(ktxTexture2* This, ktx_uint8_t* pDeflatedData, ZSTD_ErrorCode error = ZSTD_getErrorCode(levelByteLength); switch(error) { case ZSTD_error_dstSize_tooSmall: - return KTX_INVALID_VALUE; // inflatedDataCapacity too small. + return KTX_DECOMPRESS_LENGTH_ERROR; // inflatedDataCapacity too small. + case ZSTD_error_checksum_wrong: + return KTX_DECOMPRESS_CHECKSUM_ERROR; case ZSTD_error_memory_allocation: return KTX_OUT_OF_MEMORY; default: return KTX_FILE_DATA_ERROR; } } + + if (This->_private->_levelIndex[level].uncompressedByteLength != levelByteLength) + return KTX_DECOMPRESS_LENGTH_ERROR; + nindex[level].byteOffset = levelOffset; nindex[level].uncompressedByteLength = nindex[level].byteLength = levelByteLength; @@ -2421,6 +2584,89 @@ ktxTexture2_inflateZstdInt(ktxTexture2* This, ktx_uint8_t* pDeflatedData, return KTX_SUCCESS; } +/** + * @memberof ktxTexture2 @private + * @~English + * @brief Inflate the data in a ktxTexture2 object using miniz (ZLIB). + * + * 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_inflateZLIBInt(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; + + if (pDeflatedData == NULL) + return KTX_INVALID_VALUE; + + if (pInflatedData == NULL) + return KTX_INVALID_VALUE; + + if (This->supercompressionScheme != KTX_SS_ZLIB) + return KTX_INVALID_OPERATION; + + nindex = malloc(levelIndexByteLength); + if (nindex == NULL) + return KTX_OUT_OF_MEMORY; + + uncompressedLevelAlignment = + ktxTexture2_calcPostInflationLevelAlignment(This); + + ktx_size_t inflatedByteLength = 0; + for (int32_t level = This->numLevels - 1; level >= 0; level--) { + size_t levelByteLength = inflatedDataCapacity; + KTX_error_code result = ktxUncompressZLIBInt(pInflatedData + levelOffset, + &levelByteLength, + &pDeflatedData[cindex[level].byteOffset], + cindex[level].byteLength); + if (result != KTX_SUCCESS) + return result; + + if (This->_private->_levelIndex[level].uncompressedByteLength != levelByteLength) + return KTX_DECOMPRESS_LENGTH_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; + } + + // 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 /* diff --git a/thirdparty/libktx/lib/texture2.h b/thirdparty/libktx/lib/texture2.h index 14e4115ecf7..08507804d92 100644 --- a/thirdparty/libktx/lib/texture2.h +++ b/thirdparty/libktx/lib/texture2.h @@ -50,6 +50,8 @@ KTX_error_code ktxTexture2_LoadImageData(ktxTexture2* This, ktx_uint8_t* pBuffer, ktx_size_t bufSize); +KTX_error_code +ktxTexture2_constructCopy(ktxTexture2* This, ktxTexture2* orig); KTX_error_code ktxTexture2_constructFromStreamAndHeader(ktxTexture2* This, ktxStream* pStream, KTX_header2* pHeader, diff --git a/thirdparty/libktx/lib/vkformat_check.c b/thirdparty/libktx/lib/vkformat_check.c new file mode 100644 index 00000000000..e987b3d76a1 --- /dev/null +++ b/thirdparty/libktx/lib/vkformat_check.c @@ -0,0 +1,165 @@ + +/***************************** Do not edit. ***************************** + Automatically generated from vulkan_core.h version 267 by mkvkformatfiles. + *************************************************************************/ + +/* +** Copyright 2015-2023 The Khronos Group Inc. +** +** SPDX-License-Identifier: Apache-2.0 +*/ + +#include +#include + +#include "vkformat_enum.h" + +bool +isProhibitedFormat(VkFormat format) +{ + switch (format) { + case VK_FORMAT_R8_USCALED: + case VK_FORMAT_R8_SSCALED: + case VK_FORMAT_R8G8_USCALED: + case VK_FORMAT_R8G8_SSCALED: + case VK_FORMAT_R8G8B8_USCALED: + case VK_FORMAT_R8G8B8_SSCALED: + case VK_FORMAT_B8G8R8_USCALED: + case VK_FORMAT_B8G8R8_SSCALED: + case VK_FORMAT_R8G8B8A8_USCALED: + case VK_FORMAT_R8G8B8A8_SSCALED: + case VK_FORMAT_B8G8R8A8_USCALED: + case VK_FORMAT_B8G8R8A8_SSCALED: + 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: + case VK_FORMAT_A2R10G10B10_USCALED_PACK32: + case VK_FORMAT_A2R10G10B10_SSCALED_PACK32: + case VK_FORMAT_A2B10G10R10_USCALED_PACK32: + case VK_FORMAT_A2B10G10R10_SSCALED_PACK32: + case VK_FORMAT_R16_USCALED: + case VK_FORMAT_R16_SSCALED: + case VK_FORMAT_R16G16_USCALED: + case VK_FORMAT_R16G16_SSCALED: + case VK_FORMAT_R16G16B16_USCALED: + case VK_FORMAT_R16G16B16_SSCALED: + case VK_FORMAT_R16G16B16A16_USCALED: + case VK_FORMAT_R16G16B16A16_SSCALED: + case VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM: + case VK_FORMAT_G8_B8R8_2PLANE_420_UNORM: + case VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM: + case VK_FORMAT_G8_B8R8_2PLANE_422_UNORM: + case VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM: + case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16: + case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16: + case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16: + case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16: + case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16: + case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16: + case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16: + case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16: + case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16: + case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16: + case VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM: + case VK_FORMAT_G16_B16R16_2PLANE_420_UNORM: + case VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM: + case VK_FORMAT_G16_B16R16_2PLANE_422_UNORM: + case VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM: + case VK_FORMAT_G8_B8R8_2PLANE_444_UNORM: + case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16: + case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16: + case VK_FORMAT_G16_B16R16_2PLANE_444_UNORM: + return true; + default: + return false; + } +} + +bool +isValidFormat(VkFormat format) +{ + // On MSVC VkFormat can be a signed integer + if ((uint32_t) format <= VK_FORMAT_MAX_STANDARD_ENUM) + return true; + else switch(format) { + case VK_FORMAT_G8B8G8R8_422_UNORM: + case VK_FORMAT_B8G8R8G8_422_UNORM: + case VK_FORMAT_R10X6_UNORM_PACK16: + case VK_FORMAT_R10X6G10X6_UNORM_2PACK16: + case VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16: + case VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16: + case VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16: + case VK_FORMAT_R12X4_UNORM_PACK16: + case VK_FORMAT_R12X4G12X4_UNORM_2PACK16: + case VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16: + case VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16: + case VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16: + case VK_FORMAT_G16B16G16R16_422_UNORM: + case VK_FORMAT_B16G16R16G16_422_UNORM: + case VK_FORMAT_A4R4G4B4_UNORM_PACK16: + case VK_FORMAT_A4B4G4R4_UNORM_PACK16: + case VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK: + case VK_FORMAT_ASTC_5x4_SFLOAT_BLOCK: + case VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK: + case VK_FORMAT_ASTC_6x5_SFLOAT_BLOCK: + case VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK: + case VK_FORMAT_ASTC_8x5_SFLOAT_BLOCK: + case VK_FORMAT_ASTC_8x6_SFLOAT_BLOCK: + case VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK: + case VK_FORMAT_ASTC_10x5_SFLOAT_BLOCK: + case VK_FORMAT_ASTC_10x6_SFLOAT_BLOCK: + case VK_FORMAT_ASTC_10x8_SFLOAT_BLOCK: + case VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK: + case VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK: + case VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK: + case VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG: + case VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG: + case VK_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG: + case VK_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG: + case VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG: + case VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG: + case VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG: + case VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG: + case VK_FORMAT_ASTC_3x3x3_UNORM_BLOCK_EXT: + case VK_FORMAT_ASTC_3x3x3_SRGB_BLOCK_EXT: + case VK_FORMAT_ASTC_3x3x3_SFLOAT_BLOCK_EXT: + case VK_FORMAT_ASTC_4x3x3_UNORM_BLOCK_EXT: + case VK_FORMAT_ASTC_4x3x3_SRGB_BLOCK_EXT: + case VK_FORMAT_ASTC_4x3x3_SFLOAT_BLOCK_EXT: + case VK_FORMAT_ASTC_4x4x3_UNORM_BLOCK_EXT: + case VK_FORMAT_ASTC_4x4x3_SRGB_BLOCK_EXT: + case VK_FORMAT_ASTC_4x4x3_SFLOAT_BLOCK_EXT: + case VK_FORMAT_ASTC_4x4x4_UNORM_BLOCK_EXT: + case VK_FORMAT_ASTC_4x4x4_SRGB_BLOCK_EXT: + case VK_FORMAT_ASTC_4x4x4_SFLOAT_BLOCK_EXT: + case VK_FORMAT_ASTC_5x4x4_UNORM_BLOCK_EXT: + case VK_FORMAT_ASTC_5x4x4_SRGB_BLOCK_EXT: + case VK_FORMAT_ASTC_5x4x4_SFLOAT_BLOCK_EXT: + case VK_FORMAT_ASTC_5x5x4_UNORM_BLOCK_EXT: + case VK_FORMAT_ASTC_5x5x4_SRGB_BLOCK_EXT: + case VK_FORMAT_ASTC_5x5x4_SFLOAT_BLOCK_EXT: + case VK_FORMAT_ASTC_5x5x5_UNORM_BLOCK_EXT: + case VK_FORMAT_ASTC_5x5x5_SRGB_BLOCK_EXT: + case VK_FORMAT_ASTC_5x5x5_SFLOAT_BLOCK_EXT: + case VK_FORMAT_ASTC_6x5x5_UNORM_BLOCK_EXT: + case VK_FORMAT_ASTC_6x5x5_SRGB_BLOCK_EXT: + case VK_FORMAT_ASTC_6x5x5_SFLOAT_BLOCK_EXT: + case VK_FORMAT_ASTC_6x6x5_UNORM_BLOCK_EXT: + case VK_FORMAT_ASTC_6x6x5_SRGB_BLOCK_EXT: + case VK_FORMAT_ASTC_6x6x5_SFLOAT_BLOCK_EXT: + case VK_FORMAT_ASTC_6x6x6_UNORM_BLOCK_EXT: + case VK_FORMAT_ASTC_6x6x6_SRGB_BLOCK_EXT: + case VK_FORMAT_ASTC_6x6x6_SFLOAT_BLOCK_EXT: + case VK_FORMAT_R16G16_S10_5_NV: + case VK_FORMAT_A1B5G5R5_UNORM_PACK16_KHR: + case VK_FORMAT_A8_UNORM_KHR: + return true; + default: + return false; + } +} + diff --git a/thirdparty/libktx/lib/vkformat_enum.h b/thirdparty/libktx/lib/vkformat_enum.h index c6d85602bd2..62279bb0098 100644 --- a/thirdparty/libktx/lib/vkformat_enum.h +++ b/thirdparty/libktx/lib/vkformat_enum.h @@ -2,11 +2,11 @@ #define _VKFORMAT_ENUM_H_ /***************************** Do not edit. ***************************** - Automatically generated from vulkan_core.h version 151 by mkvkformatfiles. + Automatically generated from vulkan_core.h version 267 by mkvkformatfiles. *************************************************************************/ /* -** Copyright (c) 2015-2020 The Khronos Group Inc. +** Copyright 2015-2023 The Khronos Group Inc. ** ** SPDX-License-Identifier: Apache-2.0 */ @@ -238,6 +238,26 @@ typedef enum VkFormat { 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_G8_B8R8_2PLANE_444_UNORM = 1000330000, + VK_FORMAT_G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16 = 1000330001, + VK_FORMAT_G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16 = 1000330002, + VK_FORMAT_G16_B16R16_2PLANE_444_UNORM = 1000330003, + VK_FORMAT_A4R4G4B4_UNORM_PACK16 = 1000340000, + VK_FORMAT_A4B4G4R4_UNORM_PACK16 = 1000340001, + VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK = 1000066000, + VK_FORMAT_ASTC_5x4_SFLOAT_BLOCK = 1000066001, + VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK = 1000066002, + VK_FORMAT_ASTC_6x5_SFLOAT_BLOCK = 1000066003, + VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK = 1000066004, + VK_FORMAT_ASTC_8x5_SFLOAT_BLOCK = 1000066005, + VK_FORMAT_ASTC_8x6_SFLOAT_BLOCK = 1000066006, + VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK = 1000066007, + VK_FORMAT_ASTC_10x5_SFLOAT_BLOCK = 1000066008, + VK_FORMAT_ASTC_10x6_SFLOAT_BLOCK = 1000066009, + VK_FORMAT_ASTC_10x8_SFLOAT_BLOCK = 1000066010, + VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK = 1000066011, + VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK = 1000066012, + VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK = 1000066013, VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG = 1000054000, VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG = 1000054001, VK_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG = 1000054002, @@ -246,20 +266,6 @@ typedef enum VkFormat { 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, @@ -290,10 +296,18 @@ typedef enum VkFormat { 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_R16G16_S10_5_NV = 1000464000, + VK_FORMAT_A1B5G5R5_UNORM_PACK16_KHR = 1000470000, + VK_FORMAT_A8_UNORM_KHR = 1000470001, VK_FORMAT_MAX_ENUM = 0x7FFFFFFF } VkFormat; +#if defined(_MSC_VER) && _MSC_VER < 1900 // Older than VS 2015. +typedef unsigned __int32 VkFlags; +#else +#include +typedef uint64_t VkFlags64; +#endif + #define VK_FORMAT_MAX_STANDARD_ENUM 184 diff --git a/thirdparty/libktx/patches/godot.patch b/thirdparty/libktx/patches/godot.patch new file mode 100644 index 00000000000..28db86cf9b3 --- /dev/null +++ b/thirdparty/libktx/patches/godot.patch @@ -0,0 +1,50 @@ +diff --git a/thirdparty/libktx/lib/basis_transcode.cpp b/thirdparty/libktx/lib/basis_transcode.cpp +index ca68545e4a..d7ecb7a0fd 100644 +--- a/thirdparty/libktx/lib/basis_transcode.cpp ++++ b/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 +diff --git a/thirdparty/libktx/lib/dfdutils/vk2dfd.inl b/thirdparty/libktx/lib/dfdutils/vk2dfd.inl +index 85d53202a5..25c7a2c238 100644 +--- a/thirdparty/libktx/lib/dfdutils/vk2dfd.inl ++++ b/thirdparty/libktx/lib/dfdutils/vk2dfd.inl +@@ -370,6 +370,7 @@ case VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG: return createDFDCompressed(c_PVRTC, 8 + 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); ++#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); +@@ -400,6 +401,7 @@ case VK_FORMAT_ASTC_6x6x5_SFLOAT_BLOCK_EXT: return createDFDCompressed(c_ASTC, 6 + 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_A1B5G5R5_UNORM_PACK16_KHR: { + int channels[] = {0,1,2,3}; int bits[] = {5,5,5,1}; + return createDFDPacked(0, 4, bits, channels, s_UNORM); +diff --git a/thirdparty/libktx/lib/miniz_wrapper.cpp b/thirdparty/libktx/lib/miniz_wrapper.cpp +index 07920c4809..cbd7da540a 100644 +--- a/thirdparty/libktx/lib/miniz_wrapper.cpp ++++ b/thirdparty/libktx/lib/miniz_wrapper.cpp +@@ -30,7 +30,7 @@ + #pragma GCC diagnostic ignored "-Wextra" + #pragma GCC diagnostic ignored "-Wmisleading-indentation" + #endif +-#include "basisu/encoder/basisu_miniz.h" ++#include "encoder/basisu_miniz.h" + #ifdef __GNUC__ + #pragma GCC diagnostic pop + #endif