-
-
Notifications
You must be signed in to change notification settings - Fork 35.4k
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: Support transcoding UASTC HDR to BC6H and RGBA16 #29730
KTX2Loader: Support transcoding UASTC HDR to BC6H and RGBA16 #29730
Conversation
So on Linux with Firefox & AMD GPU (radeonsi), WebGL 2 exposes both EXT_texture_compression_bptc and WEBGL_compressed_texture_astc. However, ASTC isn't actually supported in hardware; radv exposes ASTC for... some reason (?).. and does a software decompress on upload from what I saw. Maybe this will change if Firefox switches to ANGLE, unsure if they have plans. As a consequence, on Linux this PR actually prints "format: RGBA_ASTC_4x4" when selecting the HDR format; additionally, the texture doesn't render correctly: If I force disable ASTC by patching KTX2Loader.js to pretend it isn't supported, then I get proper result with "RGB_BPTC_UNSIGNED" printed in the log: |
Is this part of the PR? I thought it's a separate commit but neither commits nor changes make it obvious as to where it is. |
Oh, re: radeonsi, correction: the underlying GL driver only exposes GL_KHR_texture_compression_astc_ldr and doesn't expose GL_KHR_texture_compression_astc_hdr. This is common on mobile hardware as well from I recall: some devices opt out of HDR support to conserve die area for decoding. Looks like WebGL exposes both via the same extension but requires to use |
@zeux thanks so much, this is really helpful! I'll update the PR to use
These lines were the problem... const ETC1S_OPTIONS = FORMAT_OPTIONS.sort( ( a, b ) => a.priorityETC1S - b.priorityETC1S );
const UASTC_OPTIONS = FORMAT_OPTIONS.sort( ( a, b ) => a.priorityUASTC - b.priorityUASTC ); ... because .sort() modifies the array in-place, the ETC1S options were sorted by UASTC priority. I've added a .filter() call in this PR, creating a new array for each format. |
Got it, thanks. After looking at this again, the behavior before this PR in the sample was: ETC1S selects BPTC, UASTC selects ASTC; the behavior after this PR is: ETC1S selects ETC2, UASTC selects ASTC. I feel like it might make sense to revisit the priorities separately given the hybrid behavior noted above; even before this change, I'm not sure that ETC1S selecting BPTC was the correct course of action (this results in 1 byte per pixel and uses BC7 which can reach a very high quality; I'd think that the quality of ETC1S encoding is sufficiently representable via DXT1/5 based on presence of alpha, which would save memory when textures don't have alpha, but I haven't checked this); after this change though, on Linux effectively I'm getting driver-uncompressed formats everywhere. |
WebGPU doesn't support ASTC HDR yet; there's a pending proposal for this via a separate feature string: gpuweb/gpuweb#3856 |
The target format priorities for ETC1S are based on this decision tree: Preferring BPTC over ETC2 was an accident, but I see your point that preferring BC1/3 over BC7 could be a better choice.
Ouch, do you mean that the ETC1S→ETC2 transcode path is being decompressed by drivers on Linux too? From your earlier comment I assumed this software decompress was only a concern when using ASTC HDR without checking the supported profiles, and wouldn't affect the non-HDR ETC1S and UASTC formats. |
Let's ignore the LDR behavior for the purpose of this PR, I need to look at the implications of what the driver is doing here wrt speed and quality... but Mesa actually has transcode paths internally now, so the texture should be recompressed into the relevant format. So ETC1S would go to the driver as ETC2 (and UASTC as ASTC) with minimal amount of transcoding via Basis, but the driver will then transcode from ETC2 to DXT1/5 (based on presence of alpha) or from ASTC to DXT5. (in the previous comments I was assuming the driver simply decompresses, but that's no longer the case as of a few years ago, as it now implements transcoding) The transcoding for ETC2 is basically a block recompression: it decompresses each block into 4x4 RGBA8 and then compresses it back using a custom compression code that's probably not super high quality but since the starting point is ETC1S which is much weaker than ETC2 it might be enough. The transcoding for ASTC likely loses a fair bit of quality, as it chooses DXT5 as the target format; that format is weaker than UASTC, and since transcoder is also doing a decompress-recompress with custom code it might have weaknesses of its own. From this perspective, your change would actually be beneficial for memory size on Linux... (as before the driver was just handed a BPTC texture, and now it's handed a ETC2 texture which it transcodes to DXT1) -- but I'd need to understand the quality implications here to see if we actually need priority tuning, aside from the BPTC-DXT1 question that I'd also need to test. |
Thanks again @zeux! Could I ask how you're producing the graphs above? Do you know whether that's possible on macOS? I've reverted the would-be fix for ETC1S, so the selected transcoding target should be the same before and after this PR. I also added an inline comment about the situation. Finally, I added the required check for As followups after this PR, we could:
Note that in WebGPU we don't currently have access to BPTC, so if similar emulation occurs there may be more issues to work through at some point. |
The graphs are captured from Firefox’s builtin profiler. I assume this is Linux specific: on macOS re: WebGPU, unless I’m mistaken, BPTC should be exposed under -bc feature along with other BCn formats? bc7-rgba-unorm format in this case (LDR) and bc6h-rgb-ufloat for HDR |
Oops I see – there is no |
Opened a new issue to track the remaining tasks: |
Related:
Adds support for transcoding UASTC HDR (unsigned half float), in the following order of preference:
I don't have a Windows desktop device available for testing. If someone would be able to check the
webgl_loader_texture_ktx2.html
example, select the "RGBA16 Linear (UASTC HDR)" sample in the dropdown, and then report the output to the JS Console, that would be much appreciated! On my macOS laptop, the output is...... but I'd expect a Windows device to select BC6H, instead.
Unrelated — I found a bug while working on the PR, which caused KTX2Loader to often select a non-optimal transcoding format, e.g. selecting BCn while ETC1/2 was also available. That issue is fixed in this PR as well, and should improve transcoding time and quality.Reverted for now; this caused other issues.To create Basis HDR textures you'll need the latest release of the
basisu
CLI, and a .exr input file: