-
-
Notifications
You must be signed in to change notification settings - Fork 21k
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
Corruption on VRAM-compressed texture mipmaps (S3TC compression) #49981
Comments
I don't know exactly how long this has been an issue, but it seems to have been around for a while at least. |
A bit more follow-up info, the main reason this particular texture seems to fail is due to it being non-power-of-two. I've also been informed that this particular issue is likely specific to S3TC compression. |
It is probably just that the texture compression works in blocks (e.g. 4x4), so you will often get compression artifacts across these borders in the base level or mipmaps. As you say, using a power of 2 texture size makes them less likely. |
The khronos OpenGL wiki claims the following:
From what I can tell, on OpenGL, there seems to be no hard requirement about dimensions of S3TC compressed textures being powers of two or multiples of four... However, apparently DX11 and WebGL impose some limitations to prevent it [except for 2x2 and 1x1 mipmaps since those are special]. I can't find any info on Vulkan, however. The problem Godot has is it also allows mipmaps for non-power of two textures... which means, even if LOD 0 is a multiple of 4, some of the lower resolution LODs might be odd dimensions. I don't know if there is a good way around this contradiction, other than either ignore the DX11 requirement, or block VRAM Compression for any non-power of two texture with mipmaps enabled? Just to see what other engines do in these cases, interestingly, Unity completely doesn't allow mipmaps for non-power of two textures (it defaults to resizing to nearest power-of-two when mipmaps are enabled), and it also does not allow compression for non-multiple-of-4... so they went the easy route of just not allowing this case. Regardless of what is compatible with ANGLE and DX11, it seems fair to me that Godot shouldn't produce incorrect results or crash on non-multiple-of-4 S3TC compression. So while Godot might want to consider applying stricter rules, there's still a bug here that should be fixable, I would think. See also: #48509 |
I tested importing a 958x552 image in both Godot 3 and 4 to compare the results. Godot 3: Creates a DXT1 format texture, looks correct. It seems Godot 4's DXTn encoder isn't padding the last tiles. (958 should be padded out to 960) ================================ Godot 3.3 has DXTn compression in module_compress_squish.cpp: godot/modules/squish/image_compress_squish.cpp Lines 187 to 197 in 9d0e0fe
which calls out to the third-party squish module for the actual compression: godot/thirdparty/squish/squish.cpp Lines 181 to 223 in 9d0e0fe
Squish is given the original unaligned width/height, not a padded width/height, and it pads the last 4x4 tile correctly. ================================ Godot 4 has DXTn compression in image_compress_etcpak.cpp: godot/modules/etcpak/image_compress_etcpak.cpp Lines 148 to 178 in e5c6c77
_compress_etcpak() ends up calling either CompressDxt1Dither() or CompressDxt5() with a mipmap size value that's been aligned to 4 pixels. However, this is telling the compression function that the original image is (in this case) 960 pixels, but it's actually 958 pixels. This is why the image ends up broken. |
It looks like Unreal doesn't even let you use mipmaps if your texture is non power of two https://docs.unrealengine.com/4.27/en-US/RenderingAndGraphics/Textures/Importing/ (also tested using the texture from OP) From the Unity docs: https://docs.unity3d.com/560/Documentation/Manual/ImportingTextures.html
So I agree, we porbably need to be stricter about texture dimensions as well. In the short term, we should give the user an appropriate error and disable mipmaps. In the medium run, we should have a nicer UX that allows users to automatically pad nonpot textures |
Regarding being strict, I agree that it's better to fail the import tell the user to fix their art so they aren't surprised when it's blurry (due to scaling by a few pixels. I like that Unity lets you choose how to deal with power-of-two. Currently, in Godot, you can use the "Max Size" setting but that resizes in both dimensions, and it applies a separate resize from the power-of-two one, effectively causing two resizes, so it might not be optimal (since both width and height might need to be resized differently). About your comment, two things to note:
My draft PR at #46931 only tries to restore this old behavior.
The old "modules/etc" library took in width&height in pixels, so I think it somehow handled this case, while "etcpak" is more strict. Once I add the code to scale Nx2 and Nx1 buffers to multiple of 4, I'll submit that PR. |
Godot version
eb318d3
System information
Windows 10, Vulkan, Nvidia GTX 1080 (471.11)
Issue description
It appears that the mipmaps of textures imported as VRAM Compressed can appear with odd skewing distortion.
The cube in the centre is using a texture with VRAM compression, while the other cubes are using the other four options. This issue does not appear to affect all textures, but it seems consistently broken on the example texture provided.
Steps to reproduce
Simply open the example project and observe the middle cube with VRAM Compressed version of the texture at an appropriate distance to see the mipmaps.
Minimal reproduction project
mipmaps.zip
The text was updated successfully, but these errors were encountered: