diff --git a/include/SDL3/SDL_gpu.h b/include/SDL3/SDL_gpu.h index 9748d730b9c26..c12288c2c9f1f 100644 --- a/include/SDL3/SDL_gpu.h +++ b/include/SDL3/SDL_gpu.h @@ -1126,6 +1126,53 @@ typedef enum SDL_GPUSwapchainComposition /* Structures */ +/** + * Unsigned integer clear color for unsigned integer color formats. + * + * \since This struct is available since SDL 3.2.0 + * + * \sa SDL_BeginGPURenderPass + * \sa SDL_BlitGPUTexture + */ +typedef struct SDL_GPUClearColorUint32 +{ + Uint32 r; + Uint32 g; + Uint32 b; + Uint32 a; +} SDL_GPUClearColorUint32; + +/** + * Signed integer clear color for signed integer color formats. + * + * \since This struct is available since SDL 3.2.0 + * + * \sa SDL_BeginGPURenderPass + * \sa SDL_BlitGPUTexture + */ +typedef struct SDL_GPUClearColorSint32 +{ + Sint32 r; + Sint32 g; + Sint32 b; + Sint32 a; +} SDL_GPUClearColorSint32; + +/** + * A union specifying a clear color. + * + * \since This union is available since SDL 3.2.0 + * + * \sa SDL_BeginGPURenderPass + * \sa SDL_BlitGPUTexture + */ +typedef union SDL_GPUClearColor +{ + SDL_FColor float32; + SDL_GPUClearColorUint32 uint32; + SDL_GPUClearColorSint32 sint32; +} SDL_GPUClearColor; + /** * A structure specifying a viewport. * @@ -1729,7 +1776,7 @@ typedef struct SDL_GPUColorTargetInfo SDL_GPUTexture *texture; /**< The texture that will be used as a color target by a render pass. */ Uint32 mip_level; /**< The mip level to use as a color target. */ Uint32 layer_or_depth_plane; /**< The layer index or depth plane to use as a color target. This value is treated as a layer index on 2D array and cube textures, and as a depth plane on 3D textures. */ - SDL_FColor clear_color; /**< The color to clear the color target to at the start of the render pass. Ignored if SDL_GPU_LOADOP_CLEAR is not used. */ + SDL_GPUClearColor clear_color; /**< The color to clear the color target to at the start of the render pass. Ignored if SDL_GPU_LOADOP_CLEAR is not used. */ SDL_GPULoadOp load_op; /**< What is done with the contents of the color target at the beginning of the render pass. */ SDL_GPUStoreOp store_op; /**< What is done with the results of the render pass. */ SDL_GPUTexture *resolve_texture; /**< The texture that will receive the results of a multisample resolve operation. Ignored if a RESOLVE* store_op is not used. */ @@ -1810,7 +1857,7 @@ typedef struct SDL_GPUBlitInfo { SDL_GPUBlitRegion source; /**< The source region for the blit. */ SDL_GPUBlitRegion destination; /**< The destination region for the blit. */ SDL_GPULoadOp load_op; /**< What is done with the contents of the destination before the blit. */ - SDL_FColor clear_color; /**< The color to clear the destination region to before the blit. Ignored if load_op is not SDL_GPU_LOADOP_CLEAR. */ + SDL_GPUClearColor clear_color; /**< The color to clear the destination region to before the blit. Ignored if load_op is not SDL_GPU_LOADOP_CLEAR. */ SDL_FlipMode flip_mode; /**< The flip mode for the source region. */ SDL_GPUFilter filter; /**< The filter mode used when blitting. */ bool cycle; /**< true cycles the destination texture if it is already bound. */ diff --git a/src/gpu/SDL_sysgpu.h b/src/gpu/SDL_sysgpu.h index 7f9ef6ca43324..f2dd8f81f566b 100644 --- a/src/gpu/SDL_sysgpu.h +++ b/src/gpu/SDL_sysgpu.h @@ -172,12 +172,18 @@ static inline Sint32 Texture_GetBlockWidth( case SDL_GPU_TEXTUREFORMAT_R16_UINT: case SDL_GPU_TEXTUREFORMAT_R16G16_UINT: case SDL_GPU_TEXTUREFORMAT_R16G16B16A16_UINT: + case SDL_GPU_TEXTUREFORMAT_R32_UINT: + case SDL_GPU_TEXTUREFORMAT_R32G32_UINT: + case SDL_GPU_TEXTUREFORMAT_R32G32B32A32_UINT: case SDL_GPU_TEXTUREFORMAT_R8_INT: case SDL_GPU_TEXTUREFORMAT_R8G8_INT: case SDL_GPU_TEXTUREFORMAT_R8G8B8A8_INT: case SDL_GPU_TEXTUREFORMAT_R16_INT: case SDL_GPU_TEXTUREFORMAT_R16G16_INT: case SDL_GPU_TEXTUREFORMAT_R16G16B16A16_INT: + case SDL_GPU_TEXTUREFORMAT_R32_INT: + case SDL_GPU_TEXTUREFORMAT_R32G32_INT: + case SDL_GPU_TEXTUREFORMAT_R32G32B32A32_INT: case SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM_SRGB: case SDL_GPU_TEXTUREFORMAT_B8G8R8A8_UNORM_SRGB: case SDL_GPU_TEXTUREFORMAT_D16_UNORM: @@ -286,12 +292,18 @@ static inline Sint32 Texture_GetBlockHeight( case SDL_GPU_TEXTUREFORMAT_R16_UINT: case SDL_GPU_TEXTUREFORMAT_R16G16_UINT: case SDL_GPU_TEXTUREFORMAT_R16G16B16A16_UINT: + case SDL_GPU_TEXTUREFORMAT_R32_UINT: + case SDL_GPU_TEXTUREFORMAT_R32G32_UINT: + case SDL_GPU_TEXTUREFORMAT_R32G32B32A32_UINT: case SDL_GPU_TEXTUREFORMAT_R8_INT: case SDL_GPU_TEXTUREFORMAT_R8G8_INT: case SDL_GPU_TEXTUREFORMAT_R8G8B8A8_INT: case SDL_GPU_TEXTUREFORMAT_R16_INT: case SDL_GPU_TEXTUREFORMAT_R16G16_INT: case SDL_GPU_TEXTUREFORMAT_R16G16B16A16_INT: + case SDL_GPU_TEXTUREFORMAT_R32_INT: + case SDL_GPU_TEXTUREFORMAT_R32G32_INT: + case SDL_GPU_TEXTUREFORMAT_R32G32B32A32_INT: case SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM_SRGB: case SDL_GPU_TEXTUREFORMAT_B8G8R8A8_UNORM_SRGB: case SDL_GPU_TEXTUREFORMAT_D16_UNORM: @@ -345,12 +357,18 @@ static inline bool IsIntegerFormat( case SDL_GPU_TEXTUREFORMAT_R16_UINT: case SDL_GPU_TEXTUREFORMAT_R16G16_UINT: case SDL_GPU_TEXTUREFORMAT_R16G16B16A16_UINT: + case SDL_GPU_TEXTUREFORMAT_R32_UINT: + case SDL_GPU_TEXTUREFORMAT_R32G32_UINT: + case SDL_GPU_TEXTUREFORMAT_R32G32B32A32_UINT: case SDL_GPU_TEXTUREFORMAT_R8_INT: case SDL_GPU_TEXTUREFORMAT_R8G8_INT: case SDL_GPU_TEXTUREFORMAT_R8G8B8A8_INT: case SDL_GPU_TEXTUREFORMAT_R16_INT: case SDL_GPU_TEXTUREFORMAT_R16G16_INT: case SDL_GPU_TEXTUREFORMAT_R16G16B16A16_INT: + case SDL_GPU_TEXTUREFORMAT_R32_INT: + case SDL_GPU_TEXTUREFORMAT_R32G32_INT: + case SDL_GPU_TEXTUREFORMAT_R32G32B32A32_INT: return true; default: @@ -358,6 +376,46 @@ static inline bool IsIntegerFormat( } } +static inline bool IsUnsignedIntegerFormat( + SDL_GPUTextureFormat format) +{ + switch (format) { + case SDL_GPU_TEXTUREFORMAT_R8_UINT: + case SDL_GPU_TEXTUREFORMAT_R8G8_UINT: + case SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UINT: + case SDL_GPU_TEXTUREFORMAT_R16_UINT: + case SDL_GPU_TEXTUREFORMAT_R16G16_UINT: + case SDL_GPU_TEXTUREFORMAT_R16G16B16A16_UINT: + case SDL_GPU_TEXTUREFORMAT_R32_UINT: + case SDL_GPU_TEXTUREFORMAT_R32G32_UINT: + case SDL_GPU_TEXTUREFORMAT_R32G32B32A32_UINT: + return true; + + default: + return false; + } +} + +static inline bool IsSignedIntegerFormat( + SDL_GPUTextureFormat format) +{ + switch (format) { + case SDL_GPU_TEXTUREFORMAT_R8_INT: + case SDL_GPU_TEXTUREFORMAT_R8G8_INT: + case SDL_GPU_TEXTUREFORMAT_R8G8B8A8_INT: + case SDL_GPU_TEXTUREFORMAT_R16_INT: + case SDL_GPU_TEXTUREFORMAT_R16G16_INT: + case SDL_GPU_TEXTUREFORMAT_R16G16B16A16_INT: + case SDL_GPU_TEXTUREFORMAT_R32_INT: + case SDL_GPU_TEXTUREFORMAT_R32G32_INT: + case SDL_GPU_TEXTUREFORMAT_R32G32B32A32_INT: + return true; + + default: + return false; + } +} + static inline Uint32 IndexSize(SDL_GPUIndexElementSize size) { return (size == SDL_GPU_INDEXELEMENTSIZE_16BIT) ? 2 : 4; diff --git a/src/gpu/d3d11/SDL_gpu_d3d11.c b/src/gpu/d3d11/SDL_gpu_d3d11.c index d667efddf5ba7..ab7c745ea3928 100644 --- a/src/gpu/d3d11/SDL_gpu_d3d11.c +++ b/src/gpu/d3d11/SDL_gpu_d3d11.c @@ -3544,12 +3544,26 @@ static void D3D11_BeginRenderPass( } if (colorTargetInfos[i].load_op == SDL_GPU_LOADOP_CLEAR) { - float clearColor[] = { - colorTargetInfos[i].clear_color.r, - colorTargetInfos[i].clear_color.g, - colorTargetInfos[i].clear_color.b, - colorTargetInfos[i].clear_color.a + float clearColor[4] = { + colorTargetInfos[i].clear_color.float32.r, + colorTargetInfos[i].clear_color.float32.g, + colorTargetInfos[i].clear_color.float32.b, + colorTargetInfos[i].clear_color.float32.a }; + if (IsUnsignedIntegerFormat(container->header.info.format)) { + // FIXME: Handle out-of-range values for R32_UINT & friends. + clearColor[0] = (float)colorTargetInfos[i].clear_color.uint32.r; + clearColor[1] = (float)colorTargetInfos[i].clear_color.uint32.g; + clearColor[2] = (float)colorTargetInfos[i].clear_color.uint32.b; + clearColor[3] = (float)colorTargetInfos[i].clear_color.uint32.a; + } else if (IsSignedIntegerFormat(container->header.info.format)) { + // FIXME: Handle out-of-range values for R32_INT & friends. + clearColor[0] = (float)colorTargetInfos[i].clear_color.sint32.r; + clearColor[1] = (float)colorTargetInfos[i].clear_color.sint32.g; + clearColor[2] = (float)colorTargetInfos[i].clear_color.sint32.b; + clearColor[3] = (float)colorTargetInfos[i].clear_color.sint32.a; + } + ID3D11DeviceContext_ClearRenderTargetView( d3d11CommandBuffer->context, rtvs[i], diff --git a/src/gpu/d3d12/SDL_gpu_d3d12.c b/src/gpu/d3d12/SDL_gpu_d3d12.c index 86d8dcc6c6d83..ed2ffbc48f480 100644 --- a/src/gpu/d3d12/SDL_gpu_d3d12.c +++ b/src/gpu/d3d12/SDL_gpu_d3d12.c @@ -3997,11 +3997,25 @@ static void D3D12_BeginRenderPass( D3D12_CPU_DESCRIPTOR_HANDLE rtv = subresource->rtvHandles[rtvIndex].cpuHandle; if (colorTargetInfos[i].load_op == SDL_GPU_LOADOP_CLEAR) { - float clearColor[4]; - clearColor[0] = colorTargetInfos[i].clear_color.r; - clearColor[1] = colorTargetInfos[i].clear_color.g; - clearColor[2] = colorTargetInfos[i].clear_color.b; - clearColor[3] = colorTargetInfos[i].clear_color.a; + float clearColor[4] = { + colorTargetInfos[i].clear_color.float32.r, + colorTargetInfos[i].clear_color.float32.g, + colorTargetInfos[i].clear_color.float32.b, + colorTargetInfos[i].clear_color.float32.a + }; + if (IsUnsignedIntegerFormat(container->header.info.format)) { + // FIXME: Handle out-of-range values for R32_UINT & friends. + clearColor[0] = (float)colorTargetInfos[i].clear_color.uint32.r; + clearColor[1] = (float)colorTargetInfos[i].clear_color.uint32.g; + clearColor[2] = (float)colorTargetInfos[i].clear_color.uint32.b; + clearColor[3] = (float)colorTargetInfos[i].clear_color.uint32.a; + } else if (IsSignedIntegerFormat(container->header.info.format)) { + // FIXME: Handle out-of-range values for R32_INT & friends. + clearColor[0] = (float)colorTargetInfos[i].clear_color.sint32.r; + clearColor[1] = (float)colorTargetInfos[i].clear_color.sint32.g; + clearColor[2] = (float)colorTargetInfos[i].clear_color.sint32.b; + clearColor[3] = (float)colorTargetInfos[i].clear_color.sint32.a; + } ID3D12GraphicsCommandList_ClearRenderTargetView( d3d12CommandBuffer->graphicsCommandList, diff --git a/src/gpu/metal/SDL_gpu_metal.m b/src/gpu/metal/SDL_gpu_metal.m index c8230aeeb888a..3bed0d455d844 100644 --- a/src/gpu/metal/SDL_gpu_metal.m +++ b/src/gpu/metal/SDL_gpu_metal.m @@ -2238,6 +2238,12 @@ static void METAL_BeginRenderPass( renderer, container, colorTargetInfos[i].cycle); + double clearColor[4] = { + colorTargetInfos[i].clear_color.float32.r, + colorTargetInfos[i].clear_color.float32.g, + colorTargetInfos[i].clear_color.float32.b, + colorTargetInfos[i].clear_color.float32.a + }; passDescriptor.colorAttachments[i].texture = texture->handle; passDescriptor.colorAttachments[i].level = colorTargetInfos[i].mip_level; @@ -2246,11 +2252,19 @@ static void METAL_BeginRenderPass( } else { passDescriptor.colorAttachments[i].slice = colorTargetInfos[i].layer_or_depth_plane; } - passDescriptor.colorAttachments[i].clearColor = MTLClearColorMake( - colorTargetInfos[i].clear_color.r, - colorTargetInfos[i].clear_color.g, - colorTargetInfos[i].clear_color.b, - colorTargetInfos[i].clear_color.a); + + if (IsUnsignedIntegerFormat(container->header.info.format)) { + clearColor[0] = (double)colorTargetInfos[i].clear_color.uint32.r; + clearColor[1] = (double)colorTargetInfos[i].clear_color.uint32.g; + clearColor[2] = (double)colorTargetInfos[i].clear_color.uint32.b; + clearColor[3] = (double)colorTargetInfos[i].clear_color.uint32.a; + } else if (IsSignedIntegerFormat(container->header.info.format)) { + clearColor[0] = (double)colorTargetInfos[i].clear_color.sint32.r; + clearColor[1] = (double)colorTargetInfos[i].clear_color.sint32.g; + clearColor[2] = (double)colorTargetInfos[i].clear_color.sint32.b; + clearColor[3] = (double)colorTargetInfos[i].clear_color.sint32.a; + } + passDescriptor.colorAttachments[i].clearColor = MTLClearColorMake(clearColor[0], clearColor[1], clearColor[2], clearColor[3]); passDescriptor.colorAttachments[i].loadAction = SDLToMetal_LoadOp[colorTargetInfos[i].load_op]; passDescriptor.colorAttachments[i].storeAction = SDLToMetal_StoreOp[colorTargetInfos[i].store_op]; diff --git a/src/gpu/vulkan/SDL_gpu_vulkan.c b/src/gpu/vulkan/SDL_gpu_vulkan.c index ce3abd60d17b3..4df7065e9178b 100644 --- a/src/gpu/vulkan/SDL_gpu_vulkan.c +++ b/src/gpu/vulkan/SDL_gpu_vulkan.c @@ -7703,10 +7703,10 @@ static void VULKAN_BeginRenderPass( clearValues = SDL_stack_alloc(VkClearValue, clearCount); for (i = 0; i < totalColorAttachmentCount; i += 1) { - clearValues[i].color.float32[0] = colorTargetInfos[i].clear_color.r; - clearValues[i].color.float32[1] = colorTargetInfos[i].clear_color.g; - clearValues[i].color.float32[2] = colorTargetInfos[i].clear_color.b; - clearValues[i].color.float32[3] = colorTargetInfos[i].clear_color.a; + clearValues[i].color.uint32[0] = colorTargetInfos[i].clear_color.uint32.r; + clearValues[i].color.uint32[1] = colorTargetInfos[i].clear_color.uint32.g; + clearValues[i].color.uint32[2] = colorTargetInfos[i].clear_color.uint32.b; + clearValues[i].color.uint32[3] = colorTargetInfos[i].clear_color.uint32.a; if (colorTargetInfos[i].store_op == SDL_GPU_STOREOP_RESOLVE || colorTargetInfos[i].store_op == SDL_GPU_STOREOP_RESOLVE_AND_STORE) { // Skip over the resolve texture, we're not clearing it diff --git a/src/render/gpu/SDL_render_gpu.c b/src/render/gpu/SDL_render_gpu.c index c36784ce9e865..937a29b9c7a43 100644 --- a/src/render/gpu/SDL_render_gpu.c +++ b/src/render/gpu/SDL_render_gpu.c @@ -730,7 +730,7 @@ static bool GPU_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd, case SDL_RENDERCMD_CLEAR: { - data->state.color_attachment.clear_color = GetDrawCmdColor(renderer, cmd); + data->state.color_attachment.clear_color.float32 = GetDrawCmdColor(renderer, cmd); data->state.color_attachment.load_op = SDL_GPU_LOADOP_CLEAR; break; } diff --git a/test/testgpu_simple_clear.c b/test/testgpu_simple_clear.c index 940dd37d668e5..32576a1b7b4a9 100644 --- a/test/testgpu_simple_clear.c +++ b/test/testgpu_simple_clear.c @@ -92,10 +92,10 @@ SDL_AppResult SDL_AppIterate(void *appstate) SDL_GPUColorTargetInfo color_target_info; SDL_zero(color_target_info); color_target_info.texture = swapchainTexture; - color_target_info.clear_color.r = (float)(0.5 + 0.5 * SDL_sin(currentTime)); - color_target_info.clear_color.g = (float)(0.5 + 0.5 * SDL_sin(currentTime + SDL_PI_D * 2 / 3)); - color_target_info.clear_color.b = (float)(0.5 + 0.5 * SDL_sin(currentTime + SDL_PI_D * 4 / 3)); - color_target_info.clear_color.a = 1.0f; + color_target_info.clear_color.float32.r = (float)(0.5 + 0.5 * SDL_sin(currentTime)); + color_target_info.clear_color.float32.g = (float)(0.5 + 0.5 * SDL_sin(currentTime + SDL_PI_D * 2 / 3)); + color_target_info.clear_color.float32.b = (float)(0.5 + 0.5 * SDL_sin(currentTime + SDL_PI_D * 4 / 3)); + color_target_info.clear_color.float32.a = 1.0f; color_target_info.load_op = SDL_GPU_LOADOP_CLEAR; color_target_info.store_op = SDL_GPU_STOREOP_STORE; diff --git a/test/testgpu_spinning_cube.c b/test/testgpu_spinning_cube.c index 9fe01a1a8503e..75ffe182e92e2 100644 --- a/test/testgpu_spinning_cube.c +++ b/test/testgpu_spinning_cube.c @@ -399,7 +399,7 @@ Render(SDL_Window *window, const int windownum) /* Set up the pass */ SDL_zero(color_target); - color_target.clear_color.a = 1.0f; + color_target.clear_color.float32.a = 1.0f; if (winstate->tex_msaa) { color_target.load_op = SDL_GPU_LOADOP_CLEAR; color_target.store_op = SDL_GPU_STOREOP_RESOLVE;