SDL: GPU: Zero-init handling (#10786)

From 0b6f993deac687394e69ad62e4ab82fd8019b49a Mon Sep 17 00:00:00 2001
From: Evan Hemsley <[EMAIL REDACTED]>
Date: Tue, 10 Sep 2024 18:17:08 -0700
Subject: [PATCH] GPU: Zero-init handling (#10786)

---
 include/SDL3/SDL_gpu.h               |  73 +++++++------
 src/gpu/SDL_gpu.c                    | 151 +++++++++++++++++++++++++--
 src/gpu/SDL_sysgpu.h                 |  11 +-
 src/gpu/d3d11/SDL_gpu_d3d11.c        |  45 +++++---
 src/gpu/d3d12/SDL_gpu_d3d12.c        |  37 +++++--
 src/gpu/metal/SDL_gpu_metal.m        |  34 ++++--
 src/gpu/vulkan/SDL_gpu_vulkan.c      |  34 ++++--
 src/render/sdlgpu/SDL_pipeline_gpu.c |   2 +-
 test/testgpu_spinning_cube.c         |  11 +-
 9 files changed, 310 insertions(+), 88 deletions(-)

diff --git a/include/SDL3/SDL_gpu.h b/include/SDL3/SDL_gpu.h
index ffbc51a9692b7..e6dbdf52c7487 100644
--- a/include/SDL3/SDL_gpu.h
+++ b/include/SDL3/SDL_gpu.h
@@ -250,11 +250,11 @@ typedef struct SDL_GPUFence SDL_GPUFence;
  */
 typedef enum SDL_GPUPrimitiveType
 {
-    SDL_GPU_PRIMITIVETYPE_POINTLIST,     /**< A series of separate points. */
+    SDL_GPU_PRIMITIVETYPE_TRIANGLELIST,  /**< A series of separate triangles. */
+    SDL_GPU_PRIMITIVETYPE_TRIANGLESTRIP, /**< A series of connected triangles. */
     SDL_GPU_PRIMITIVETYPE_LINELIST,      /**< A series of separate lines. */
     SDL_GPU_PRIMITIVETYPE_LINESTRIP,     /**< A series of connected lines. */
-    SDL_GPU_PRIMITIVETYPE_TRIANGLELIST,  /**< A series of separate triangles. */
-    SDL_GPU_PRIMITIVETYPE_TRIANGLESTRIP  /**< A series of connected triangles. */
+    SDL_GPU_PRIMITIVETYPE_POINTLIST      /**< A series of separate points. */
 } SDL_GPUPrimitiveType;
 
 /**
@@ -384,7 +384,7 @@ typedef enum SDL_GPUIndexElementSize
  */
 typedef enum SDL_GPUTextureFormat
 {
-    SDL_GPU_TEXTUREFORMAT_INVALID = -1,
+    SDL_GPU_TEXTUREFORMAT_INVALID,
 
     /* Unsigned Normalized Float Color Formats */
     SDL_GPU_TEXTUREFORMAT_A8_UNORM,
@@ -586,12 +586,13 @@ typedef enum SDL_GPUShaderStage
  */
 typedef Uint32 SDL_GPUShaderFormat;
 
-#define SDL_GPU_SHADERFORMAT_PRIVATE  (1u << 0) /**< Shaders for NDA'd platforms. */
-#define SDL_GPU_SHADERFORMAT_SPIRV    (1u << 1) /**< SPIR-V shaders for Vulkan. */
-#define SDL_GPU_SHADERFORMAT_DXBC     (1u << 2) /**< DXBC SM5_0 shaders for D3D11. */
-#define SDL_GPU_SHADERFORMAT_DXIL     (1u << 3) /**< DXIL shaders for D3D12. */
-#define SDL_GPU_SHADERFORMAT_MSL      (1u << 4) /**< MSL shaders for Metal. */
-#define SDL_GPU_SHADERFORMAT_METALLIB (1u << 5) /**< Precompiled metallib shaders for Metal. */
+#define SDL_GPU_SHADERFORMAT_INVALID  0
+#define SDL_GPU_SHADERFORMAT_PRIVATE  (1u << 1) /**< Shaders for NDA'd platforms. */
+#define SDL_GPU_SHADERFORMAT_SPIRV    (1u << 2) /**< SPIR-V shaders for Vulkan. */
+#define SDL_GPU_SHADERFORMAT_DXBC     (1u << 3) /**< DXBC SM5_0 shaders for D3D11. */
+#define SDL_GPU_SHADERFORMAT_DXIL     (1u << 4) /**< DXIL shaders for D3D12. */
+#define SDL_GPU_SHADERFORMAT_MSL      (1u << 5) /**< MSL shaders for Metal. */
+#define SDL_GPU_SHADERFORMAT_METALLIB (1u << 6) /**< Precompiled metallib shaders for Metal. */
 
 /**
  * Specifies the format of a vertex attribute.
@@ -602,6 +603,8 @@ typedef Uint32 SDL_GPUShaderFormat;
  */
 typedef enum SDL_GPUVertexElementFormat
 {
+    SDL_GPU_VERTEXELEMENTFORMAT_INVALID,
+
     /* 32-bit Signed Integers */
     SDL_GPU_VERTEXELEMENTFORMAT_INT,
     SDL_GPU_VERTEXELEMENTFORMAT_INT2,
@@ -666,8 +669,8 @@ typedef enum SDL_GPUVertexElementFormat
  */
 typedef enum SDL_GPUVertexInputRate
 {
-    SDL_GPU_VERTEXINPUTRATE_VERTEX = 0,   /**< Attribute addressing is a function of the vertex index. */
-    SDL_GPU_VERTEXINPUTRATE_INSTANCE = 1  /**< Attribute addressing is a function of the instance index. */
+    SDL_GPU_VERTEXINPUTRATE_VERTEX,   /**< Attribute addressing is a function of the vertex index. */
+    SDL_GPU_VERTEXINPUTRATE_INSTANCE  /**< Attribute addressing is a function of the instance index. */
 } SDL_GPUVertexInputRate;
 
 /**
@@ -720,6 +723,7 @@ typedef enum SDL_GPUFrontFace
  */
 typedef enum SDL_GPUCompareOp
 {
+    SDL_GPU_COMPAREOP_INVALID,
     SDL_GPU_COMPAREOP_NEVER,             /**< The comparison always evaluates false. */
     SDL_GPU_COMPAREOP_LESS,              /**< The comparison evaluates reference < test. */
     SDL_GPU_COMPAREOP_EQUAL,             /**< The comparison evaluates reference == test. */
@@ -740,6 +744,7 @@ typedef enum SDL_GPUCompareOp
  */
 typedef enum SDL_GPUStencilOp
 {
+    SDL_GPU_STENCILOP_INVALID,
     SDL_GPU_STENCILOP_KEEP,                 /**< Keeps the current value. */
     SDL_GPU_STENCILOP_ZERO,                 /**< Sets the value to 0. */
     SDL_GPU_STENCILOP_REPLACE,              /**< Sets the value to reference. */
@@ -763,6 +768,7 @@ typedef enum SDL_GPUStencilOp
  */
 typedef enum SDL_GPUBlendOp
 {
+    SDL_GPU_BLENDOP_INVALID,
     SDL_GPU_BLENDOP_ADD,               /**< (source * source_factor) + (destination * destination_factor) */
     SDL_GPU_BLENDOP_SUBTRACT,          /**< (source * source_factor) - (destination * destination_factor) */
     SDL_GPU_BLENDOP_REVERSE_SUBTRACT,  /**< (destination * destination_factor) - (source * source_factor) */
@@ -783,6 +789,7 @@ typedef enum SDL_GPUBlendOp
  */
 typedef enum SDL_GPUBlendFactor
 {
+    SDL_GPU_BLENDFACTOR_INVALID,
     SDL_GPU_BLENDFACTOR_ZERO,                      /**< 0 */
     SDL_GPU_BLENDFACTOR_ONE,                       /**< 1 */
     SDL_GPU_BLENDFACTOR_SRC_COLOR,                 /**< source color */
@@ -933,7 +940,7 @@ typedef enum SDL_GPUSwapchainComposition
  */
 typedef enum SDL_GPUDriver
 {
-    SDL_GPU_DRIVER_INVALID = -1,
+    SDL_GPU_DRIVER_INVALID,
     SDL_GPU_DRIVER_PRIVATE, /* NDA'd platforms */
     SDL_GPU_DRIVER_VULKAN,
     SDL_GPU_DRIVER_D3D11,
@@ -1159,13 +1166,13 @@ typedef struct SDL_GPUSamplerCreateInfo
     SDL_GPUSamplerAddressMode address_mode_w;  /**< The addressing mode for W coordinates outside [0, 1). */
     float mip_lod_bias;                        /**< The bias to be added to mipmap LOD calculation. */
     float max_anisotropy;                      /**< The anisotropy value clamp used by the sampler. If enable_anisotropy is SDL_FALSE, this is ignored. */
+    SDL_GPUCompareOp compare_op;               /**< The comparison operator to apply to fetched data before filtering. */
+    float min_lod;                             /**< Clamps the minimum of the computed LOD value. */
+    float max_lod;                             /**< Clamps the maximum of the computed LOD value. */
     SDL_bool enable_anisotropy;                /**< SDL_TRUE to enable anisotropic filtering. */
     SDL_bool enable_compare;                   /**< SDL_TRUE to enable comparison against a reference value during lookups. */
     Uint8 padding1;
     Uint8 padding2;
-    SDL_GPUCompareOp compare_op;               /**< The comparison operator to apply to fetched data before filtering. */
-    float min_lod;                             /**< Clamps the minimum of the computed LOD value. */
-    float max_lod;                             /**< Clamps the maximum of the computed LOD value. */
 
     SDL_PropertiesID props;                    /**< A properties ID for extensions. Should be 0 if no extensions are needed. */
 } SDL_GPUSamplerCreateInfo;
@@ -1251,17 +1258,17 @@ typedef struct SDL_GPUStencilOpState
  */
 typedef struct SDL_GPUColorTargetBlendState
 {
-    SDL_bool enable_blend;                        /**< Whether blending is enabled for the color target. */
-    Uint8 padding1;
-    Uint8 padding2;
-    Uint8 padding3;
     SDL_GPUBlendFactor src_color_blendfactor;     /**< The value to be multiplied by the source RGB value. */
     SDL_GPUBlendFactor dst_color_blendfactor;     /**< The value to be multiplied by the destination RGB value. */
     SDL_GPUBlendOp color_blend_op;                /**< The blend operation for the RGB components. */
     SDL_GPUBlendFactor src_alpha_blendfactor;     /**< The value to be multiplied by the source alpha. */
     SDL_GPUBlendFactor dst_alpha_blendfactor;     /**< The value to be multiplied by the destination alpha. */
     SDL_GPUBlendOp alpha_blend_op;                /**< The blend operation for the alpha component. */
-    SDL_GPUColorComponentFlags color_write_mask;  /**< A bitmask specifying which of the RGBA components are enabled for writing. */
+    SDL_GPUColorComponentFlags color_write_mask;  /**< A bitmask specifying which of the RGBA components are enabled for writing. Writes to all channels if enable_color_write_mask is SDL_FALSE. */
+    SDL_bool enable_blend;                        /**< Whether blending is enabled for the color target. */
+    SDL_bool enable_color_write_mask;             /**< Whether the color write mask is enabled. */
+    Uint8 padding2;
+    Uint8 padding3;
 } SDL_GPUColorTargetBlendState;
 
 
@@ -1367,13 +1374,13 @@ typedef struct SDL_GPURasterizerState
     SDL_GPUFillMode fill_mode;         /**< Whether polygons will be filled in or drawn as lines. */
     SDL_GPUCullMode cull_mode;         /**< The facing direction in which triangles will be culled. */
     SDL_GPUFrontFace front_face;       /**< The vertex winding that will cause a triangle to be determined as front-facing. */
+    float depth_bias_constant_factor;  /**< A scalar factor controlling the depth value added to each fragment. */
+    float depth_bias_clamp;            /**< The maximum depth bias of a fragment. */
+    float depth_bias_slope_factor;     /**< A scalar factor applied to a fragment's slope in depth calculations. */
     SDL_bool enable_depth_bias;        /**< SDL_TRUE to bias fragment depth values. */
     Uint8 padding1;
     Uint8 padding2;
     Uint8 padding3;
-    float depth_bias_constant_factor;  /**< A scalar factor controlling the depth value added to each fragment. */
-    float depth_bias_clamp;            /**< The maximum depth bias of a fragment. */
-    float depth_bias_slope_factor;     /**< A scalar factor applied to a fragment's slope in depth calculations. */
 } SDL_GPURasterizerState;
 
 /**
@@ -1387,7 +1394,11 @@ typedef struct SDL_GPURasterizerState
 typedef struct SDL_GPUMultisampleState
 {
     SDL_GPUSampleCount sample_count;  /**< The number of samples to be used in rasterization. */
-    Uint32 sample_mask;               /**< Determines which samples get updated in the render targets. 0xFFFFFFFF is a reasonable default. */
+    Uint32 sample_mask;               /**< Determines which samples get updated in the render targets. Treated as 0xFFFFFFFF if enable_mask is SDL_FALSE. */
+    SDL_bool enable_mask;             /**< Enables sample masking. */
+    Uint8 padding1;
+    Uint8 padding2;
+    Uint8 padding3;
 } SDL_GPUMultisampleState;
 
 /**
@@ -1400,15 +1411,15 @@ typedef struct SDL_GPUMultisampleState
  */
 typedef struct SDL_GPUDepthStencilState
 {
-    SDL_bool enable_depth_test;                 /**< SDL_TRUE enables the depth test. */
-    SDL_bool enable_depth_write;                /**< SDL_TRUE enables depth writes. Depth writes are always disabled when enable_depth_test is SDL_FALSE. */
-    SDL_bool enable_stencil_test;               /**< SDL_TRUE enables the stencil test. */
-    Uint8 padding1;
     SDL_GPUCompareOp compare_op;                /**< The comparison operator used for depth testing. */
     SDL_GPUStencilOpState back_stencil_state;   /**< The stencil op state for back-facing triangles. */
     SDL_GPUStencilOpState front_stencil_state;  /**< The stencil op state for front-facing triangles. */
     Uint8 compare_mask;                         /**< Selects the bits of the stencil values participating in the stencil test. */
     Uint8 write_mask;                           /**< Selects the bits of the stencil values updated by the stencil test. */
+    SDL_bool enable_depth_test;                 /**< SDL_TRUE enables the depth test. */
+    SDL_bool enable_depth_write;                /**< SDL_TRUE enables depth writes. Depth writes are always disabled when enable_depth_test is SDL_FALSE. */
+    SDL_bool enable_stencil_test;               /**< SDL_TRUE enables the stencil test. */
+    Uint8 padding1;
     Uint8 padding2;
     Uint8 padding3;
 } SDL_GPUDepthStencilState;
@@ -1439,11 +1450,11 @@ typedef struct SDL_GpuGraphicsPipelineTargetInfo
 {
     const SDL_GPUColorTargetDescription *color_target_descriptions;  /**< A pointer to an array of color target descriptions. */
     Uint32 num_color_targets;                                        /**< The number of color target descriptions in the above array. */
+    SDL_GPUTextureFormat depth_stencil_format;                       /**< The pixel format of the depth-stencil target. Ignored if has_depth_stencil_target is SDL_FALSE. */
     SDL_bool has_depth_stencil_target;                               /**< SDL_TRUE specifies that the pipeline uses a depth-stencil target. */
     Uint8 padding1;
     Uint8 padding2;
     Uint8 padding3;
-    SDL_GPUTextureFormat depth_stencil_format;                       /**< The pixel format of the depth-stencil target. Ignored if has_depth_stencil_target is SDL_FALSE. */
 } SDL_GpuGraphicsPipelineTargetInfo;
 
 /**
@@ -1601,7 +1612,7 @@ typedef struct SDL_GPUBlitInfo {
     SDL_FlipMode flip_mode;         /**< The flip mode for the source region. */
     SDL_GPUFilter filter;           /**< The filter mode used when blitting. */
     SDL_bool cycle;                 /**< SDL_TRUE cycles the destination texture if it is already bound. */
-    Uint8 padding;
+    Uint8 padding1;
     Uint8 padding2;
     Uint8 padding3;
 } SDL_GPUBlitInfo;
diff --git a/src/gpu/SDL_gpu.c b/src/gpu/SDL_gpu.c
index bfd94b68372ac..7e2396d92bab0 100644
--- a/src/gpu/SDL_gpu.c
+++ b/src/gpu/SDL_gpu.c
@@ -79,20 +79,50 @@
         return;                                            \
     }
 
-#define CHECK_TEXTUREFORMAT_ENUM_INVALID(format, retval)     \
-    if (format >= SDL_GPU_TEXTUREFORMAT_MAX) {               \
+#define CHECK_TEXTUREFORMAT_ENUM_INVALID(enumval, retval)     \
+    if (enumval <= SDL_GPU_TEXTUREFORMAT_INVALID || enumval >= SDL_GPU_TEXTUREFORMAT_MAX_ENUM_VALUE) {               \
         SDL_assert_release(!"Invalid texture format enum!"); \
         return retval;                                       \
     }
 
+#define CHECK_VERTEXELEMENTFORMAT_ENUM_INVALID(enumval, retval)       \
+    if (enumval <= SDL_GPU_VERTEXELEMENTFORMAT_INVALID || enumval >= SDL_GPU_VERTEXELEMENTFORMAT_MAX_ENUM_VALUE) {  \
+        SDL_assert_release(!"Invalid vertex format enum!");          \
+        return retval;                                               \
+    }
+
+#define CHECK_COMPAREOP_ENUM_INVALID(enumval, retval)                              \
+    if (enumval <= SDL_GPU_COMPAREOP_INVALID || enumval >= SDL_GPU_COMPAREOP_MAX_ENUM_VALUE) { \
+        SDL_assert_release(!"Invalid compare op enum!");                          \
+        return retval;                                                            \
+    }
+
+#define CHECK_STENCILOP_ENUM_INVALID(enumval, retval)                                \
+    if (enumval <= SDL_GPU_STENCILOP_INVALID || enumval >= SDL_GPU_STENCILOP_MAX_ENUM_VALUE) { \
+        SDL_assert_release(!"Invalid stencil op enum!");                            \
+        return retval;                                                              \
+    }
+
+#define CHECK_BLENDOP_ENUM_INVALID(enumval, retval)                              \
+    if (enumval <= SDL_GPU_BLENDOP_INVALID || enumval >= SDL_GPU_BLENDOP_MAX_ENUM_VALUE) { \
+        SDL_assert_release(!"Invalid blend op enum!");                          \
+        return retval;                                                          \
+    }
+
+#define CHECK_BLENDFACTOR_ENUM_INVALID(enumval, retval)                                  \
+    if (enumval <= SDL_GPU_BLENDFACTOR_INVALID || enumval >= SDL_GPU_BLENDFACTOR_MAX_ENUM_VALUE) { \
+        SDL_assert_release(!"Invalid blend factor enum!");                              \
+        return retval;                                                                  \
+    }
+
 #define CHECK_SWAPCHAINCOMPOSITION_ENUM_INVALID(enumval, retval)    \
-    if (enumval >= SDL_GPU_SWAPCHAINCOMPOSITION_MAX) {              \
+    if (enumval < 0 || enumval >= SDL_GPU_SWAPCHAINCOMPOSITION_MAX_ENUM_VALUE) {              \
         SDL_assert_release(!"Invalid swapchain composition enum!"); \
         return retval;                                              \
     }
 
 #define CHECK_PRESENTMODE_ENUM_INVALID(enumval, retval)    \
-    if (enumval >= SDL_GPU_PRESENTMODE_MAX) {              \
+    if (enumval < 0 || enumval >= SDL_GPU_PRESENTMODE_MAX_ENUM_VALUE) {              \
         SDL_assert_release(!"Invalid present mode enum!"); \
         return retval;                                     \
     }
@@ -190,7 +220,7 @@ SDL_GPUGraphicsPipeline *SDL_GPU_FetchBlitPipeline(
     }
 
     blit_pipeline_create_info.multisample_state.sample_count = SDL_GPU_SAMPLECOUNT_1;
-    blit_pipeline_create_info.multisample_state.sample_mask = 0xFFFFFFFF;
+    blit_pipeline_create_info.multisample_state.enable_mask = SDL_FALSE;
 
     blit_pipeline_create_info.primitive_type = SDL_GPU_PRIMITIVETYPE_TRIANGLELIST;
 
@@ -590,11 +620,14 @@ SDL_GPUComputePipeline *SDL_CreateGPUComputePipeline(
     }
 
     if (device->debug_mode) {
+        if (createinfo->format == SDL_GPU_SHADERFORMAT_INVALID) {
+            SDL_assert_release(!"Shader format cannot be INVALID!");
+            return NULL;
+        }
         if (!(createinfo->format & device->shader_formats)) {
             SDL_assert_release(!"Incompatible shader format for GPU backend");
             return NULL;
         }
-
         if (createinfo->num_writeonly_storage_textures > MAX_COMPUTE_WRITE_TEXTURES) {
             SDL_assert_release(!"Compute pipeline write-only texture count cannot be higher than 8!");
             return NULL;
@@ -627,12 +660,25 @@ SDL_GPUGraphicsPipeline *SDL_CreateGPUGraphicsPipeline(
     }
 
     if (device->debug_mode) {
+        if (graphicsPipelineCreateInfo->target_info.num_color_targets > 0 && graphicsPipelineCreateInfo->target_info.color_target_descriptions == NULL) {
+            SDL_assert_release(!"Color target descriptions array pointer cannot be NULL if num_color_targets is greater than zero!");
+            return NULL;
+        }
         for (Uint32 i = 0; i < graphicsPipelineCreateInfo->target_info.num_color_targets; i += 1) {
             CHECK_TEXTUREFORMAT_ENUM_INVALID(graphicsPipelineCreateInfo->target_info.color_target_descriptions[i].format, NULL);
             if (IsDepthFormat(graphicsPipelineCreateInfo->target_info.color_target_descriptions[i].format)) {
                 SDL_assert_release(!"Color target formats cannot be a depth format!");
                 return NULL;
             }
+            if (graphicsPipelineCreateInfo->target_info.color_target_descriptions[i].blend_state.enable_blend) {
+                const SDL_GPUColorTargetBlendState *blend_state = &graphicsPipelineCreateInfo->target_info.color_target_descriptions[i].blend_state;
+                CHECK_BLENDFACTOR_ENUM_INVALID(blend_state->src_color_blendfactor, NULL)
+                CHECK_BLENDFACTOR_ENUM_INVALID(blend_state->dst_color_blendfactor, NULL)
+                CHECK_BLENDOP_ENUM_INVALID(blend_state->color_blend_op, NULL)
+                CHECK_BLENDFACTOR_ENUM_INVALID(blend_state->src_alpha_blendfactor, NULL)
+                CHECK_BLENDFACTOR_ENUM_INVALID(blend_state->dst_alpha_blendfactor, NULL)
+                CHECK_BLENDOP_ENUM_INVALID(blend_state->alpha_blend_op, NULL)
+            }
         }
         if (graphicsPipelineCreateInfo->target_info.has_depth_stencil_target) {
             CHECK_TEXTUREFORMAT_ENUM_INVALID(graphicsPipelineCreateInfo->target_info.depth_stencil_format, NULL);
@@ -641,6 +687,27 @@ SDL_GPUGraphicsPipeline *SDL_CreateGPUGraphicsPipeline(
                 return NULL;
             }
         }
+        if (graphicsPipelineCreateInfo->vertex_input_state.num_vertex_bindings > 0 && graphicsPipelineCreateInfo->vertex_input_state.vertex_bindings == NULL) {
+            SDL_assert_release(!"Vertex bindings array pointer cannot be NULL!");
+            return NULL;
+        }
+        if (graphicsPipelineCreateInfo->vertex_input_state.num_vertex_attributes > 0 && graphicsPipelineCreateInfo->vertex_input_state.vertex_attributes == NULL) {
+            SDL_assert_release(!"Vertex attributes array pointer cannot be NULL!");
+            return NULL;
+        }
+        for (Uint32 i = 0; i < graphicsPipelineCreateInfo->vertex_input_state.num_vertex_attributes; i += 1) {
+            CHECK_VERTEXELEMENTFORMAT_ENUM_INVALID(graphicsPipelineCreateInfo->vertex_input_state.vertex_attributes[i].format, NULL);
+        }
+        if (graphicsPipelineCreateInfo->depth_stencil_state.enable_depth_test) {
+            CHECK_COMPAREOP_ENUM_INVALID(graphicsPipelineCreateInfo->depth_stencil_state.compare_op, NULL)
+        }
+        if (graphicsPipelineCreateInfo->depth_stencil_state.enable_stencil_test) {
+            const SDL_GPUStencilOpState *stencil_state = &graphicsPipelineCreateInfo->depth_stencil_state.back_stencil_state;
+            CHECK_COMPAREOP_ENUM_INVALID(stencil_state->compare_op, NULL)
+            CHECK_STENCILOP_ENUM_INVALID(stencil_state->fail_op, NULL)
+            CHECK_STENCILOP_ENUM_INVALID(stencil_state->pass_op, NULL)
+            CHECK_STENCILOP_ENUM_INVALID(stencil_state->depth_fail_op, NULL)
+        }
     }
 
     return device->CreateGraphicsPipeline(
@@ -674,6 +741,10 @@ SDL_GPUShader *SDL_CreateGPUShader(
     }
 
     if (device->debug_mode) {
+        if (createinfo->format == SDL_GPU_SHADERFORMAT_INVALID) {
+            SDL_assert_release(!"Shader format cannot be INVALID!");
+            return NULL;
+        }
         if (!(createinfo->format & device->shader_formats)) {
             SDL_assert_release(!"Incompatible shader format for GPU backend");
             return NULL;
@@ -1909,6 +1980,14 @@ void SDL_UploadToGPUTexture(
 
     if (COPYPASS_DEVICE->debug_mode) {
         CHECK_COPYPASS
+        if (source->transfer_buffer == NULL) {
+            SDL_assert_release(!"Source transfer buffer cannot be NULL!");
+            return;
+        }
+        if (destination->texture == NULL) {
+            SDL_assert_release(!"Destination texture cannot be NULL!");
+            return;
+        }
     }
 
     COPYPASS_DEVICE->UploadToTexture(
@@ -1937,6 +2016,18 @@ void SDL_UploadToGPUBuffer(
         return;
     }
 
+    if (COPYPASS_DEVICE->debug_mode) {
+        CHECK_COPYPASS
+        if (source->transfer_buffer == NULL) {
+            SDL_assert_release(!"Source transfer buffer cannot be NULL!");
+            return;
+        }
+        if (destination->buffer == NULL) {
+            SDL_assert_release(!"Destination buffer cannot be NULL!");
+            return;
+        }
+    }
+
     COPYPASS_DEVICE->UploadToBuffer(
         COPYPASS_COMMAND_BUFFER,
         source,
@@ -1966,6 +2057,18 @@ void SDL_CopyGPUTextureToTexture(
         return;
     }
 
+    if (COPYPASS_DEVICE->debug_mode) {
+        CHECK_COPYPASS
+        if (source->texture == NULL) {
+            SDL_assert_release(!"Source texture cannot be NULL!");
+            return;
+        }
+        if (destination->texture == NULL) {
+            SDL_assert_release(!"Destination texture cannot be NULL!");
+            return;
+        }
+    }
+
     COPYPASS_DEVICE->CopyTextureToTexture(
         COPYPASS_COMMAND_BUFFER,
         source,
@@ -1996,6 +2099,18 @@ void SDL_CopyGPUBufferToBuffer(
         return;
     }
 
+    if (COPYPASS_DEVICE->debug_mode) {
+        CHECK_COPYPASS
+        if (source->buffer == NULL) {
+            SDL_assert_release(!"Source buffer cannot be NULL!");
+            return;
+        }
+        if (destination->buffer == NULL) {
+            SDL_assert_release(!"Destination buffer cannot be NULL!");
+            return;
+        }
+    }
+
     COPYPASS_DEVICE->CopyBufferToBuffer(
         COPYPASS_COMMAND_BUFFER,
         source,
@@ -2022,6 +2137,18 @@ void SDL_DownloadFromGPUTexture(
         return;
     }
 
+    if (COPYPASS_DEVICE->debug_mode) {
+        CHECK_COPYPASS
+        if (source->texture == NULL) {
+            SDL_assert_release(!"Source texture cannot be NULL!");
+            return;
+        }
+        if (destination->transfer_buffer == NULL) {
+            SDL_assert_release(!"Destination transfer buffer cannot be NULL!");
+            return;
+        }
+    }
+
     COPYPASS_DEVICE->DownloadFromTexture(
         COPYPASS_COMMAND_BUFFER,
         source,
@@ -2046,6 +2173,18 @@ void SDL_DownloadFromGPUBuffer(
         return;
     }
 
+    if (COPYPASS_DEVICE->debug_mode) {
+        CHECK_COPYPASS
+        if (source->buffer == NULL) {
+            SDL_assert_release(!"Source buffer cannot be NULL!");
+            return;
+        }
+        if (destination->transfer_buffer == NULL) {
+            SDL_assert_release(!"Destination transfer buffer cannot be NULL!");
+            return;
+        }
+    }
+
     COPYPASS_DEVICE->DownloadFromBuffer(
         COPYPASS_COMMAND_BUFFER,
         source,
diff --git a/src/gpu/SDL_sysgpu.h b/src/gpu/SDL_sysgpu.h
index 47a9653205350..1706071dc2082 100644
--- a/src/gpu/SDL_sysgpu.h
+++ b/src/gpu/SDL_sysgpu.h
@@ -69,9 +69,14 @@ typedef struct BlitPipelineCacheEntry
 
 // Internal Helper Utilities
 
-#define SDL_GPU_TEXTUREFORMAT_MAX        (SDL_GPU_TEXTUREFORMAT_D32_FLOAT_S8_UINT + 1)
-#define SDL_GPU_SWAPCHAINCOMPOSITION_MAX (SDL_GPU_SWAPCHAINCOMPOSITION_HDR10_ST2048 + 1)
-#define SDL_GPU_PRESENTMODE_MAX          (SDL_GPU_PRESENTMODE_MAILBOX + 1)
+#define SDL_GPU_TEXTUREFORMAT_MAX_ENUM_VALUE        (SDL_GPU_TEXTUREFORMAT_D32_FLOAT_S8_UINT + 1)
+#define SDL_GPU_VERTEXELEMENTFORMAT_MAX_ENUM_VALUE  (SDL_GPU_VERTEXELEMENTFORMAT_HALF4 + 1)
+#define SDL_GPU_COMPAREOP_MAX_ENUM_VALUE            (SDL_GPU_COMPAREOP_ALWAYS + 1)
+#define SDL_GPU_STENCILOP_MAX_ENUM_VALUE            (SDL_GPU_STENCILOP_DECREMENT_AND_WRAP + 1)
+#define SDL_GPU_BLENDOP_MAX_ENUM_VALUE              (SDL_GPU_BLENDOP_MAX + 1)
+#define SDL_GPU_BLENDFACTOR_MAX_ENUM_VALUE          (SDL_GPU_BLENDFACTOR_SRC_ALPHA_SATURATE + 1)
+#define SDL_GPU_SWAPCHAINCOMPOSITION_MAX_ENUM_VALUE (SDL_GPU_SWAPCHAINCOMPOSITION_HDR10_ST2048 + 1)
+#define SDL_GPU_PRESENTMODE_MAX_ENUM_VALUE          (SDL_GPU_PRESENTMODE_MAILBOX + 1)
 
 static inline Sint32 Texture_GetBlockSize(
     SDL_GPUTextureFormat format)
diff --git a/src/gpu/d3d11/SDL_gpu_d3d11.c b/src/gpu/d3d11/SDL_gpu_d3d11.c
index e2df614302544..711688ae3b635 100644
--- a/src/gpu/d3d11/SDL_gpu_d3d11.c
+++ b/src/gpu/d3d11/SDL_gpu_d3d11.c
@@ -168,6 +168,7 @@ static DXGI_COLOR_SPACE_TYPE SwapchainCompositionToColorSpace[] = {
 };
 
 static DXGI_FORMAT SDLToD3D11_TextureFormat[] = {
+    DXGI_FORMAT_UNKNOWN,              // INVALID
     DXGI_FORMAT_A8_UNORM,             // A8_UNORM
     DXGI_FORMAT_R8_UNORM,             // R8_UNORM
     DXGI_FORMAT_R8G8_UNORM,           // R8G8_UNORM
@@ -225,9 +226,10 @@ static DXGI_FORMAT SDLToD3D11_TextureFormat[] = {
     DXGI_FORMAT_D24_UNORM_S8_UINT,    // D24_UNORM_S8_UINT
     DXGI_FORMAT_D32_FLOAT_S8X24_UINT, // D32_FLOAT_S8_UINT
 };
-SDL_COMPILE_TIME_ASSERT(SDLToD3D11_TextureFormat, SDL_arraysize(SDLToD3D11_TextureFormat) == SDL_GPU_TEXTUREFORMAT_MAX);
+SDL_COMPILE_TIME_ASSERT(SDLToD3D11_TextureFormat, SDL_arraysize(SDLToD3D11_TextureFormat) == SDL_GPU_TEXTUREFORMAT_MAX_ENUM_VALUE);
 
 static DXGI_FORMAT SDLToD3D11_VertexFormat[] = {
+    DXGI_FORMAT_UNKNOWN,            // INVALID
     DXGI_FORMAT_R32_SINT,           // INT
     DXGI_FORMAT_R32G32_SINT,        // INT2
     DXGI_FORMAT_R32G32B32_SINT,     // INT3
@@ -259,6 +261,7 @@ static DXGI_FORMAT SDLToD3D11_VertexFormat[] = {
     DXGI_FORMAT_R16G16_FLOAT,       // HALF2
     DXGI_FORMAT_R16G16B16A16_FLOAT  // HALF4
 };
+SDL_COMPILE_TIME_ASSERT(SDLToD3D11_VertexFormat, SDL_arraysize(SDLToD3D11_VertexFormat) == SDL_GPU_VERTEXELEMENTFORMAT_MAX_ENUM_VALUE);
 
 static Uint32 SDLToD3D11_SampleCount[] = {
     1, // SDL_GPU_SAMPLECOUNT_1
@@ -273,11 +276,11 @@ static DXGI_FORMAT SDLToD3D11_IndexType[] = {
 };
 
 static D3D11_PRIMITIVE_TOPOLOGY SDLToD3D11_PrimitiveType[] = {
-    D3D_PRIMITIVE_TOPOLOGY_POINTLIST,    // POINTLIST
-    D3D_PRIMITIVE_TOPOLOGY_LINELIST,     // LINELIST
-    D3D_PRIMITIVE_TOPOLOGY_LINESTRIP,    // LINESTRIP
-    D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST, // TRIANGLELIST
-    D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP // TRIANGLESTRIP
+    D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST,  // TRIANGLELIST
+    D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP, // TRIANGLESTRIP
+    D3D_PRIMITIVE_TOPOLOGY_LINELIST,      // LINELIST
+    D3D_PRIMITIVE_TOPOLOGY_LINESTRIP,     // LINESTRIP
+    D3D_PRIMITIVE_TOPOLOGY_POINTLIST      // POINTLIST
 };
 
 static D3D11_CULL_MODE SDLToD3D11_CullMode[] = {
@@ -287,6 +290,7 @@ static D3D11_CULL_MODE SDLToD3D11_CullMode[] = {
 };
 
 static D3D11_BLEND SDLToD3D11_BlendFactor[] = {
+    D3D11_BLEND_ZERO,             // INVALID
     D3D11_BLEND_ZERO,             // ZERO
     D3D11_BLEND_ONE,              // ONE
     D3D11_BLEND_SRC_COLOR,        // SRC_COLOR
@@ -301,8 +305,10 @@ static D3D11_BLEND SDLToD3D11_BlendFactor[] = {
     D3D11_BLEND_INV_BLEND_FACTOR, // ONE_MINUS_CONSTANT_COLOR
     D3D11_BLEND_SRC_ALPHA_SAT,    // SRC_ALPHA_SATURATE
 };
+SDL_COMPILE_TIME_ASSERT(SDLToD3D11_BlendFactor, SDL_arraysize(SDLToD3D11_BlendFactor) == SDL_GPU_BLENDFACTOR_MAX_ENUM_VALUE);
 
 static D3D11_BLEND SDLToD3D11_BlendFactorAlpha[] = {
+    D3D11_BLEND_ZERO,             // ALPHA
     D3D11_BLEND_ZERO,             // ZERO
     D3D11_BLEND_ONE,              // ONE
     D3D11_BLEND_SRC_ALPHA,        // SRC_COLOR
@@ -317,16 +323,20 @@ static D3D11_BLEND SDLToD3D11_BlendFactorAlpha[] = {
     D3D11_BLEND_INV_BLEND_FACTOR, // ONE_MINUS_CONSTANT_COLOR
     D3D11_BLEND_SRC_ALPHA_SAT,    // SRC_ALPHA_SATURATE
 };
+SDL_COMPILE_TIME_ASSERT(SDLToD3D11_BlendFactorAlpha, SDL_arraysize(SDLToD3D11_BlendFactorAlpha) == SDL_GPU_BLENDFACTOR_MAX_ENUM_VALUE);
 
 static D3D11_BLEND_OP SDLToD3D11_BlendOp[] = {
+    D3D11_BLEND_OP_ADD,          // INVALID
     D3D11_BLEND_OP_ADD,          // ADD
     D3D11_BLEND_OP_SUBTRACT,     // SUBTRACT
     D3D11_BLEND_OP_REV_SUBTRACT, // REVERSE_SUBTRACT
     D3D11_BLEND_OP_MIN,          // MIN
     D3D11_BLEND_OP_MAX           // MAX
 };
+SDL_COMPILE_TIME_ASSERT(SDLToD3D11_BlendOp, SDL_arraysize(SDLToD3D11_BlendOp) == SDL_GPU_BLENDOP_MAX_ENUM_VALUE);
 
 static D3D11_COMPARISON_FUNC SDLToD3D11_CompareOp[] = {
+    D3D11_COMPARISON_NEVER,         // INVALID
     D3D11_COMPARISON_NEVER,         // NEVER
     D3D11_COMPARISON_LESS,          // LESS
     D3D11_COMPARISON_EQUAL,         // EQUAL
@@ -336,8 +346,10 @@ static D3D11_COMPARISON_FUNC SDLToD3D11_CompareOp[] = {
     D3D11_COMPARISON_GREATER_EQUAL, // GREATER_OR_EQUAL
     D3D11_COMPARISON_ALWAYS         // ALWAYS
 };
+SDL_COMPILE_TIME_ASSERT(SDLToD3D11_CompareOp, SDL_arraysize(SDLToD3D11_CompareOp) == SDL_GPU_COMPAREOP_MAX_ENUM_VALUE);
 
 static D3D11_STENCIL_OP SDLToD3D11_StencilOp[] = {
+    D3D11_STENCIL_OP_KEEP,     // INVALID
     D3D11_STENCIL_OP_KEEP,     // KEEP
     D3D11_STENCIL_OP_ZERO,     // ZERO
     D3D11_STENCIL_OP_REPLACE,  // REPLACE
@@ -347,6 +359,7 @@ static D3D11_STENCIL_OP SDLToD3D11_StencilOp[] = {
     D3D11_STENCIL_OP_INCR,     // INCREMENT_AND_WRAP
     D3D11_STENCIL_OP_DECR      // DECREMENT_AND_WRAP
 };
+SDL_COMPILE_TIME_ASSERT(SDLToD3D11_StencilOp, SDL_arraysize(SDLToD3D11_StencilOp) == SDL_GPU_STENCILOP_MAX_ENUM_VALUE);
 
 static D3D11_INPUT_CLASSIFICATION SDLToD3D11_VertexInputRate[] = {
     D3D11_INPUT_PER_VERTEX_DATA,  // VERTEX
@@ -1

(Patch may be truncated, please check the link at the top of this post.)