From 0ccb76ae876e3e893d179828f16f0933326bf084 Mon Sep 17 00:00:00 2001
From: Ethan Lee <[EMAIL REDACTED]>
Date: Thu, 17 Sep 2026 13:29:54 -0400
Subject: [PATCH] gpu: Add debug validation for viewport/scissor being larger
than target size
---
src/gpu/SDL_gpu.c | 22 ++++++++++++++++++++++
src/gpu/SDL_sysgpu.h | 2 ++
2 files changed, 24 insertions(+)
diff --git a/src/gpu/SDL_gpu.c b/src/gpu/SDL_gpu.c
index 527c5c7c738a4..12939c2d9e0dd 100644
--- a/src/gpu/SDL_gpu.c
+++ b/src/gpu/SDL_gpu.c
@@ -749,6 +749,10 @@ SDL_GPUDevice *SDL_CreateGPUDeviceWithProperties(SDL_PropertiesID props)
if (!SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_FEATURE_ANISOTROPY_BOOLEAN, true)) {
result->validate_feature_anisotropy_disabled = true;
}
+ if (result->debug_mode) {
+ result->max_viewport_width = SDL_MAX_UINT32;
+ result->max_viewport_height = SDL_MAX_UINT32;
+ }
}
}
return result;
@@ -1822,9 +1826,15 @@ SDL_GPURenderPass *SDL_BeginGPURenderPass(
CHECK_COMMAND_BUFFER_RETURN_NULL
CHECK_ANY_PASS_IN_PROGRESS("Cannot begin render pass during another pass!", NULL);
+ COMMAND_BUFFER_DEVICE->max_viewport_width = SDL_MAX_UINT32;
+ COMMAND_BUFFER_DEVICE->max_viewport_height = SDL_MAX_UINT32;
+
for (Uint32 i = 0; i < num_color_targets; i += 1) {
TextureCommonHeader *textureHeader = (TextureCommonHeader *)color_target_infos[i].texture;
+ COMMAND_BUFFER_DEVICE->max_viewport_width = SDL_min(COMMAND_BUFFER_DEVICE->max_viewport_width, textureHeader->info.width);
+ COMMAND_BUFFER_DEVICE->max_viewport_height = SDL_min(COMMAND_BUFFER_DEVICE->max_viewport_height, textureHeader->info.height);
+
if (color_target_infos[i].cycle && color_target_infos[i].load_op == SDL_GPU_LOADOP_LOAD) {
SDL_assert_release(!"Cannot cycle color target when load op is LOAD!");
return NULL;
@@ -1959,6 +1969,12 @@ void SDL_SetGPUViewport(
if (RENDERPASS_DEVICE->debug_mode) {
CHECK_RENDERPASS
+
+ if (((viewport->x + viewport->w) > RENDERPASS_DEVICE->max_viewport_width) ||
+ ((viewport->y + viewport->h) > RENDERPASS_DEVICE->max_viewport_height)) {
+ SDL_assert_release(!"Viewport size exceeds current render target dimensions");
+ return;
+ }
}
RENDERPASS_DEVICE->SetViewport(
@@ -1981,6 +1997,12 @@ void SDL_SetGPUScissor(
if (RENDERPASS_DEVICE->debug_mode) {
CHECK_RENDERPASS
+
+ if (((Uint32) (scissor->x + scissor->w) > RENDERPASS_DEVICE->max_viewport_width) ||
+ ((Uint32) (scissor->y + scissor->h) > RENDERPASS_DEVICE->max_viewport_height)) {
+ SDL_assert_release(!"Scissor rectangle size exceeds current render target dimensions");
+ return;
+ }
}
RENDERPASS_DEVICE->SetScissor(
diff --git a/src/gpu/SDL_sysgpu.h b/src/gpu/SDL_sysgpu.h
index 604be78b5b9b2..c04ce508edaec 100644
--- a/src/gpu/SDL_sysgpu.h
+++ b/src/gpu/SDL_sysgpu.h
@@ -1124,6 +1124,8 @@ struct SDL_GPUDevice
bool default_enable_depth_clip;
bool validate_feature_depth_clamp_disabled;
bool validate_feature_anisotropy_disabled;
+ Uint32 max_viewport_width;
+ Uint32 max_viewport_height;
};
#define ASSIGN_DRIVER_FUNC(func, name) \