SDL: gpu: Validate that reserved struct members are unset

From 60b7faa9871b18fa51ae789146d742ffb629268b Mon Sep 17 00:00:00 2001
From: Caleb Cornett <[EMAIL REDACTED]>
Date: Mon, 24 Feb 2025 11:21:09 -0500
Subject: [PATCH] gpu: Validate that reserved struct members are unset

---
 include/SDL3/SDL_gpu.h |  6 +++---
 src/gpu/SDL_gpu.c      | 15 +++++++++++++++
 2 files changed, 18 insertions(+), 3 deletions(-)

diff --git a/include/SDL3/SDL_gpu.h b/include/SDL3/SDL_gpu.h
index ce54423097e74..c969c19d5baaf 100644
--- a/include/SDL3/SDL_gpu.h
+++ b/include/SDL3/SDL_gpu.h
@@ -1550,7 +1550,7 @@ typedef struct SDL_GPUVertexBufferDescription
     Uint32 slot;                        /**< The binding slot of the vertex buffer. */
     Uint32 pitch;                       /**< The byte pitch between consecutive elements of the vertex buffer. */
     SDL_GPUVertexInputRate input_rate;  /**< Whether attribute addressing is a function of the vertex index or instance index. */
-    Uint32 instance_step_rate;          /**< Ignored, reserved for future use. */
+    Uint32 instance_step_rate;          /**< Reserved for future use. Must be set to 0. */
 } SDL_GPUVertexBufferDescription;
 
 /**
@@ -1757,8 +1757,8 @@ typedef struct SDL_GPURasterizerState
 typedef struct SDL_GPUMultisampleState
 {
     SDL_GPUSampleCount sample_count;  /**< The number of samples to be used in rasterization. */
-    Uint32 sample_mask;               /**< Ignored, reserved for future use. */
-    bool enable_mask;             /**< Ignored, reserved for future use. */
+    Uint32 sample_mask;               /**< Reserved for future use. Must be set to 0. */
+    bool enable_mask;             /**< Reserved for future use. Must be set to false. */
     Uint8 padding1;
     Uint8 padding2;
     Uint8 padding3;
diff --git a/src/gpu/SDL_gpu.c b/src/gpu/SDL_gpu.c
index 72f15569bad50..f2add3534b565 100644
--- a/src/gpu/SDL_gpu.c
+++ b/src/gpu/SDL_gpu.c
@@ -854,6 +854,12 @@ SDL_GPUGraphicsPipeline *SDL_CreateGPUGraphicsPipeline(
             SDL_assert_release(!"The number of vertex attributes in a vertex input state must not exceed 16!");
             return NULL;
         }
+        for (Uint32 i = 0; i < graphicsPipelineCreateInfo->vertex_input_state.num_vertex_buffers; i += 1) {
+            if (graphicsPipelineCreateInfo->vertex_input_state.vertex_buffer_descriptions[i].instance_step_rate != 0) {
+                SDL_assert_release(!"For all vertex buffer descriptions, instance_step_rate must be 0!");
+                return NULL;
+            }
+        }
         Uint32 locations[MAX_VERTEX_ATTRIBUTES];
         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);
@@ -862,9 +868,18 @@ SDL_GPUGraphicsPipeline *SDL_CreateGPUGraphicsPipeline(
             for (Uint32 j = 0; j < i; j += 1) {
                 if (locations[j] == locations[i]) {
                     SDL_assert_release(!"Each vertex attribute location in a vertex input state must be unique!");
+                    return NULL;
                 }
             }
         }
+        if (graphicsPipelineCreateInfo->multisample_state.enable_mask) {
+            SDL_assert_release(!"For multisample states, enable_mask must be false!");
+            return NULL;
+        }
+        if (graphicsPipelineCreateInfo->multisample_state.sample_mask != 0) {
+            SDL_assert_release(!"For multisample states, sample_mask must be 0!");
+            return NULL;
+        }
         if (graphicsPipelineCreateInfo->depth_stencil_state.enable_depth_test) {
             CHECK_COMPAREOP_ENUM_INVALID(graphicsPipelineCreateInfo->depth_stencil_state.compare_op, NULL)
         }