From 56c76c20a0cf4332c2c478a93a46babd82dde795 Mon Sep 17 00:00:00 2001 From: Evan Hemsley <2342303+thatcosmonaut@users.noreply.github.com> Date: Tue, 29 Apr 2025 16:52:52 -0700 Subject: [PATCH] GPU: Validate that textures are not bound for both read and write on render passes (#12925) (cherry picked from commit a1632572955f1a47c3981f41d98533d07fd59779) --- src/gpu/SDL_gpu.c | 53 ++++++++++++++++++++++++++++++++++++++++++-- src/gpu/SDL_sysgpu.h | 41 +++++++++++++++++++++------------- 2 files changed, 76 insertions(+), 18 deletions(-) diff --git a/src/gpu/SDL_gpu.c b/src/gpu/SDL_gpu.c index b7ca696267..db3525b91f 100644 --- a/src/gpu/SDL_gpu.c +++ b/src/gpu/SDL_gpu.c @@ -56,11 +56,43 @@ } #define CHECK_RENDERPASS \ - if (!((Pass *)render_pass)->in_progress) { \ + if (!((RenderPass *)render_pass)->in_progress) { \ SDL_assert_release(!"Render pass not in progress!"); \ return; \ } +#define CHECK_SAMPLER_TEXTURES \ + RenderPass *rp = (RenderPass *)render_pass; \ + for (Uint32 color_target_index = 0; color_target_index < rp->num_color_targets; color_target_index += 1) { \ + for (Uint32 texture_sampler_index = 0; texture_sampler_index < num_bindings; texture_sampler_index += 1) { \ + if (rp->color_targets[color_target_index] == texture_sampler_bindings[texture_sampler_index].texture) { \ + SDL_assert_release(!"Texture cannot be simultaneously bound as a color target and a sampler!"); \ + } \ + } \ + } \ + \ + for (Uint32 texture_sampler_index = 0; texture_sampler_index < num_bindings; texture_sampler_index += 1) { \ + if (rp->depth_stencil_target != NULL && rp->depth_stencil_target == texture_sampler_bindings[texture_sampler_index].texture) { \ + SDL_assert_release(!"Texture cannot be simultaneously bound as a depth stencil target and a sampler!"); \ + } \ + } + +#define CHECK_STORAGE_TEXTURES \ + RenderPass *rp = (RenderPass *)render_pass; \ + for (Uint32 color_target_index = 0; color_target_index < rp->num_color_targets; color_target_index += 1) { \ + for (Uint32 texture_sampler_index = 0; texture_sampler_index < num_bindings; texture_sampler_index += 1) { \ + if (rp->color_targets[color_target_index] == storage_textures[texture_sampler_index]) { \ + SDL_assert_release(!"Texture cannot be simultaneously bound as a color target and a storage texture!"); \ + } \ + } \ + } \ + \ + for (Uint32 texture_sampler_index = 0; texture_sampler_index < num_bindings; texture_sampler_index += 1) { \ + if (rp->depth_stencil_target != NULL && rp->depth_stencil_target == storage_textures[texture_sampler_index]) { \ + SDL_assert_release(!"Texture cannot be simultaneously bound as a depth stencil target and a storage texture!"); \ + } \ + } + #define CHECK_GRAPHICS_PIPELINE_BOUND \ if (!((CommandBufferCommonHeader *)RENDERPASS_COMMAND_BUFFER)->graphics_pipeline_bound) { \ SDL_assert_release(!"Graphics pipeline not bound!"); \ @@ -137,7 +169,7 @@ ((CommandBufferCommonHeader *)command_buffer)->device #define RENDERPASS_COMMAND_BUFFER \ - ((Pass *)render_pass)->command_buffer + ((RenderPass *)render_pass)->command_buffer #define RENDERPASS_DEVICE \ ((CommandBufferCommonHeader *)RENDERPASS_COMMAND_BUFFER)->device @@ -1523,6 +1555,13 @@ SDL_GPURenderPass *SDL_BeginGPURenderPass( commandBufferHeader = (CommandBufferCommonHeader *)command_buffer; commandBufferHeader->render_pass.in_progress = true; + for (Uint32 i = 0; i < num_color_targets; i += 1) { + commandBufferHeader->render_pass.color_targets[i] = color_target_infos[i].texture; + } + commandBufferHeader->render_pass.num_color_targets = num_color_targets; + if (depth_stencil_target_info != NULL) { + commandBufferHeader->render_pass.depth_stencil_target = depth_stencil_target_info->texture; + } return (SDL_GPURenderPass *)&(commandBufferHeader->render_pass); } @@ -1696,6 +1735,7 @@ void SDL_BindGPUVertexSamplers( if (RENDERPASS_DEVICE->debug_mode) { CHECK_RENDERPASS + CHECK_SAMPLER_TEXTURES } RENDERPASS_DEVICE->BindVertexSamplers( @@ -1722,6 +1762,7 @@ void SDL_BindGPUVertexStorageTextures( if (RENDERPASS_DEVICE->debug_mode) { CHECK_RENDERPASS + CHECK_STORAGE_TEXTURES } RENDERPASS_DEVICE->BindVertexStorageTextures( @@ -1774,6 +1815,7 @@ void SDL_BindGPUFragmentSamplers( if (RENDERPASS_DEVICE->debug_mode) { CHECK_RENDERPASS + CHECK_SAMPLER_TEXTURES } RENDERPASS_DEVICE->BindFragmentSamplers( @@ -1800,6 +1842,7 @@ void SDL_BindGPUFragmentStorageTextures( if (RENDERPASS_DEVICE->debug_mode) { CHECK_RENDERPASS + CHECK_STORAGE_TEXTURES } RENDERPASS_DEVICE->BindFragmentStorageTextures( @@ -1960,6 +2003,12 @@ void SDL_EndGPURenderPass( commandBufferCommonHeader = (CommandBufferCommonHeader *)RENDERPASS_COMMAND_BUFFER; commandBufferCommonHeader->render_pass.in_progress = false; + for (Uint32 i = 0; i < MAX_COLOR_TARGET_BINDINGS; i += 1) + { + commandBufferCommonHeader->render_pass.color_targets[i] = NULL; + } + commandBufferCommonHeader->render_pass.num_color_targets = 0; + commandBufferCommonHeader->render_pass.depth_stencil_target = NULL; commandBufferCommonHeader->graphics_pipeline_bound = false; } diff --git a/src/gpu/SDL_sysgpu.h b/src/gpu/SDL_sysgpu.h index 6de1765f6d..7425f6adc5 100644 --- a/src/gpu/SDL_sysgpu.h +++ b/src/gpu/SDL_sysgpu.h @@ -24,6 +24,21 @@ #ifndef SDL_GPU_DRIVER_H #define SDL_GPU_DRIVER_H +// GraphicsDevice Limits + +#define MAX_TEXTURE_SAMPLERS_PER_STAGE 16 +#define MAX_STORAGE_TEXTURES_PER_STAGE 8 +#define MAX_STORAGE_BUFFERS_PER_STAGE 8 +#define MAX_UNIFORM_BUFFERS_PER_STAGE 4 +#define MAX_COMPUTE_WRITE_TEXTURES 8 +#define MAX_COMPUTE_WRITE_BUFFERS 8 +#define UNIFORM_BUFFER_SIZE 32768 +#define MAX_VERTEX_BUFFERS 16 +#define MAX_VERTEX_ATTRIBUTES 16 +#define MAX_COLOR_TARGET_BINDINGS 4 +#define MAX_PRESENT_COUNT 16 +#define MAX_FRAMES_IN_FLIGHT 3 + // Common Structs typedef struct Pass @@ -32,10 +47,19 @@ typedef struct Pass bool in_progress; } Pass; +typedef struct RenderPass +{ + SDL_GPUCommandBuffer *command_buffer; + bool in_progress; + SDL_GPUTexture *color_targets[MAX_COLOR_TARGET_BINDINGS]; + Uint32 num_color_targets; + SDL_GPUTexture *depth_stencil_target; +} RenderPass; + typedef struct CommandBufferCommonHeader { SDL_GPUDevice *device; - Pass render_pass; + RenderPass render_pass; bool graphics_pipeline_bound; Pass compute_pass; bool compute_pipeline_bound; @@ -385,21 +409,6 @@ static inline Uint32 BytesPerRow( return blocksPerRow * SDL_GPUTextureFormatTexelBlockSize(format); } -// GraphicsDevice Limits - -#define MAX_TEXTURE_SAMPLERS_PER_STAGE 16 -#define MAX_STORAGE_TEXTURES_PER_STAGE 8 -#define MAX_STORAGE_BUFFERS_PER_STAGE 8 -#define MAX_UNIFORM_BUFFERS_PER_STAGE 4 -#define MAX_COMPUTE_WRITE_TEXTURES 8 -#define MAX_COMPUTE_WRITE_BUFFERS 8 -#define UNIFORM_BUFFER_SIZE 32768 -#define MAX_VERTEX_BUFFERS 16 -#define MAX_VERTEX_ATTRIBUTES 16 -#define MAX_COLOR_TARGET_BINDINGS 4 -#define MAX_PRESENT_COUNT 16 -#define MAX_FRAMES_IN_FLIGHT 3 - // Internal Macros #define EXPAND_ARRAY_IF_NEEDED(arr, elementType, newCount, capacity, newCapacity) \