diff --git a/Makefile b/Makefile index 0ae210d..cb0bfa1 100644 --- a/Makefile +++ b/Makefile @@ -22,6 +22,8 @@ ktx_inlined_images := icons/ktx_favicon.ico \ appendices=appendices ktx_sources := ktxspec.adoc \ + $(appendices)/basisuah66i-gdata.adoc \ + $(appendices)/basisuah66i-bitstream.adoc \ $(appendices)/basislz-gdata.adoc \ $(appendices)/basislz-bitstream.adoc \ $(appendices)/vendor-metadata.adoc \ diff --git a/appendices/basislz-gdata.adoc b/appendices/basislz-gdata.adoc index 58277b7..1d483f2 100644 --- a/appendices/basislz-gdata.adoc +++ b/appendices/basislz-gdata.adoc @@ -3,7 +3,7 @@ BasisLZ combines encoding to a block-compressed format, that can be easily transcoded to various GPU-native block-compressed formats, with lossless supercompression. Supercompression is accomplished by conditioning the block-compressed representation for entropy encoding then Huffman encoding the result. BasisLZ creates a global codebook referenced by each supercompressed image that contains the processed endpoint and selector data from the block-compression and the Huffman tables. The global data block contains this codebook. -It also contains an array of _image descriptors_ with flags for each image and the offset and length within the mip level of the data for that image. +It also contains an array of _image descriptors_ with flags for each image and the offset within its mip level and length of the data for that image. The global data structure is designed to accommodate various transcodable block-compressed formats. The format in use is indicated by the <<_data_format_descriptor, Data Format Descriptor>>. Currently BasisLZ only supports one, <> (a subset of ETC1, see {url-df-spec}#ETC1S[Section 21.1] of <>). ETC1S is a common subset of many GPU-native formats. @@ -139,3 +139,4 @@ in <>. === extendedData Extended data. This is not used for ETC1S. +// vim: filetype=asciidoc ai expandtab tw=0 ts=4 sts=2 sw=2 diff --git a/appendices/basisuah66i-bitstream.adoc b/appendices/basisuah66i-bitstream.adoc new file mode 100644 index 0000000..fa49099 --- /dev/null +++ b/appendices/basisuah66i-bitstream.adoc @@ -0,0 +1,15 @@ +[appendix#basisuah66i] +[#basisuah66i_bitstream] +== Basis UASTC HDR 6x6 Intermediate Bitstream Specification + +_Basis UASTC HDR 6x6 Intermediate_ is a custom supercompression scheme for the Basis UASTC HDR 6x6 texture format. + +The bitstream is as documented in the https://github.com/BinomialLLC/basis_universal/wiki/UASTC-HDR-6x6-Intermediate-File-Format-(Basis-GPU-Photo-6x6)[format specification] on the basis_universal Wiki. +The compression type is signalled by `supercompressionScheme` = 4 and `colorModel` = 168. +The bitstream has a https://github.com/BinomialLLC/basis_universal/wiki/UASTC-HDR-6x6-Intermediate-File-Format-(Basis-GPU-Photo-6x6)#header[header] of 3 little-endian 16-bit fields. +The first field is a combined ID field containing the entropy profile and stream semantic version with the profile ID in bits 15-8 (the second byte) and the stream semantic version in bits 7-0 (the first byte). +This field must match the least significant 16-bits of (the first two bytes) of `rgbSliceType` in the <> that refers to the bitstream. +The second and third fields are the width and height of the texture image in pixels. +The value of the width field must equal stem:[\textit{num_blocks_x}] and the value of the height field must equal stem:[\textit{num_blocks_y}] as calculated for the mip level using <>. Since the width and height are in pixels, stem:[\textit{block_width}] and stem:[\textit{block_height}] in those formulae must be stem:[1]. + +// vim: filetype=asciidoc ai expandtab tw=0 ts=4 sts=2 sw=2 diff --git a/appendices/basisuah66i-gdata.adoc b/appendices/basisuah66i-gdata.adoc new file mode 100644 index 0000000..cef8e01 --- /dev/null +++ b/appendices/basisuah66i-gdata.adoc @@ -0,0 +1,77 @@ +[appendix#basisuah66i_gd] +== Basis UASTC HDR 6x6 Intermediate Global Data + +Basis UASTC HDR 6x6 Intermediate format combines encoding to the UASTC HDR 6x6 subset of ASTC, that can be easily transcoded to BC6H unsigned, with lossless supercompression. +The format uses a small number of variable bit length command codes which can output one or more blocks, and which can reuse parts of previously encoded blocks. +Because of the variable size of each image Basis UASTC HDR 6x6 Intermediate creates a global data structure that contains an array of _image descriptors_ with the offset within its mip level and the length of the data for that image. + + +[[basisuah66i_global_data_structure]] +.Basis UASTC HDR 6x6 Global Data Structure +[source,c,subs="+quotes,+attributes,+replacements"] +---- +ImageDesc[imageCount] imageDescs; +---- + +`ImageDesc` is the following structure. + +.ImageDesc +[source,c] +---- +UInt32 rgbSliceByteOffset +UInt32 rgbSliceByteLength +UInt32 rgbSliceType +---- + +Descriptions in the `imageDescs` array are in the order layer, face and z_slice as if arranged by the following pseudo code. +[source,c] +---- +for each level in max(levelCount, 1) + for each layer in max (layerCount, 1) + for each face in faceCount // 1 or 6 + for each z_slice in max((pixelDepth of level), 1) +---- + +`imageCount` is the total number of images in the Mip Level Array. + +[TIP] +==== +`imageCount` may be calculated as follows: +[source,c] +---- +int imageCount = max(layerCount, 1) * faceCount * layerPixelDepth; + +// where layerPixelDepth can be derived as +int layerPixelDepth = max(pixelDepth, 1); +for(int i = 1; i < levelCount; i++) + layerPixelDepth += max(pixelDepth >> i, 1); +---- +==== + +There must be no trailing bytes in the global data section after the array of image descriptors, i.e., the following condition must always be true: +[source,c] +---- +sgdByteLength == imageCount * 12 +---- + +[[basisuah66i_image_desc]] +=== ImageDesc +==== rgbSliceByteOffset, rgbSliceByteLength +The offset of the start of the RGB slice within the <> of its mip level and its byte length. The offset of <> within the file is given in the <<_level_index,Level Index>>. + +`rgbSliceByteLength` must not be zero. + +`rgbSliceByteOffset + rgbSliceByteLength` must not be greater than the byte length of the corresponding mip level. + +[[basisuah66i_rgbSliceType]] +==== rgbSliceType +The combined ID field containing the entropy profile and stream semantic version used in the bitstream for this slice. +The least significant 16-bits (the first two bytes) of this value must equal the first 16-bits of the bitstream for this slice as described in the https://github.com/BinomialLLC/basis_universal/wiki/UASTC-HDR-6x6-Intermediate-File-Format-(Basis-GPU-Photo-6x6)#header[header section] of the bitstream specification. +The most significant 16-bits (the last two bytes) must be 0. +[NOTE] +.Rationale +==== +Implementations can use this field to check for an unsupported version without having to load the data. +==== + +// vim: filetype=asciidoc ai expandtab tw=0 ts=4 sts=2 sw=2 diff --git a/docinfo.html b/docinfo.html index 49d15e3..630882a 100644 --- a/docinfo.html +++ b/docinfo.html @@ -4,11 +4,15 @@ /* Put Khronos ribbon on left side */ background-attachment: fixed; background-image: url(images/logo-spec.svg); - background-position: left top; + background-position: right top; background-repeat: no-repeat/*, no-repeat*/; - /* Override default Asciidoctor margin settings to center the page. */ - margin: 2em auto 2em auto; - max-width: 60em; + /* If wider than in #content below, this adds extra margin. */ + max-width: 100em; +} + +#content { + /* Override max from khronos.css. */ + max-width: 62.5em } div.legal p { diff --git a/ktxspec.adoc b/ktxspec.adoc index 50765b0..e1ba414 100644 --- a/ktxspec.adoc +++ b/ktxspec.adoc @@ -2,7 +2,7 @@ :author: Mark Callow :author_org: Edgewise Consulting :description: Specification of a container format for GPU textures. -:docrev: 4 +:docrev: 5 (draft) :ktxver: 2.0 :revnumber: {ktxver}.{docrev} :revdate: {docdate} @@ -16,14 +16,8 @@ // names and indented blocks, overrides the unreadable equations. //// :stem: latexmath -// Disabling toc and numbered attributes doesn't work with a2x. -// Use the xsltproc options instead. -:toc!: -// a2x: --xsltproc-opts "--stringparam generate.toc nop" +:toc: left :numbered: -// a2x: --xsltproc-opts "--stringparam chapter.autolabel 0" -// a2x: --xsltproc-opts "--stringparam section.autolabel 0" -//:max-width: 50em :data-uri: :icons: font :source-highlighter: prettify @@ -96,6 +90,8 @@ Document Revision 3 approved by the 3D Formats WG Feb 14th, 2024. Document Revision 4 approved by the 3D Formats WG Feb 19th, 2025. +Document Revision 5 in drafting. + == Introduction This document describes the KTX^™️^ file format version 2.0, hereafter @@ -327,12 +323,12 @@ in {url-vk-docs-sp-chapters}/formats.html[Formats] on <>. Use of the value `VK_FORMAT_UNDEFINED` (0) is only permissible when the format of the data is a not a recognized Vulkan format, such -as in the case of the universal texture formats. In this case -information about the format must be provided by the Data Format -Descriptor and, in cases where the format is known to another GPU -API, the KTX writer must include one or more of the metadata items -described in <>. Some permissible uses are -outlined within this specification and summarized in +as in the case of some of the universal texture formats. In this +case information about the format must be provided by the Data +Format Descriptor and, in cases where the format is known to another +GPU API, the KTX writer must include one or more of the metadata +items described in <>. Some permissible +uses are outlined within this specification and summarized in <>. The table in <> gives the mapping for all `VkFormat` @@ -539,7 +535,7 @@ If `faceCount` is equal to 6, `pixelHeight` must be equal to `pixelWidth`, and `pixelDepth` must be 0. `pixelHeight` must not be 0 for block-compressed formats, including -BasisLZ/ETC1S and UASTC. +BasisLZ/ETC1S, UASTC, UASTC HDR 4x4 and UASTC HDR 6x6 Intermediate. `pixelDepth` must not be 0 for block-compressed formats that have block depth greater than 1. @@ -633,7 +629,8 @@ supercompression. | 1 | BasisLZ | <> | <> | 2 | Zstandard | <> | n/a | 3 | ZLIB | <> | n/a -| 4・・・0xffff | Reserved^1^ | | +| 4 | Basis UASTC 6x6 Intermediate | <> | <> +| 5・・・0xffff | Reserved^1^ | | | 0x10000・・・0x1ffff | Reserved^2^ | | | 0x20000・・・0xffffffff | Reserved^3^ | | |=== @@ -661,11 +658,13 @@ inflated from the scheme prior to GPU sampling. [TIP] ==== -LZW-style lossless supercompression, e.g, scheme 2, is generally -ineffective on the block-compressed data of GPU texture formats. -It is best reserved for use with uncompressed texture formats or -with block-compressed data that has been specially conditioned for -LZW compression such as by _Rate-distortion Optimization_ <>. +Depending on the content of the image, LZW-style lossless +supercompression, e.g, scheme 2, may be ineffective on the +block-compressed data of GPU texture formats. Compressibility can +be improved by specially conditioning the data for LZW compression +such as with _Rate-distortion Optimization_ <>. Such conditioning +is an encoding detail which is transparent to the user of the +texture. BasisLZ internally uses a universal block-compressed texture format and Rate-distortion Optimization. Encoding to the @@ -784,6 +783,21 @@ transcode target format is selected. retain pre-deflation color space information and indicate which components are present. See <>. +[#basisuah66_scheme] +===== Basis UASTC HDR 6x6 Intermediate +* <> + describes the bitstream for a single image (slice). +* UASTC slice locations within a mip level are defined exclusively + by the corresponding `ImageDesc` structures from the + <>. The same slice data may be + used by multiple `ImageDesc` structures within the mip level. +* <<_vkformat,`vkFormat`>> must be `VK_FORMAT_UNDEFINED` (0x00). + The <<_data_format_descriptor,_Data Format Descriptor_>> must + retain the pre-deflation color space information. + See <>. +* `<<_levelsp_uncompressedbytelength,levels[p].uncompressedByteLength>>` + must be 0. + [#vendorSchemeNotes] //// // A PR registering a new vendor supercompression scheme must add @@ -971,8 +985,8 @@ _dfDescriptorBlock_. `KHR_DF_MODEL_YUVSDA` or the matching block compressed color model listed in <> {url-df-spec}#CompressedFormatModels[Section 5.6] or its successors, currently `KHR_DF_MODEL_BC1A` to - `KHR_DF_MODEL_UASTC`. `KHR_DF_MODEL_YUVSDA` should be used for - all non-prohibited `+*_422_*+` formats. + `KHR_DF_MODEL_UASTC_6x6_HDR`. `KHR_DF_MODEL_YUVSDA` should be + used for all non-prohibited `+*_422_*+` formats. * If <<_vkformat,`vkFormat`>> is one of the `+*_SRGB{,_*}+` formats, `transferFunction` must be `KHR_DF_TRANSFER_SRGB`. * If <<_vkformat,`vkFormat`>> is not one of the `+*_SRGB{,_*}+` formats @@ -1098,17 +1112,18 @@ The Universal ASTC image format (UASTC) is indicated by `colorModel` {url-df-spec}#KHR_DF_MODEL_UASTC[_KHR_DF_MODEL_UASTC_] of <>. Images in this format must be transcoded to a GPU-supported block-compressed format or decoded to a GPU-supported uncompressed -format before being uploaded to and sampled by a GPU. UASTC images -can be supercompressed with Zstandard (`supercompressionScheme` = -2) with or without first conditioning the data with Rate-distortion -Optimization. If supercompression is used, the DFD must follow the -rules described in the next subsection. +format before being uploaded to and sampled by a GPU. UASTC images +can be supercompressed with any scheme except BasisLZ +(`supercompressionScheme` = 1) and Basis UASTC HDR 6x6 Intermediate +(`supercompressionScheme` = 4). If supercompression is used, the +DFD must follow the rules described in the next +<>. + -This color model provides channel Ids, e.g. `KHR_DF_CHANNEL_UASTC_RGB` -that must be used to indicate the effective number of components -in the data. Consumers use this information to help select a -transcode target. The following ids are valid and must be used for -the type of data indicated. +This color model has a single channel with several possible ids, +e.g. `KHR_DF_CHANNEL_UASTC_RGB`, that are used to indicate the +effective number of components in the data. Consumers use this +information to help select a transcode target. The following ids +are valid and must be used for the type of data indicated. + [width=100%,align=center,cols="<30,^10,<60",options=header] |=== @@ -1140,6 +1155,66 @@ The bitstream of the UASTC data is described in Chapter 25 {url-df-spec}#UASTC[_UASTC Compressed Texture Image Format_] of <>. +Basis Universal UASTC HDR 4x4 Format:: +The Universal ASTC HDR 4x4 image format (UASTC HDR 4x4) is a strict +RGB-only subset of ASTC HDR 4x4. `vkFormat` must be set to +`VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK` (= 1000066000). The DFD must be +as described in Section 5.6.10 +{url-df-spec}#KHR_DF_MODEL_ASTC[_KHR_DF_MODEL_ASTC_] of <> +but `colorModel` must be `KHR_DF_MODEL_UASTC_HDR_4x4` (= 167), +`texelBlockDimension[01]` must be 3 and `sampleLower` must be 0. +If the GPU does not support `VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK`, +images in this format must be transcoded to a GPU-supported +block-compressed format like `VK_FORMAT_BC6H_UFLOAT_BLOCK` or decoded +to a GPU-supported uncompressed format like +`VK_FORMAT_E5B9G9R9_UFLOAT_PACK32` or `VK_FORMAT_R16G16B16A16_SFLOAT` +before being uploaded to and sampled by a GPU. UASTC HDR 4x4 images +can be supercompressed with any scheme except BasisLZ +(`supercompressionScheme` = 1) and Basis UASTC HDR 6x6 Intermediate +(`supercompressionScheme` = 4). If supercompression is used, the +DFD must follow the rules described in the next +<>. ++ +This color model has a single channel with id +`KHR_DF_CHANNEL_UASTC_HDR_4x4_RGB` (= 0) for which the +`KHR_DF_SAMPLE_DATATYPE_FLOAT` qualifier (= 0x80) must be set. ++ +The bitstream of the UASTC HDR 4x4 data is described in <>. + +Basis Universal UASTC HDR 6x6 Format:: +The Universal ASTC HDR 6x6 image format (UASTC HDR 6x6) is a custom +format based off ASTC HDR 6x6 that underlies the <> supercompression scheme +(`supercompressionScheme` = 4). `vkFormat` must be set to +`VK_FORMAT_UNDEFINED` (= 0). The DFD must be as described in Section +5.6.10 {url-df-spec}#KHR_DF_MODEL_ASTC[_KHR_DF_MODEL_ASTC_] of +<> but `colorModel` must be `KHR_DF_MODEL_UASTC_6x6_HDR` (= +168), `texelBlockDimension[01]` must be 5 and `sampleLower` must +be 0. Images in this format are RGB-only and are always supercompressed +with the <> +scheme and must be inflated and transcoded to a GPU-supported +block-compressed format like `VK_FORMAT_BC6H_UFLOAT_BLOCK` or +`VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK` or decoded to a GPU-supported +uncompressed format like `VK_FORMAT_E5B9G9R9_UFLOAT_PACK32` or +`VK_FORMAT_R16G16B16A16_SFLOAT` before being uploaded to and sampled +by a GPU. Because UASTC HDR 6x6 Intermediate images are supercompressed, +the DFD must follow the rules described in the next +<>. ++ +This color model has a single channel with id +`KHR_DF_CHANNEL_UASTC_HDR_6x6_RGB` (= 0) for which the +`KHR_DF_SAMPLE_DATATYPE_FLOAT` qualifier (= 0x80) must be set. ++ +The bitstream of UASTC HDR 6x6 data compressed with _UASTC HDR 6x6 +Intermediate_ is described in <>. + +[NOTE] +==== +Because void-extent blocks in ASTC HDR can have negative values the +Vulkan format names for ASTC HDR use `SFLOAT` although regular ASTC +HDR blocks cannot have negative values. No UASTC HDR value can be < 0. +==== + [[etc1s]] Basis Universal ETC1S Format:: The ETC1S image format is indicated by `colorModel` `KHR_DF_MODEL_ETC1S` @@ -1148,8 +1223,9 @@ DFD must be as described in Section 5.6.11 {url-df-spec}#KHR_DF_MODEL_ETC1S[_KHR_DF_MODEL_ETC1S_] of <>. Because ETC1S does not support an alpha component, Basis Universal uses 2 _slices_, (_planes_ in DFD-speak) to represent -RGBA images. This color model provides the following channel ids -that must be used to indicate the use of a slice. +RGBA images. In this color model each slice has a single channel +with the following possible channel ids that must be used to indicate +the use of a slice. + [width=100%,align=center,cols="<30,^10,<60",options=header] |=== @@ -1194,8 +1270,8 @@ for ETC1S streams such as BasisLZ must be used. Images must be inflated and transcoded to a GPU-supported block-compressed format or decoded to a GPU-supported uncompressed format before being uploaded to and sampled by a GPU. Because ETC1S images are -supercompressed, the DFD must follow the rules described in the -next subsection. +supercompressed, the DFD must follow the rules described in +the next <>. TIP: Whether the image has 1 or 2 slices can be determined from the DFD's sample count. @@ -1216,6 +1292,7 @@ submitting the data to a Basis encoder then the DFD must not have a sample with a channelType that indicates it is alpha. ==== +[[dfdSupercompressed]] ===== DFD for Supercompressed Data When `<<_supercompressionscheme,supercompressionScheme>>` is not 0 the _dfDescriptorBlock_ must preserve the `colorModel`, `transferFunction`, @@ -2005,6 +2082,61 @@ seconds is stem:[\texttt{duration} / \texttt{timescale}]. This metadata entry must not be used together with <>. +=== KTXmapRange +When the payload is a floating point format with a reduced range, +such as `ASTC_*\_SFLOAT_BLOCK`, `BC6H_[S,U]FLOAT_BLOCK`, +`B10G11R11_UFLOAT_PACK32`, `E5B9G9R9_UFLOAT_PACK32` or +`R16[G16[B16[A16]]]_SFLOAT` and data is input from a source with +32-bit floating point data, such as a .exr file, the values in the +source may be mapped to the more limited range. KTX file writers +may indicate the mapping by using the key + +- `KTXmapRange` + +The value is 8 bytes representing two IEEE 754 single-precision +floating-point values: +[source,c] +---- +Float32 scale +Float32 offset +---- +These values must be finite. + +An application can restore the original 32-bit float value with +[stem] ++++++ +\textit{effective} = \textit{sampled} \times \textit{scale} + \textit{offset} ++++++ +where stem:[\textit{sampled}] is the value retrieved from the texture after any +filtering. + +[TIP] +==== +This formula allows decoders to use a single fused multiply-add +instruction to apply the scale and the offset. +==== + +This metadata entry may be used with: + +* any floating point format. In the case of a combined depth-stencil +format, e.g. `D32_SFLOAT_S8_UINT` it must be applied only to the +depth component. + +* any linear `*_UNORM` or `*_SNORM` format. + +It is incompatible with and must not be used with: + +* non-linear formats such as those with sRGB encoding, + +* true integer or boolean formats. + +If `KTXmapRange` appears in a KTX file containing these formats, the +file is invalid. + +Metadata must be applied before swizzling and must be applied only to +existing components. E.g, if blue and alpha are missing they must remain +as 0.0 and 1.0. + == An example KTX version 2 file: [source,c] @@ -2326,6 +2458,11 @@ Bradner. IETF Network Working Group, March 1997. Collet, M. Kucherawy, Ed. Internet Engineering Task Force (IETF), October 2018. +- [[[UASTCHDR44]]] + https://github.com/BinomialLLC/basis_universal/wiki/UASTC-HDR-4x4-Texture-Specification-v1.0[UASTC + HDR 4x4 Texture Specification v1.0]. + Binomial Llc Wiki, Jan 2025. + - [[[VULKAN]]] {url-vk-spec}[Vulkan^®^ 1.n.p - A Specification]. The Khronos Group, February 2025. @@ -2425,6 +2562,10 @@ include::appendices/basislz-gdata.adoc[] include::appendices/basislz-bitstream.adoc[] +include::appendices/basisuah66i-gdata.adoc[] + +include::appendices/basisuah66i-bitstream.adoc[] + include::appendices/vendor-metadata.adoc[] [appendix] @@ -2533,7 +2674,7 @@ include::appendices/vendor-metadata.adoc[] - Prohibit YCbCr 2-plane 444 formats recently added to Vulkan. - Allow `A8B8G8R8*PACK32` formats. -| {docrev} | {revdate} | - Relax restrictions on +| 4 | 2025-02-20 | - Relax restrictions on `colorPrimaries` values. - Fix bit size of descriptorType in dfdBlock. @@ -2548,8 +2689,11 @@ include::appendices/vendor-metadata.adoc[] functions. - Update KDFS references to 1.4 and make the links active. - - Clarify that KHR_DF_SAMPLE_DATATYPE_LINEAR +| {docrev} | {revdate} | - Clarify that KHR_DF_SAMPLE_DATATYPE_LINEAR can vary from format definition. + - Specify how to carry the new + Binomial HDR formats. + - Add table of contents. |=== [discrete]