SDL: GPU: Rename VertexBinding to VertexBufferDescription (#10811)

From a45a2caf4930274b012d4b3c0fa22cd66285f173 Mon Sep 17 00:00:00 2001
From: Caleb Cornett <[EMAIL REDACTED]>
Date: Thu, 12 Sep 2024 18:02:39 -0500
Subject: [PATCH] GPU: Rename VertexBinding to VertexBufferDescription (#10811)

---
 include/SDL3/SDL_gpu.h            | 40 ++++++++++++++------------
 src/gpu/SDL_gpu.c                 | 20 +++++++++++--
 src/gpu/SDL_sysgpu.h              |  5 ++--
 src/gpu/d3d11/SDL_gpu_d3d11.c     | 48 ++++++++++++++++---------------
 src/gpu/d3d12/SDL_gpu_d3d12.c     | 28 +++++++++---------
 src/gpu/metal/SDL_gpu_metal.m     | 20 +++++++------
 src/gpu/vulkan/SDL_gpu_vulkan.c   | 30 +++++++++----------
 src/render/gpu/SDL_pipeline_gpu.c | 20 ++++++-------
 test/testgpu_spinning_cube.c      | 22 +++++++-------
 9 files changed, 130 insertions(+), 103 deletions(-)

diff --git a/include/SDL3/SDL_gpu.h b/include/SDL3/SDL_gpu.h
index 9bf2ad313bfd1..5afc74fbe2f44 100644
--- a/include/SDL3/SDL_gpu.h
+++ b/include/SDL3/SDL_gpu.h
@@ -1179,42 +1179,46 @@ typedef struct SDL_GPUSamplerCreateInfo
 } SDL_GPUSamplerCreateInfo;
 
 /**
- * A structure specifying a vertex binding.
+ * A structure specifying the parameters of vertex buffers used in a graphics
+ * pipeline.
  *
- * When you call SDL_BindGPUVertexBuffers, you specify the binding indices of
+ * When you call SDL_BindGPUVertexBuffers, you specify the binding slots of
  * the vertex buffers. For example if you called SDL_BindGPUVertexBuffers with
- * a first_binding of 2 and num_bindings of 3, the binding indices 2, 3, 4
- * would be used by the vertex buffers you pass in.
+ * a first_slot of 2 and num_bindings of 3, the binding slots 2, 3, 4 would be
+ * used by the vertex buffers you pass in.
  *
- * Vertex attributes are linked to bindings via the index. The binding_index
- * field of SDL_GPUVertexAttribute specifies the vertex buffer binding index
- * that the attribute will be read from.
+ * Vertex attributes are linked to buffers via the buffer_slot field of
+ * SDL_GPUVertexAttribute. For example, if an attribute has a buffer_slot of 0,
+ * then that attribute belongs to the vertex buffer bound at slot 0.
  *
  * \since This struct is available since SDL 3.0.0
  *
  * \sa SDL_GPUVertexAttribute
  * \sa SDL_GPUVertexInputState
  */
-typedef struct SDL_GPUVertexBinding
+typedef struct SDL_GPUVertexBufferDescription
 {
-    Uint32 index;                     /**< The binding index. */
+    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;          /**< The number of instances to draw using the same per-instance data before advancing in the instance buffer by one element. Ignored unless input_rate is SDL_GPU_VERTEXINPUTRATE_INSTANCE */
-} SDL_GPUVertexBinding;
+} SDL_GPUVertexBufferDescription;
 
 /**
  * A structure specifying a vertex attribute.
  *
+ * All vertex attribute locations provided to an SDL_GPUVertexInputState
+ * must be unique.
+ *
  * \since This struct is available since SDL 3.0.0
  *
- * \sa SDL_GPUVertexBinding
+ * \sa SDL_GPUVertexBufferDescription
  * \sa SDL_GPUVertexInputState
  */
 typedef struct SDL_GPUVertexAttribute
 {
     Uint32 location;                    /**< The shader input location index. */
-    Uint32 binding_index;               /**< The binding index. */
+    Uint32 buffer_slot;                 /**< The binding slot of the associated vertex buffer. */
     SDL_GPUVertexElementFormat format;  /**< The size and type of the attribute data. */
     Uint32 offset;                      /**< The byte offset of this attribute relative to the start of the vertex element. */
 } SDL_GPUVertexAttribute;
@@ -1229,10 +1233,10 @@ typedef struct SDL_GPUVertexAttribute
  */
 typedef struct SDL_GPUVertexInputState
 {
-    const SDL_GPUVertexBinding *vertex_bindings;      /**< A pointer to an array of vertex binding descriptions. */
-    Uint32 num_vertex_bindings;                       /**< The number of vertex binding descriptions in the above array. */
-    const SDL_GPUVertexAttribute *vertex_attributes;  /**< A pointer to an array of vertex attribute descriptions. */
-    Uint32 num_vertex_attributes;                     /**< The number of vertex attribute descriptions in the above array. */
+    const SDL_GPUVertexBufferDescription *vertex_buffer_descriptions; /**< A pointer to an array of vertex buffer descriptions. */
+    Uint32 num_vertex_buffers;                                        /**< The number of vertex buffer descriptions in the above array. */
+    const SDL_GPUVertexAttribute *vertex_attributes;                  /**< A pointer to an array of vertex attribute descriptions. */
+    Uint32 num_vertex_attributes;                                     /**< The number of vertex attribute descriptions in the above array. */
 } SDL_GPUVertexInputState;
 
 /**
@@ -2447,7 +2451,7 @@ extern SDL_DECLSPEC void SDLCALL SDL_SetGPUStencilReference(
  * calls.
  *
  * \param render_pass a render pass handle.
- * \param first_binding the starting bind point for the vertex buffers.
+ * \param first_slot the vertex buffer slot to begin binding from.
  * \param bindings an array of SDL_GPUBufferBinding structs containing vertex
  *                 buffers and offset values.
  * \param num_bindings the number of bindings in the bindings array.
@@ -2456,7 +2460,7 @@ extern SDL_DECLSPEC void SDLCALL SDL_SetGPUStencilReference(
  */
 extern SDL_DECLSPEC void SDLCALL SDL_BindGPUVertexBuffers(
     SDL_GPURenderPass *render_pass,
-    Uint32 first_binding,
+    Uint32 first_slot,
     const SDL_GPUBufferBinding *bindings,
     Uint32 num_bindings);
 
diff --git a/src/gpu/SDL_gpu.c b/src/gpu/SDL_gpu.c
index 6d33cf36835f3..ed86ab21265a4 100644
--- a/src/gpu/SDL_gpu.c
+++ b/src/gpu/SDL_gpu.c
@@ -692,16 +692,32 @@ 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!");
+        if (graphicsPipelineCreateInfo->vertex_input_state.num_vertex_buffers > 0 && graphicsPipelineCreateInfo->vertex_input_state.vertex_buffer_descriptions == NULL) {
+            SDL_assert_release(!"Vertex buffer descriptions array pointer cannot be NULL!");
+            return NULL;
+        }
+        if (graphicsPipelineCreateInfo->vertex_input_state.num_vertex_buffers > MAX_VERTEX_BUFFERS) {
+            SDL_assert_release(!"The number of vertex buffer descriptions in a vertex input state must not exceed 16!");
             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;
         }
+        if (graphicsPipelineCreateInfo->vertex_input_state.num_vertex_attributes > MAX_VERTEX_ATTRIBUTES) {
+            SDL_assert_release(!"The number of vertex attributes in a vertex input state must not exceed 16!");
+            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);
+
+            locations[i] = graphicsPipelineCreateInfo->vertex_input_state.vertex_attributes[i].location;
+            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!");
+                }
+            }
         }
         if (graphicsPipelineCreateInfo->depth_stencil_state.enable_depth_test) {
             CHECK_COMPAREOP_ENUM_INVALID(graphicsPipelineCreateInfo->depth_stencil_state.compare_op, NULL)
diff --git a/src/gpu/SDL_sysgpu.h b/src/gpu/SDL_sysgpu.h
index fb295f4592560..79eef1964c584 100644
--- a/src/gpu/SDL_sysgpu.h
+++ b/src/gpu/SDL_sysgpu.h
@@ -232,7 +232,8 @@ static inline Sint32 BytesPerImage(
 #define MAX_COMPUTE_WRITE_TEXTURES     8
 #define MAX_COMPUTE_WRITE_BUFFERS      8
 #define UNIFORM_BUFFER_SIZE            32768
-#define MAX_BUFFER_BINDINGS            16
+#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
@@ -411,7 +412,7 @@ struct SDL_GPUDevice
 
     void (*BindVertexBuffers)(
         SDL_GPUCommandBuffer *commandBuffer,
-        Uint32 firstBinding,
+        Uint32 firstSlot,
         const SDL_GPUBufferBinding *bindings,
         Uint32 numBindings);
 
diff --git a/src/gpu/d3d11/SDL_gpu_d3d11.c b/src/gpu/d3d11/SDL_gpu_d3d11.c
index 39e1f3e8f9af0..7188754a37f3d 100644
--- a/src/gpu/d3d11/SDL_gpu_d3d11.c
+++ b/src/gpu/d3d11/SDL_gpu_d3d11.c
@@ -672,8 +672,8 @@ typedef struct D3D11CommandBuffer
     // defer OMSetBlendState because it combines three different states
     bool needBlendStateSet;
 
-    ID3D11Buffer *vertexBuffers[MAX_BUFFER_BINDINGS];
-    Uint32 vertexBufferOffsets[MAX_BUFFER_BINDINGS];
+    ID3D11Buffer *vertexBuffers[MAX_VERTEX_BUFFERS];
+    Uint32 vertexBufferOffsets[MAX_VERTEX_BUFFERS];
     Uint32 vertexBufferCount;
 
     D3D11Texture *vertexSamplerTextures[MAX_TEXTURE_SAMPLERS_PER_STAGE];
@@ -1380,18 +1380,18 @@ static ID3D11RasterizerState *D3D11_INTERNAL_FetchRasterizerState(
     return result;
 }
 
-static Uint32 D3D11_INTERNAL_FindIndexOfVertexBinding(
-    Uint32 targetBinding,
-    const SDL_GPUVertexBinding *bindings,
-    Uint32 numBindings)
+static Uint32 D3D11_INTERNAL_FindIndexOfVertexSlot(
+    Uint32 targetSlot,
+    const SDL_GPUVertexBufferDescription *bufferDescriptions,
+    Uint32 numDescriptions)
 {
-    for (Uint32 i = 0; i < numBindings; i += 1) {
-        if (bindings[i].index == targetBinding) {
+    for (Uint32 i = 0; i < numDescriptions; i += 1) {
+        if (bufferDescriptions[i].slot == targetSlot) {
             return i;
         }
     }
 
-    SDL_LogError(SDL_LOG_CATEGORY_GPU, "Could not find vertex binding %u!", targetBinding);
+    SDL_LogError(SDL_LOG_CATEGORY_GPU, "Could not find vertex buffer slot %u!", targetSlot);
     return 0;
 }
 
@@ -1420,15 +1420,17 @@ static ID3D11InputLayout *D3D11_INTERNAL_FetchInputLayout(
     for (Uint32 i = 0; i < inputState.num_vertex_attributes; i += 1) {
         elementDescs[i].AlignedByteOffset = inputState.vertex_attributes[i].offset;
         elementDescs[i].Format = SDLToD3D11_VertexFormat[inputState.vertex_attributes[i].format];
-        elementDescs[i].InputSlot = inputState.vertex_attributes[i].binding_index;
+        elementDescs[i].InputSlot = inputState.vertex_attributes[i].buffer_slot;
 
-        bindingIndex = D3D11_INTERNAL_FindIndexOfVertexBinding(
+        bindingIndex = D3D11_INTERNAL_FindIndexOfVertexSlot(
             elementDescs[i].InputSlot,
-            inputState.vertex_bindings,
-            inputState.num_vertex_bindings);
-        elementDescs[i].InputSlotClass = SDLToD3D11_VertexInputRate[inputState.vertex_bindings[bindingIndex].input_rate];
+            inputState.vertex_buffer_descriptions,
+            inputState.num_vertex_buffers);
+        elementDescs[i].InputSlotClass = SDLToD3D11_VertexInputRate[inputState.vertex_buffer_descriptions[bindingIndex].input_rate];
         // The spec requires this to be 0 for per-vertex data
-        elementDescs[i].InstanceDataStepRate = (inputState.vertex_bindings[bindingIndex].input_rate == SDL_GPU_VERTEXINPUTRATE_INSTANCE) ? inputState.vertex_bindings[bindingIndex].instance_step_rate : 0;
+        elementDescs[i].InstanceDataStepRate = (inputState.vertex_buffer_descriptions[bindingIndex].input_rate == SDL_GPU_VERTEXINPUTRATE_INSTANCE)
+            ? inputState.vertex_buffer_descriptions[bindingIndex].instance_step_rate
+            : 0;
 
         elementDescs[i].SemanticIndex = inputState.vertex_attributes[i].location;
         elementDescs[i].SemanticName = "TEXCOORD";
@@ -1609,13 +1611,13 @@ static SDL_GPUGraphicsPipeline *D3D11_CreateGraphicsPipeline(
         vertShader->bytecode,
         vertShader->bytecodeSize);
 
-    if (createinfo->vertex_input_state.num_vertex_bindings > 0) {
+    if (createinfo->vertex_input_state.num_vertex_buffers > 0) {
         pipeline->vertexStrides = SDL_malloc(
             sizeof(Uint32) *
-            createinfo->vertex_input_state.num_vertex_bindings);
+            createinfo->vertex_input_state.num_vertex_buffers);
 
-        for (Uint32 i = 0; i < createinfo->vertex_input_state.num_vertex_bindings; i += 1) {
-            pipeline->vertexStrides[i] = createinfo->vertex_input_state.vertex_bindings[i].pitch;
+        for (Uint32 i = 0; i < createinfo->vertex_input_state.num_vertex_buffers; i += 1) {
+            pipeline->vertexStrides[i] = createinfo->vertex_input_state.vertex_buffer_descriptions[i].pitch;
         }
     } else {
         pipeline->vertexStrides = NULL;
@@ -3732,7 +3734,7 @@ static void D3D11_BindGraphicsPipeline(
 
 static void D3D11_BindVertexBuffers(
     SDL_GPUCommandBuffer *commandBuffer,
-    Uint32 firstBinding,
+    Uint32 firstSlot,
     const SDL_GPUBufferBinding *bindings,
     Uint32 numBindings)
 {
@@ -3740,13 +3742,13 @@ static void D3D11_BindVertexBuffers(
 
     for (Uint32 i = 0; i < numBindings; i += 1) {
         D3D11Buffer *currentBuffer = ((D3D11BufferContainer *)bindings[i].buffer)->activeBuffer;
-        d3d11CommandBuffer->vertexBuffers[firstBinding + i] = currentBuffer->handle;
-        d3d11CommandBuffer->vertexBufferOffsets[firstBinding + i] = bindings[i].offset;
+        d3d11CommandBuffer->vertexBuffers[firstSlot + i] = currentBuffer->handle;
+        d3d11CommandBuffer->vertexBufferOffsets[firstSlot + i] = bindings[i].offset;
         D3D11_INTERNAL_TrackBuffer(d3d11CommandBuffer, currentBuffer);
     }
 
     d3d11CommandBuffer->vertexBufferCount =
-        SDL_max(d3d11CommandBuffer->vertexBufferCount, firstBinding + numBindings);
+        SDL_max(d3d11CommandBuffer->vertexBufferCount, firstSlot + numBindings);
 
     d3d11CommandBuffer->needVertexBufferBind = true;
 }
diff --git a/src/gpu/d3d12/SDL_gpu_d3d12.c b/src/gpu/d3d12/SDL_gpu_d3d12.c
index 0c18bb526b713..e01cda26da3f5 100644
--- a/src/gpu/d3d12/SDL_gpu_d3d12.c
+++ b/src/gpu/d3d12/SDL_gpu_d3d12.c
@@ -702,8 +702,8 @@ struct D3D12CommandBuffer
     bool needComputeReadOnlyStorageBufferBind;
     bool needComputeUniformBufferBind[MAX_UNIFORM_BUFFERS_PER_STAGE];
 
-    D3D12Buffer *vertexBuffers[MAX_BUFFER_BINDINGS];
-    Uint32 vertexBufferOffsets[MAX_BUFFER_BINDINGS];
+    D3D12Buffer *vertexBuffers[MAX_VERTEX_BUFFERS];
+    Uint32 vertexBufferOffsets[MAX_VERTEX_BUFFERS];
     Uint32 vertexBufferCount;
 
     D3D12Texture *vertexSamplerTextures[MAX_TEXTURE_SAMPLERS_PER_STAGE];
@@ -792,7 +792,7 @@ struct D3D12GraphicsPipeline
     D3D12GraphicsRootSignature *rootSignature;
     SDL_GPUPrimitiveType primitiveType;
 
-    Uint32 vertexStrides[MAX_BUFFER_BINDINGS];
+    Uint32 vertexStrides[MAX_VERTEX_BUFFERS];
 
     Uint32 vertexSamplerCount;
     Uint32 vertexUniformBufferCount;
@@ -2531,10 +2531,12 @@ static bool D3D12_INTERNAL_ConvertVertexInputState(SDL_GPUVertexInputState verte
         desc[i].SemanticName = semantic;
         desc[i].SemanticIndex = attribute.location;
         desc[i].Format = SDLToD3D12_VertexFormat[attribute.format];
-        desc[i].InputSlot = attribute.binding_index;
+        desc[i].InputSlot = attribute.buffer_slot;
         desc[i].AlignedByteOffset = attribute.offset;
-        desc[i].InputSlotClass = SDLToD3D12_InputRate[vertexInputState.vertex_bindings[attribute.binding_index].input_rate];
-        desc[i].InstanceDataStepRate = (vertexInputState.vertex_bindings[attribute.binding_index].input_rate == SDL_GPU_VERTEXINPUTRATE_INSTANCE) ? vertexInputState.vertex_bindings[attribute.binding_index].instance_step_rate : 0;
+        desc[i].InputSlotClass = SDLToD3D12_InputRate[vertexInputState.vertex_buffer_descriptions[attribute.buffer_slot].input_rate];
+        desc[i].InstanceDataStepRate = (vertexInputState.vertex_buffer_descriptions[attribute.buffer_slot].input_rate == SDL_GPU_VERTEXINPUTRATE_INSTANCE)
+            ? vertexInputState.vertex_buffer_descriptions[attribute.buffer_slot].instance_step_rate
+            : 0;
     }
 
     return true;
@@ -2660,8 +2662,8 @@ static SDL_GPUGraphicsPipeline *D3D12_CreateGraphicsPipeline(
 
     pipeline->pipelineState = pipelineState;
 
-    for (Uint32 i = 0; i < createinfo->vertex_input_state.num_vertex_bindings; i += 1) {
-        pipeline->vertexStrides[i] = createinfo->vertex_input_state.vertex_bindings[i].pitch;
+    for (Uint32 i = 0; i < createinfo->vertex_input_state.num_vertex_buffers; i += 1) {
+        pipeline->vertexStrides[i] = createinfo->vertex_input_state.vertex_buffer_descriptions[i].pitch;
     }
 
     pipeline->primitiveType = createinfo->primitive_type;
@@ -4250,7 +4252,7 @@ static void D3D12_BindGraphicsPipeline(
 
 static void D3D12_BindVertexBuffers(
     SDL_GPUCommandBuffer *commandBuffer,
-    Uint32 firstBinding,
+    Uint32 firstSlot,
     const SDL_GPUBufferBinding *bindings,
     Uint32 numBindings)
 {
@@ -4258,13 +4260,13 @@ static void D3D12_BindVertexBuffers(
 
     for (Uint32 i = 0; i < numBindings; i += 1) {
         D3D12Buffer *currentBuffer = ((D3D12BufferContainer *)bindings[i].buffer)->activeBuffer;
-        d3d12CommandBuffer->vertexBuffers[firstBinding + i] = currentBuffer;
-        d3d12CommandBuffer->vertexBufferOffsets[firstBinding + i] = bindings[i].offset;
+        d3d12CommandBuffer->vertexBuffers[firstSlot + i] = currentBuffer;
+        d3d12CommandBuffer->vertexBufferOffsets[firstSlot + i] = bindings[i].offset;
         D3D12_INTERNAL_TrackBuffer(d3d12CommandBuffer, currentBuffer);
     }
 
     d3d12CommandBuffer->vertexBufferCount =
-        SDL_max(d3d12CommandBuffer->vertexBufferCount, firstBinding + numBindings);
+        SDL_max(d3d12CommandBuffer->vertexBufferCount, firstSlot + numBindings);
 
     d3d12CommandBuffer->needVertexBufferBind = true;
 }
@@ -4492,7 +4494,7 @@ static void D3D12_INTERNAL_BindGraphicsResources(
 
     D3D12_CPU_DESCRIPTOR_HANDLE cpuHandles[MAX_TEXTURE_SAMPLERS_PER_STAGE];
     D3D12_GPU_DESCRIPTOR_HANDLE gpuDescriptorHandle;
-    D3D12_VERTEX_BUFFER_VIEW vertexBufferViews[MAX_BUFFER_BINDINGS];
+    D3D12_VERTEX_BUFFER_VIEW vertexBufferViews[MAX_VERTEX_BUFFERS];
 
     if (commandBuffer->needVertexBufferBind) {
         for (Uint32 i = 0; i < commandBuffer->vertexBufferCount; i += 1) {
diff --git a/src/gpu/metal/SDL_gpu_metal.m b/src/gpu/metal/SDL_gpu_metal.m
index d3cdbfb3f6d34..f2361c82dd3ba 100644
--- a/src/gpu/metal/SDL_gpu_metal.m
+++ b/src/gpu/metal/SDL_gpu_metal.m
@@ -1090,21 +1090,23 @@ static void METAL_ReleaseGraphicsPipeline(
 
         // Vertex Descriptor
 
-        if (createinfo->vertex_input_state.num_vertex_bindings > 0) {
+        if (createinfo->vertex_input_state.num_vertex_buffers > 0) {
             vertexDescriptor = [MTLVertexDescriptor vertexDescriptor];
 
             for (Uint32 i = 0; i < createinfo->vertex_input_state.num_vertex_attributes; i += 1) {
                 Uint32 loc = createinfo->vertex_input_state.vertex_attributes[i].location;
                 vertexDescriptor.attributes[loc].format = SDLToMetal_VertexFormat[createinfo->vertex_input_state.vertex_attributes[i].format];
                 vertexDescriptor.attributes[loc].offset = createinfo->vertex_input_state.vertex_attributes[i].offset;
-                vertexDescriptor.attributes[loc].bufferIndex = METAL_INTERNAL_GetVertexBufferIndex(createinfo->vertex_input_state.vertex_attributes[i].binding_index);
+                vertexDescriptor.attributes[loc].bufferIndex = METAL_INTERNAL_GetVertexBufferIndex(createinfo->vertex_input_state.vertex_attributes[i].buffer_slot);
             }
 
-            for (Uint32 i = 0; i < createinfo->vertex_input_state.num_vertex_bindings; i += 1) {
-                binding = METAL_INTERNAL_GetVertexBufferIndex(createinfo->vertex_input_state.vertex_bindings[i].index);
-                vertexDescriptor.layouts[binding].stepFunction = SDLToMetal_StepFunction[createinfo->vertex_input_state.vertex_bindings[i].input_rate];
-                vertexDescriptor.layouts[binding].stepRate = (createinfo->vertex_input_state.vertex_bindings[i].input_rate == SDL_GPU_VERTEXINPUTRATE_INSTANCE) ? createinfo->vertex_input_state.vertex_bindings[i].instance_step_rate : 1;
-                vertexDescriptor.layouts[binding].stride = createinfo->vertex_input_state.vertex_bindings[i].pitch;
+            for (Uint32 i = 0; i < createinfo->vertex_input_state.num_vertex_buffers; i += 1) {
+                binding = METAL_INTERNAL_GetVertexBufferIndex(createinfo->vertex_input_state.vertex_buffer_descriptions[i].slot);
+                vertexDescriptor.layouts[binding].stepFunction = SDLToMetal_StepFunction[createinfo->vertex_input_state.vertex_buffer_descriptions[i].input_rate];
+                vertexDescriptor.layouts[binding].stepRate = (createinfo->vertex_input_state.vertex_buffer_descriptions[i].input_rate == SDL_GPU_VERTEXINPUTRATE_INSTANCE)
+                    ? createinfo->vertex_input_state.vertex_buffer_descriptions[i].instance_step_rate
+                    : 1;
+                vertexDescriptor.layouts[binding].stride = createinfo->vertex_input_state.vertex_buffer_descriptions[i].pitch;
             }
 
             pipelineDescriptor.vertexDescriptor = vertexDescriptor;
@@ -2367,8 +2369,8 @@ static void METAL_BindVertexBuffers(
 {
     @autoreleasepool {
         MetalCommandBuffer *metalCommandBuffer = (MetalCommandBuffer *)commandBuffer;
-        id<MTLBuffer> metalBuffers[MAX_BUFFER_BINDINGS];
-        NSUInteger bufferOffsets[MAX_BUFFER_BINDINGS];
+        id<MTLBuffer> metalBuffers[MAX_VERTEX_BUFFERS];
+        NSUInteger bufferOffsets[MAX_VERTEX_BUFFERS];
         NSRange range = NSMakeRange(METAL_INTERNAL_GetVertexBufferIndex(firstBinding), numBindings);
 
         if (range.length == 0) {
diff --git a/src/gpu/vulkan/SDL_gpu_vulkan.c b/src/gpu/vulkan/SDL_gpu_vulkan.c
index b87c0d48d3cd3..1e842e8774f42 100644
--- a/src/gpu/vulkan/SDL_gpu_vulkan.c
+++ b/src/gpu/vulkan/SDL_gpu_vulkan.c
@@ -6366,9 +6366,9 @@ static SDL_GPUGraphicsPipeline *VULKAN_CreateGraphicsPipeline(
 
     VkPipelineVertexInputStateCreateInfo vertexInputStateCreateInfo;
     VkPipelineVertexInputDivisorStateCreateInfoEXT divisorStateCreateInfo;
-    VkVertexInputBindingDescription *vertexInputBindingDescriptions = SDL_stack_alloc(VkVertexInputBindingDescription, createinfo->vertex_input_state.num_vertex_bindings);
+    VkVertexInputBindingDescription *vertexInputBindingDescriptions = SDL_stack_alloc(VkVertexInputBindingDescription, createinfo->vertex_input_state.num_vertex_buffers);
     VkVertexInputAttributeDescription *vertexInputAttributeDescriptions = SDL_stack_alloc(VkVertexInputAttributeDescription, createinfo->vertex_input_state.num_vertex_attributes);
-    VkVertexInputBindingDivisorDescriptionEXT *divisorDescriptions = SDL_stack_alloc(VkVertexInputBindingDivisorDescriptionEXT, createinfo->vertex_input_state.num_vertex_bindings);
+    VkVertexInputBindingDivisorDescriptionEXT *divisorDescriptions = SDL_stack_alloc(VkVertexInputBindingDivisorDescriptionEXT, createinfo->vertex_input_state.num_vertex_buffers);
     Uint32 divisorDescriptionCount = 0;
 
     VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateCreateInfo;
@@ -6445,18 +6445,18 @@ static SDL_GPUGraphicsPipeline *VULKAN_CreateGraphicsPipeline(
 
     // Vertex input
 
-    for (i = 0; i < createinfo->vertex_input_state.num_vertex_bindings; i += 1) {
-        vertexInputBindingDescriptions[i].binding = createinfo->vertex_input_state.vertex_bindings[i].index;
-        vertexInputBindingDescriptions[i].inputRate = SDLToVK_VertexInputRate[createinfo->vertex_input_state.vertex_bindings[i].input_rate];
-        vertexInputBindingDescriptions[i].stride = createinfo->vertex_input_state.vertex_bindings[i].pitch;
+    for (i = 0; i < createinfo->vertex_input_state.num_vertex_buffers; i += 1) {
+        vertexInputBindingDescriptions[i].binding = createinfo->vertex_input_state.vertex_buffer_descriptions[i].slot;
+        vertexInputBindingDescriptions[i].inputRate = SDLToVK_VertexInputRate[createinfo->vertex_input_state.vertex_buffer_descriptions[i].input_rate];
+        vertexInputBindingDescriptions[i].stride = createinfo->vertex_input_state.vertex_buffer_descriptions[i].pitch;
 
-        if (createinfo->vertex_input_state.vertex_bindings[i].input_rate == SDL_GPU_VERTEXINPUTRATE_INSTANCE) {
+        if (createinfo->vertex_input_state.vertex_buffer_descriptions[i].input_rate == SDL_GPU_VERTEXINPUTRATE_INSTANCE) {
             divisorDescriptionCount += 1;
         }
     }
 
     for (i = 0; i < createinfo->vertex_input_state.num_vertex_attributes; i += 1) {
-        vertexInputAttributeDescriptions[i].binding = createinfo->vertex_input_state.vertex_attributes[i].binding_index;
+        vertexInputAttributeDescriptions[i].binding = createinfo->vertex_input_state.vertex_attributes[i].buffer_slot;
         vertexInputAttributeDescriptions[i].format = SDLToVK_VertexFormat[createinfo->vertex_input_state.vertex_attributes[i].format];
         vertexInputAttributeDescriptions[i].location = createinfo->vertex_input_state.vertex_attributes[i].location;
         vertexInputAttributeDescriptions[i].offset = createinfo->vertex_input_state.vertex_attributes[i].offset;
@@ -6465,7 +6465,7 @@ static SDL_GPUGraphicsPipeline *VULKAN_CreateGraphicsPipeline(
     vertexInputStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
     vertexInputStateCreateInfo.pNext = NULL;
     vertexInputStateCreateInfo.flags = 0;
-    vertexInputStateCreateInfo.vertexBindingDescriptionCount = createinfo->vertex_input_state.num_vertex_bindings;
+    vertexInputStateCreateInfo.vertexBindingDescriptionCount = createinfo->vertex_input_state.num_vertex_buffers;
     vertexInputStateCreateInfo.pVertexBindingDescriptions = vertexInputBindingDescriptions;
     vertexInputStateCreateInfo.vertexAttributeDescriptionCount = createinfo->vertex_input_state.num_vertex_attributes;
     vertexInputStateCreateInfo.pVertexAttributeDescriptions = vertexInputAttributeDescriptions;
@@ -6473,10 +6473,10 @@ static SDL_GPUGraphicsPipeline *VULKAN_CreateGraphicsPipeline(
     if (divisorDescriptionCount > 0) {
         divisorDescriptionCount = 0;
 
-        for (i = 0; i < createinfo->vertex_input_state.num_vertex_bindings; i += 1) {
-            if (createinfo->vertex_input_state.vertex_bindings[i].input_rate == SDL_GPU_VERTEXINPUTRATE_INSTANCE) {
-                divisorDescriptions[divisorDescriptionCount].binding = createinfo->vertex_input_state.vertex_bindings[i].index;
-                divisorDescriptions[divisorDescriptionCount].divisor = createinfo->vertex_input_state.vertex_bindings[i].instance_step_rate;
+        for (i = 0; i < createinfo->vertex_input_state.num_vertex_buffers; i += 1) {
+            if (createinfo->vertex_input_state.vertex_buffer_descriptions[i].input_rate == SDL_GPU_VERTEXINPUTRATE_INSTANCE) {
+                divisorDescriptions[divisorDescriptionCount].binding = createinfo->vertex_input_state.vertex_buffer_descriptions[i].slot;
+                divisorDescriptions[divisorDescriptionCount].divisor = createinfo->vertex_input_state.vertex_buffer_descriptions[i].instance_step_rate;
 
                 divisorDescriptionCount += 1;
             }
@@ -8087,7 +8087,7 @@ static void VULKAN_BindGraphicsPipeline(
 
 static void VULKAN_BindVertexBuffers(
     SDL_GPUCommandBuffer *commandBuffer,
-    Uint32 firstBinding,
+    Uint32 firstSlot,
     const SDL_GPUBufferBinding *bindings,
     Uint32 numBindings)
 {
@@ -8107,7 +8107,7 @@ static void VULKAN_BindVertexBuffers(
 
     renderer->vkCmdBindVertexBuffers(
         vulkanCommandBuffer->commandBuffer,
-        firstBinding,
+        firstSlot,
         numBindings,
         buffers,
         offsets);
diff --git a/src/render/gpu/SDL_pipeline_gpu.c b/src/render/gpu/SDL_pipeline_gpu.c
index a5448cc0b9340..5e670c1437b90 100644
--- a/src/render/gpu/SDL_pipeline_gpu.c
+++ b/src/render/gpu/SDL_pipeline_gpu.c
@@ -126,8 +126,8 @@ static SDL_GPUGraphicsPipeline *MakePipeline(SDL_GPUDevice *device, GPU_Shaders
     pci.rasterizer_state.fill_mode = SDL_GPU_FILLMODE_FILL;
     pci.rasterizer_state.front_face = SDL_GPU_FRONTFACE_COUNTER_CLOCKWISE;
 
-    SDL_GPUVertexBinding bind;
-    SDL_zero(bind);
+    SDL_GPUVertexBufferDescription vertex_buffer_desc;
+    SDL_zero(vertex_buffer_desc);
 
     Uint32 num_attribs = 0;
     SDL_GPUVertexAttribute attribs[4];
@@ -150,16 +150,16 @@ static SDL_GPUGraphicsPipeline *MakePipeline(SDL_GPUDevice *device, GPU_Shaders
     // Position
     attribs[num_attribs].location = num_attribs;
     attribs[num_attribs].format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT2;
-    attribs[num_attribs].offset = bind.pitch;
-    bind.pitch += 2 * sizeof(float);
+    attribs[num_attribs].offset = vertex_buffer_desc.pitch;
+    vertex_buffer_desc.pitch += 2 * sizeof(float);
     num_attribs++;
 
     if (have_attr_color) {
         // Color
         attribs[num_attribs].location = num_attribs;
         attribs[num_attribs].format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT4;
-        attribs[num_attribs].offset = bind.pitch;
-        bind.pitch += 4 * sizeof(float);
+        attribs[num_attribs].offset = vertex_buffer_desc.pitch;
+        vertex_buffer_desc.pitch += 4 * sizeof(float);
         num_attribs++;
     }
 
@@ -167,15 +167,15 @@ static SDL_GPUGraphicsPipeline *MakePipeline(SDL_GPUDevice *device, GPU_Shaders
         // UVs
         attribs[num_attribs].location = num_attribs;
         attribs[num_attribs].format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT2;
-        attribs[num_attribs].offset = bind.pitch;
-        bind.pitch += 2 * sizeof(float);
+        attribs[num_attribs].offset = vertex_buffer_desc.pitch;
+        vertex_buffer_desc.pitch += 2 * sizeof(float);
         num_attribs++;
     }
 
     pci.vertex_input_state.num_vertex_attributes = num_attribs;
     pci.vertex_input_state.vertex_attributes = attribs;
-    pci.vertex_input_state.num_vertex_bindings = 1;
-    pci.vertex_input_state.vertex_bindings = &bind;
+    pci.vertex_input_state.num_vertex_buffers = 1;
+    pci.vertex_input_state.vertex_buffer_descriptions = &vertex_buffer_desc;
 
     return SDL_CreateGPUGraphicsPipeline(device, &pci);
 }
diff --git a/test/testgpu_spinning_cube.c b/test/testgpu_spinning_cube.c
index 8e5bd49f32207..14e8c631f3240 100644
--- a/test/testgpu_spinning_cube.c
+++ b/test/testgpu_spinning_cube.c
@@ -465,7 +465,7 @@ init_render_state(int msaa)
     SDL_GPUColorTargetDescription color_target_desc;
     Uint32 drawablew, drawableh;
     SDL_GPUVertexAttribute vertex_attributes[2];
-    SDL_GPUVertexBinding vertex_binding;
+    SDL_GPUVertexBufferDescription vertex_buffer_desc;
     SDL_GPUShader *vertex_shader;
     SDL_GPUShader *fragment_shader;
     int i;
@@ -554,8 +554,8 @@ init_render_state(int msaa)
     pipelinedesc.target_info.depth_stencil_format = SDL_GPU_TEXTUREFORMAT_D16_UNORM;
     pipelinedesc.t

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