Skip to content
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

VRAM texture compression always uses DXT5 codec #58012

Closed
kubajz22 opened this issue Feb 12, 2022 · 10 comments · Fixed by #76516
Closed

VRAM texture compression always uses DXT5 codec #58012

kubajz22 opened this issue Feb 12, 2022 · 10 comments · Fixed by #76516

Comments

@kubajz22
Copy link

Godot version

v4.0.alpha2.official [79077e6]

System information

Linux Mint 20.2, nvidia GTX 1650 with 470.103.01 driver

Issue description

If you import texture in Godot 3.x in VRAM compression mode (tested with 3.4.2), the compression method chosen depends on whether the image contains transparency or not. DXT1 for RGB images and DXT5 for those with alpha channel. This doesn't seem to work in v4.0_alpha2 and the engine always chooses DXT5 and also says the texture is RGBA8 when you double click it, regardless if it actually is or not.

Steps to reproduce

Import 2 images, one with alpha channel, one without.
Apply the compression as described above to both of them.
Godot 3 will choose different codecs, whereas Godot 4 will only use DXT5.

Minimal reproduction project

No response

@Calinou
Copy link
Member

Calinou commented Feb 12, 2022

cc @fire

By the way, does DXT5 look better for opaque images compared to DXT1? If so, there might be a reason for forcing the use of DXT5 on opaque images. However, this should be done on a per-image basis and should be opt-in (rather than opt-out).

@kubajz22
Copy link
Author

cc @fire

By the way, does DXT5 look better for opaque images compared to DXT1?

I don't think it does.. Perhaps the 'extra bits' could be used to improve the quality to some extent, but I didn't find much info on this.
What definitely is true though, is that the DXT5 takes up more VRAM.

@fire
Copy link
Member

fire commented Feb 13, 2022

To be clear the distinction is between dxt1/dx5 and bc7/astc.

I can provide samples of the quality difference which matters for normal maps.

@fire
Copy link
Member

fire commented Feb 16, 2022

Sorry I misread this issue.

Currently the etcpak always does DXT5.

So we need to devise a test case that triggers an optimization opportunity for compressed RGB vs RGBA. I chose always doing RGBA (dxt5) so need some help with a test project.

@kubajz22
Copy link
Author

Sorry I misread this issue.

Currently the etcpak always does DXT5.

So we need to devise a test case that triggers an optimization opportunity for compressed RGB vs RGBA. I chose always doing RGBA (dxt5) so need some help with a test project.

I'm not sure if I understand. The way I see it is that RGB images should always be compressed as DXT1 and RGBA as DXT5 to save space. Can't Godot check if there's an alpha channel present like it supposedly did in the past, which would trigger the optimization? I can provide a test project if needed but I'm not sure what needs testing.

@TokisanGames
Copy link
Contributor

TokisanGames commented Aug 9, 2022

@Calinou

By the way, does DXT5 look better for opaque images compared to DXT1?

@kubajz22

I don't think it does.. Perhaps the 'extra bits' could be used to improve the quality to some extent, but I didn't find much info on this. What definitely is true though, is that the DXT5 takes up more VRAM.

Kubajz is correct. Converting a quality 2k texture to DDS (via photoshop + intel DDS) to DXT1 and DXT5, then viewing a difference blend shows they are identical. However on the file system the first is 2.7mb and the latter 5.4mb. The memory requirements are also double as DXT1 is 4bpp, DXT5 is 8bpp.

This is a big deal for games with hundreds of textures like mine. DXT5 doubles the memory requirements for no gain and no option to turn it off. (For me individually, we manually convert all our textures to DDS, and it's a very good thing because the current auto conversion would screw us. We're already pushing up against 2GB of VRAM for some scenes. GD4 auto conversion would double that.)

This is still an issue in GD4 alpha 13. Can this be added to the GD4 roadmap?

@fire

I chose always doing RGBA (dxt5) so need some help with a test project.

There's no test project necessary. Just import two PNGs into the editor. One with alpha, one without. Import w/ vram compressed and you know it's working when the image with alpha displays as DXT5 in the inspector and the opaque one displays DXT1. This is what occurs in GD3, which was able to detect the image type.

@fire
Copy link
Member

fire commented Aug 10, 2022

I support this, and I think the work is not so difficult. It's open to a pr in my opinion.

I have a backlog I'm working through and Beta times are near.

@JohanAR
Copy link
Contributor

JohanAR commented Nov 10, 2022

I'm having a problem with 16 bit textures looking like dithered 8 bit when setting Compress To VRAM Compressed on import, is this what could be causing it?

Screenshot_20221110_203535

Here's what it looks like if I use basis universal or disabled:

Screenshot_20221110_203048

@TokisanGames
Copy link
Contributor

When importing a png with compress to vram, it gets converted to DXT 5, which is 8bpp, not 16. You can try enabling etc2, or the other formats in the project settings/rendering/textures/VRAM compression, and try the various import options.

Or use the settings you found.

Or preconvert the file and give Godot a format it won't convert like DDS, or a format that supports 16-bit like exr.

@clayjohn clayjohn modified the milestones: 4.0, 4.x Jan 18, 2023
@clayjohn
Copy link
Member

clayjohn commented Apr 27, 2023

Here is the logic responsible. Looks like we only use DXT1 when the texture only contains black and white data with no alpha

case Image::USED_CHANNELS_L:
return EtcpakType::ETCPAK_TYPE_DXT1;
case Image::USED_CHANNELS_LA:
return EtcpakType::ETCPAK_TYPE_DXT5;
case Image::USED_CHANNELS_R:
return EtcpakType::ETCPAK_TYPE_DXT5;
case Image::USED_CHANNELS_RG:
return EtcpakType::ETCPAK_TYPE_DXT5_RA_AS_RG;
case Image::USED_CHANNELS_RGB:
return EtcpakType::ETCPAK_TYPE_DXT5;
case Image::USED_CHANNELS_RGBA:
return EtcpakType::ETCPAK_TYPE_DXT5;
default:
return EtcpakType::ETCPAK_TYPE_DXT5;

We should confirm that the quality is the same with if we switch RGB and R to use DXT1 as well

Looks like RGB switched from DXT1 to DXT5 in this PR #47370 CC @fire Was the change intentional? If not we can just switch it back.

The old logic was here:

switch (p_channels) {
case Image::USED_CHANNELS_L: {
target_format = Image::FORMAT_DXT1;
squish_comp |= squish::kDxt1;
} break;
case Image::USED_CHANNELS_LA: {
target_format = Image::FORMAT_DXT5;
squish_comp |= squish::kDxt5;
} break;
case Image::USED_CHANNELS_R: {
target_format = Image::FORMAT_RGTC_R;
squish_comp |= squish::kBc4;
} break;
case Image::USED_CHANNELS_RG: {
target_format = Image::FORMAT_RGTC_RG;
squish_comp |= squish::kBc5;
} break;
case Image::USED_CHANNELS_RGB: {
target_format = Image::FORMAT_DXT1;
squish_comp |= squish::kDxt1;
} break;
case Image::USED_CHANNELS_RGBA: {
//TODO, should convert both, then measure which one does a better job
target_format = Image::FORMAT_DXT5;
squish_comp |= squish::kDxt5;
} break;
default: {
ERR_PRINT("Unknown image format, defaulting to RGBA8");
break;
}
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants