libsdl-org / SDL

Simple Directmedia Layer
https://libsdl.org
zlib License
10.15k stars 1.85k forks source link

GPU: Integer Color Target Clears #11343

Open rabbit-ecl opened 3 weeks ago

rabbit-ecl commented 3 weeks ago

Clearing of integer color targets is currently underspecified in SDL_GPU and has diverging behavior between backends. D3D will take float and convert it to the closest representable integer for clearing, this means that some 32-bit integer values can't be represented! Metal does the same, but uses double instead and thus should be able to represent all 32-bit integer values. Vulkan will currently just bitcast the floats. Clearing an R8_UINT with r=255.0 will result in integer 255 on Metal and D3D, but bitcasted garbage on Vulkan.

Somewhat relevant from WebGPU: https://github.com/gpuweb/gpuweb/issues/1085 https://github.com/gpuweb/gpuweb/issues/965 WebGPU chose to mandate full 32-bit clears and implementations have to emulate the out-of-range clears on D3D.

TheSpydog commented 3 weeks ago

Microsoft's docs recommend drawing a full-screen quad to clear integer render targets rather than using ClearRenderTargetView: https://learn.microsoft.com/en-us/windows/win32/api/d3d11/nf-d3d11-id3d11devicecontext-clearrendertargetview#remarks

We should document this workaround for GPU as well.

rabbit-ecl commented 3 weeks ago

We should document this workaround for GPU as well.

As in user code or backend? Vulkan/Metal can support this for all values (32-bit ones anyway) but D3D would need a shader path for values >2**24. There's some precedence for this already in SDL_GPU's emulated blits. I think we might want to replace SDL_FColor clear_color with a union or go the Metal way and use SDL_DColor (which currently doesn't exist).