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

GPU: Add integer color target clears #11347

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 49 additions & 2 deletions include/SDL3/SDL_gpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*
Expand Down Expand Up @@ -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. */
TheSpydog marked this conversation as resolved.
Show resolved Hide resolved
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. */
Expand Down Expand Up @@ -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. */
Expand Down
58 changes: 58 additions & 0 deletions src/gpu/SDL_sysgpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -345,19 +357,65 @@ 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:
return false;
}
}

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;
Expand Down
24 changes: 19 additions & 5 deletions src/gpu/d3d11/SDL_gpu_d3d11.c
Original file line number Diff line number Diff line change
Expand Up @@ -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],
Expand Down
24 changes: 19 additions & 5 deletions src/gpu/d3d12/SDL_gpu_d3d12.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
24 changes: 19 additions & 5 deletions src/gpu/metal/SDL_gpu_metal.m
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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];

Expand Down
8 changes: 4 additions & 4 deletions src/gpu/vulkan/SDL_gpu_vulkan.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion src/render/gpu/SDL_render_gpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
8 changes: 4 additions & 4 deletions test/testgpu_simple_clear.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
2 changes: 1 addition & 1 deletion test/testgpu_spinning_cube.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Loading