-
-
Notifications
You must be signed in to change notification settings - Fork 36.2k
KTX2Loader: Add VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK_EXT
#31689
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
KTX2Loader: Add VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK_EXT
#31689
Conversation
|
Thanks @hybridherbst! I think what's implemented in this PR is support for plain ASTC 6x6 without the fallback to BC6H or RGBA16. We should certainly add the support for plain ASTC 6x6, but it's maybe not what you intended based on the "uastc" in the filename? The Basis Universal subset of ASTC HDR is identified by a specific color model in the header: three.js/examples/jsm/loaders/KTX2Loader.js Lines 426 to 442 in ca3194a
I haven't tested but I assume it's the same color model for 6x6 as for 4x4, and you could just add one more vkFormat to the check above? Related: Aside — do these files look as expected (same color as non-HDR textures) on the ktx2 example page? I'm not sure I understand the implications of the |
|
Hi @donmccurdy, I was confused by that from the BasisU docs as well, since there's a mix of namings – sometimes UASTC HDR 6x6 is called just ASTC HDR 6x6 but still can be transcoded to BC6H, see https://github.com/BinomialLLC/basis_universal?tab=readme-ov-file#supported-hdr-gpu-texture-formats. The HDR support notes here also make me believe the files are "uastc": https://github.com/BinomialLLC/basis_universal/wiki/UASTC-HDR-6x6-Support-Notes
In fact, when I run basis_uastc_hdr4x4.ktx2 basis_uastc_hdr6x6.ktx2 I agree that this conflicts with the code snippet you posted… If you want to reproduce this, I added them to your KTX2-Samples repo as well: |
|
I just noticed that the 6x6 compression logs "Mode: ASTC 6x6 HDR" whereas the 4x4 compression logs "Mode: UASTC 4x4 HDR". I also tried with an EXR input file with % basisu -hdr_6x6 basis_uastc_hdr6x6.png
Basis Universal LDR/HDR GPU Texture Compression and Transcoding System v1.60.0
Copyright (C) 2019-2025 Binomial LLC, All rights reserved
No SSE, Multithreading: 1, Zstandard support: 1, OpenCL: 0
Processing 1 total file(s)
Processing source file "basis_uastc_hdr6x6.png"
Read source image "basis_uastc_hdr6x6.png", 40x40
Total slices: 1
Slice: 0, alpha: 0, orig width/height: 40x40, width/height: 40x40, first_block: 0, image_index: 0, mip_level: 0, iframe: 0
Mode: ASTC 6x6 HDR , Base Level: 0, Highest Level: 1, Lambda: 0.000000, REC 2020: false
Blurring image
Transforming to ITP
Wrote output .basis/.ktx2 file "basis_uastc_hdr6x6.ktx2"
Compression succeeded to file "basis_uastc_hdr6x6.ktx2" size 573 bytes in 0.006 secs
Total successes: 1 failures: 0% basisu -hdr_4x4 basis_uastc_hdr4x4.png
Basis Universal LDR/HDR GPU Texture Compression and Transcoding System v1.60.0
Copyright (C) 2019-2025 Binomial LLC, All rights reserved
No SSE, Multithreading: 1, Zstandard support: 1, OpenCL: 0
Processing 1 total file(s)
Processing source file "basis_uastc_hdr4x4.png"
Read source image "basis_uastc_hdr4x4.png", 40x40
Total slices: 1
Slice: 0, alpha: 0, orig width/height: 40x40, width/height: 40x40, first_block: 0, image_index: 0, mip_level: 0, iframe: 0
Mode: UASTC 4x4 HDR Level 1
Wrote output .basis/.ktx2 file "basis_uastc_hdr4x4.ktx2"
Compression succeeded to file "basis_uastc_hdr4x4.ktx2" size 827 bytes in 0.009 secs
Total successes: 1 failures: 0@richgel999 Is that expected? Is there a way to differentiate "regular ASTC 6x6 HDR" from "UASTC 6x6 HDR" like for the 4x4 version? |
|
@hybridherbst hoping to avoid being blocked here, maybe we can remove the examples from this PR and just merge the changes to KTX2Loader? Those changes look good regardless, it's just the validity of the samples I'm still a little confused about. |
7af4854 to
c3ad482
Compare
|
Sure! I removed the 6x6 example and kept the 4x4 example because I believe that one is already correct (and was already working/supported before this PR). |
|
Thanks for rolling with the feedback/questions, looks good to me now! :) And yeah, not worried about color difference on the ETC1S example at this point. Possibly my encoding script could use better defaults. |
There are 2 different modes for 6x6 HDR (both use the same encoder however):
For 4x4 HDR:
Note all the HDR encoders support automatically upconverting LDR/SDR to HDR images, by converting them to normalized linear light and multiplying by 80-100 nits. (This stores the exit radiances an sRGB monitor would emit into a scene referenced HDR file. There doesn't seem to be a standard multiplier, so we use 100 nits.) The exact upconversion multiplier used is stored in the KTX2 file and is configurable via command line or in the compressor's API.
Yes, if you compress the same .EXR to -hdr_4x4, -hdr_6x6, and -hdr_6x6i, and unpack each .KTX2 file using the "basisu" tool, you'll see the various fields that get placed into the KTX2 header/DFD. -hdr_4x4: -hdr_6x6: -hdr_6x6i: This output from the tool comes from examining the KTX2 header and the DFD. m_header.m_vk_format will equal basist::KTX2_FORMAT_ASTC_4x4_SFLOAT_BLOCK for 4x4 HDR, or KTX2_FORMAT_ASTC_6x6_SFLOAT_BLOCK for 6x6 HDR. The DFD's color model is examined by the transcoder to determine the type of file. A DFD color model of KTX2_KDF_DF_MODEL_ASTC_HDR_6X6_INTERMEDIATE is the HDR 6x6 intermediate format. For this format, the KTX2 header's vk format will be KTX2_VK_FORMAT_UNDEFINED. (See the code transcoder/basisu_transcoder.cpp, method ktx2_transcoder::init().) The actual constants can be found by grepping the transcoder's source files. Hope this helps. |
|
Thank you @richgel999 for the additional info. I believe I've mostly read these bits of information on your docs/wiki pages already – great that these exist! What I'm still confused about is the naming and what is supposed to be transcodable. I think my main confusion is "Why is nothing here named UASTC_HDR_6x6"?
Some links I read through: KhronosGroup/KTX-Specification#216 (comment), BinomialLLC/basis_universal#381 @donmccurdy the transcoder errors look like this when I override
|
|
Both
The implementation and the validation error make sense to me based on https://registry.khronos.org/KTX/specs/2.0/ktxspec.v2.html#basislz_gd — is there an expected difference versus the previous (LDR) BasisLZ supercompression scheme not yet in the KTX2 spec, or another document on the supercompression scheme? |
|
I believe this is the most comprehensive writeup: As the note on the top states, it's still a draft, I believe there are still some discussions on the spec: |
|
Ah, thanks! I think the first link describes the block-compression format and not the KTX2 SGD headers. The second link is probably where the SGD description might land, but isn't there yet. This might not yet be at a stage where I want to make changes in ktx-parse. It would be helpful to have a release candidate (or similar) for any KTX2 specification updates. |
The exact names for the HDR modes has been in flux. The "U" prefix was added to the docs but not everywhere in the code yet.
This data (ASTC HDR 6x6 mode) is just 100% standard ASTC HDR data - so no "U" prefix needed. The basisu encoder can output either highest quality or RDO preconditioned data (using a non-zero Lambda setting to control the rate-distortion tradeoff). The transcoder can unpack this data and give you either BC6H, plain ASTC (just a memcpy), or a variety of uncompressed formats (RGB9E5, half float, etc.). This type of texture data is not specific to our system or encoder (because the block data follows the ASTC HDR spec exactly).
The DFD's we write for the various HDR modes are in
I'll be adding the "U" prefix here to the next release (scheduled for early Jan.). This is our custom intermediate format for 6x6 HDR, which is directly based off ASTC HDR 6x6 but with a higher level structure to reduce per-block overhead/redundancies. This format is locked in stone (i.e. we won't be breaking compatibility). It gets substantially higher compression than plain ASTC HDR 6x6+LZ. Note that all the HDR data generated by the basisu library is transcodable to BC6H, or various uncompressed HDR formats, or you can get plain ASTC 4x4 or 6x6 HDR. |
The HDR 6x6 intermediate mode is not in the KTX2 spec yet, so it's going to fail validation. This is not true of the plain ASTC HDR 6x6 mode, which is just 100% standard ASTC HDR texture data. Unfortunately, HDR imaging is still not super well understood by most developers, so there hasn't been a big push to standardize the format yet. Scene-referenced half-float HDR at 1.5-2.5 bpp is far ahead of the adoption curve. We're releasing another major update to the library in early Jan., then we'll see if we can get a few major tech corps to help push for standardization. I am in contact with Mark Callow at Khronos and we're talking about this. Note that the HDR intermediate format is already being utilized by at least one major corporation at a large scale, FWIW. |
Thanks @richgel999! Hoping to confirm what you mean here. I understand there's a big distinction between HDR imagery intended for output to display, and scene-referred floating-point RGB stimulus data that happens to be stored in textures, intended for use throughout a rendering pipeline. I'd consider HEIC or UltraHDR suitable quality-wise for HDR images but very lossy for floating-point data, given perception-based assumptions in compression. I'd consider OpenEXR suitable in quality for both uses, but larger than necessary in filesize for HDR images. Does a similar distinction hold up for (U)ASTC HDR? I believe BasisU supports the "HDR imagery" case, primarily? |



Related issue: #31686
Description
Adds support for ASTC_6x6_SFLOAT_BLOCK in KTX2Loader. 4x4 blocks were already there.
This contribution is funded by Needle