Skip to content

Fix RenderingDevice::texture_clear() behaving unexpectedly when using the D3D12 driver#117294

Merged
Repiteo merged 1 commit into
godotengine:masterfrom
H3x4g0n:d3d12-texture-clear-fix
Mar 12, 2026
Merged

Fix RenderingDevice::texture_clear() behaving unexpectedly when using the D3D12 driver#117294
Repiteo merged 1 commit into
godotengine:masterfrom
H3x4g0n:d3d12-texture-clear-fix

Conversation

@H3x4g0n
Copy link
Copy Markdown
Contributor

@H3x4g0n H3x4g0n commented Mar 10, 2026

Fixes: #117210

Using RenderingDevice::texture_clear() led to different results between the Vulkan and D3D12 driver, depending on the DataFormat of the texture.
This PR changes the D3D12 driver to use ID3D12GraphicsCommandList::ClearUnorderedAccessViewFloat() for clearing color textures instead of ID3D12GraphicsCommandList::ClearUnorderedAccessViewUint().
As far as my testing goes, this should make the result of RenderingDevice::texture_clear() be on par between the D3D12 and Vulkan driver.

The following example clears textures with different data formats to Color.HOT_PINK (left to right: R8G8B8A8_UNORM, R32G32B32A32_SFLOAT, R8_UNORM, R32_SFLOAT).

Before:
Before

This PR:
PR

Example project: texture-clear-example.zip

From what I've read about the behavior of those two clearing functions, I think that ClearUnorderedAccessViewFloat() would be more appropriate for clearing color textures.
However, I am not sure whether I am missing something here that might cause issues, as I don't know whether there was a reason for using ClearUnorderedAccessViewUint() in the first place.

@H3x4g0n H3x4g0n requested a review from a team as a code owner March 10, 2026 16:38
@akien-mga
Copy link
Copy Markdown
Member

akien-mga commented Mar 10, 2026

For the record, your commit seems not to be linked to your GitHub account. See: Why are my commits linked to the wrong user? for more info.

The CI failures seem unrelated to this commit, it's just a GH fluke, and should be resolved by maintainers restarting the builds manually.

@akien-mga akien-mga added this to the 4.x milestone Mar 10, 2026
@H3x4g0n
Copy link
Copy Markdown
Contributor Author

H3x4g0n commented Mar 10, 2026

Thank you for pointing that out. I was using an email address that was not yet linked to my GitHub account for the commit. Should be fixed now!

@blueskythlikesclouds
Copy link
Copy Markdown
Member

blueskythlikesclouds commented Mar 11, 2026

What behavior does this show with integer textures? If it matches how Vulkan looks, then it should be ok.

Given this function takes a "Color", it doesn't seem like it was intended to be used for integer textures in the first place.

@H3x4g0n
Copy link
Copy Markdown
Contributor Author

H3x4g0n commented Mar 11, 2026

The behavior with integer textures is very inconsistent and seems to depend on how the underlying graphics driver implements the Vulkan/D3D12 API. I tested this today with different UINT16 texture formats on a dedicated AMD GPU (RX 5700 XT) and integrated graphics from Intel.

Before:

DataFormat Vulkan (Intel) Vulkan (AMD) D3D12 (Intel) D3D12 (AMD)
R16_UINT R: 65535 R: 0 R: 255 R: 255
R16G16_UINT R: 65535
G: 65535
R: 0
G: 53971
R: 255
G: 105
R: 255
G: 105
R16G16B16A16_UINT R: 65535
G: 65535
B: 65535
A: 65535
R: 0
G: 53971
B: 46261
A: 0
R: 255
G: 105
B: 180
A: 255
R: 255
G: 105
B: 180
A: 255

This PR:

DataFormat Vulkan (Intel) Vulkan (AMD) D3D12 (Intel) D3D12 (AMD)
R16_UINT R: 65535 R: 0 R: 65535 R: 1
R16G16_UINT R: 65535
G: 65535
R: 0
G: 53971
R: 65535
G: 65535
R: 1
G: 0
R16G16B16A16_UINT R: 65535
G: 65535
B: 65535
A: 65535
R: 0
G: 53971
B: 46261
A: 0
R: 1
G: 0
B: 0
A: 1
R: 1
G: 0
B: 0
A: 1

Main conclusion: Clearing integer textures using RenderingDevice::texture_clear() is not consistent between the Vulkan and D3D12 driver, neither before nor with this PR - the inconsistency is just different. Mainly that, before this PR, clearing integer textures with the D3D12 driver was at least consistent when using different hardware. This somewhat makes sense, when considering that ClearUnorderedAccessViewFloat() was reported to handle data type conversions differently, depending on the GPU vendor.

In my opinion, RenderingDeviceDriver::command_clear_color_texture() should always use the respective float clearing function of the underlying graphics API, since the clear color is supplied as floats to RenderingDevice::texture_clear().

Furthermore, clearing integer textures with RenderingDevice::texture_clear() seems like a bad idea and I think that ultimately there should be a separate clearing function for integer textures.

On a note: before this PR, setting TEXTURE_USAGE_COLOR_ATTACHMENT_BIT also leads to the expected clearing behavior of float textures when using D3D12. However, clearing with the Vulkan driver leads to the same result with and without setting TEXTURE_USAGE_COLOR_ATTACHMENT_BIT.

Copy link
Copy Markdown
Member

@blueskythlikesclouds blueskythlikesclouds left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, makes sense. The debug layer also seems happy so let's go with it.

@akien-mga akien-mga modified the milestones: 4.x, 4.7 Mar 12, 2026
@Repiteo Repiteo merged commit 0e32499 into godotengine:master Mar 12, 2026
38 of 40 checks passed
@Repiteo
Copy link
Copy Markdown
Contributor

Repiteo commented Mar 12, 2026

Thanks! Congratulations on your first merged contribution! 🎉

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

RenderingDevice.texture_clear() behaves differently between the Vulkan and D3D12 driver, depending on the DataFormat of the texture

4 participants