KhronosGroup / 3D-Formats-Guidelines

Guidelines for artists and developers using Khronos Group 3D formats.
Other
125 stars 18 forks source link

ETC1S desktop decoding guidelines may be inefficient #25

Open zeux opened 2 hours ago

zeux commented 2 hours ago

The guidelines for ETC1S format suggest that the applications should decode to BC7 (if available) with a fallback to BC1 (single-slice) and BC3 (dual-slice).

I'm curious, where does this recommendation come from? Intuitively, this seemed wrong to me because ETC1S is a comparatively weak format, and BC1 is usually able to match or slightly surpass its color encoding quality. Encoding a single-slice image into BC7 results in 8 bits per pixel; encoding into BC1 results in 4 bits per pixel (same as ETC1/2), which is more memory friendly.

I tried to gather a little bit of data to help validate this intuition; this is somewhat cumbersome since basisu no longer supports "-bench" command, but you can do this by encoding the texture into .basis file (basisu -basis file.png), unpacking it back (basisu -unpack file.basis), and using ImageMagick compare -metric psnr on the original .png and every unpacked image. I looked at the various diffuse textures for FlightHelmet asset (https://github.com/KhronosGroup/glTF-Sample-Assets/tree/main/Models/FlightHelmet/) and produced the following results:

Texture ETC2 PSNR ASTC PSNR BC1 PSNR BC7 PSNR
FlightHelmet_Materials_GlassPlasticMat_BaseColor.png 37.869 37.8623 37.695 37.7077
FlightHelmet_Materials_LeatherPartsMat_BaseColor.png 35.0998 35.1131 35.0543 35.0182
FlightHelmet_Materials_LensesMat_BaseColor.png 11.1624 11.1609 11.1557 11.1664
FlightHelmet_Materials_MetalPartsMat_BaseColor.png 36.1754 36.1807 36.0521 36.1625
FlightHelmet_Materials_RubberWoodMat_BaseColor.png 35.5046 35.521 35.3116 35.4136

BC7 here is actually almost always slightly worse than BC1, with the exception of LeatherPartsMat; regardless a 0.04 delta in PSNR should never be worth doubling the texture memory.

(I'm not really claiming that FlightHelmet base color textures are representative, but I'm not sure if there's more complete data that motivated the recommendation and what that data is)

For dual-slice source images, BC3 and BC7 have the same memory footprint, so in that case I don't have a problem with the current guidelines as I assume the quality delta will be minimal and the size delta is non-existent.

cc @donmccurdy as this came out of a discussion on three.js PR; three.js currently follows the guidelines and as such uses BC7 for decoding on desktop when that is supported. This results in 2x memory consumption for single-slice textures vs what is optimal, which affects memory consumption and the time to upload the compressed assets to GPU. I haven't measured the transcode time and assume it's close, but maybe that's not the case?

zeux commented 2 hours ago

For completeness also adding ORM and normal map for one material from the same asset (normal map encoded with -normal_map flag); the conclusion here is the same as above.

Texture ETC2 PSNR ASTC PSNR BC1 PSNR BC7 PSNR
FlightHelmet_Materials_MetalPartsMat_OcclusionRoughMetal.png 24.8572 24.8601 24.8328 24.8602
FlightHelmet_Materials_MetalPartsMat_Normal.png 32.8355 32.8311 32.7714 32.8121
lexaknyazev commented 2 hours ago

Please do not confuse dual-slice as RGB + A and dual-slice as Red-Green. BC5 is applicable only to the latter case. The former is handled with either BC7 or BC1/BC3.

The observed transcoding quality difference between BC1 and BC7 is a bit unexpected. I'll take a look.

zeux commented 2 hours ago

@lexaknyazev BC5 was a typo and I meant BC3 (aka DXT5) above. Edited to correct this.