From f6868ae4dd7928a251939069f9be6ff669bc391e Mon Sep 17 00:00:00 2001
From: yzct12345 <yzct12345@users.noreply.github.com>
Date: Mon, 12 Dec 2022 20:52:32 -0500
Subject: [PATCH] Fix validation errors on less compatible Intel GPU

---
 src/video_core/renderer_vulkan/vk_buffer_cache.cpp     |  3 +++
 .../renderer_vulkan/vk_graphics_pipeline.cpp           | 10 ++++++++--
 src/video_core/renderer_vulkan/vk_pipeline_cache.cpp   |  9 +++++++++
 src/video_core/vulkan_common/vulkan_device.cpp         |  4 ++++
 src/video_core/vulkan_common/vulkan_device.h           | 10 ++++++++++
 5 files changed, 34 insertions(+), 2 deletions(-)

diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
index 558b8db56..84d36fea6 100644
--- a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
@@ -285,6 +285,9 @@ void BufferCacheRuntime::BindQuadArrayIndexBuffer(u32 first, u32 count) {
 
 void BufferCacheRuntime::BindVertexBuffer(u32 index, VkBuffer buffer, u32 offset, u32 size,
                                           u32 stride) {
+    if (index >= device.GetMaxVertexInputBindings()) {
+        return;
+    }
     if (device.IsExtExtendedDynamicStateSupported()) {
         scheduler.Record([index, buffer, offset, size, stride](vk::CommandBuffer cmdbuf) {
             const VkDeviceSize vk_offset = buffer != VK_NULL_HANDLE ? offset : 0;
diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
index 006128638..4b10fe7bc 100644
--- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
+++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
@@ -529,7 +529,9 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) {
     static_vector<VkVertexInputBindingDivisorDescriptionEXT, 32> vertex_binding_divisors;
     static_vector<VkVertexInputAttributeDescription, 32> vertex_attributes;
     if (key.state.dynamic_vertex_input) {
-        for (size_t index = 0; index < key.state.attributes.size(); ++index) {
+        const size_t num_vertex_arrays = std::min(
+            key.state.attributes.size(), static_cast<size_t>(device.GetMaxVertexInputBindings()));
+        for (size_t index = 0; index < num_vertex_arrays; ++index) {
             const u32 type = key.state.DynamicAttributeType(index);
             if (!stage_infos[0].loads.Generic(index) || type == 0) {
                 continue;
@@ -551,7 +553,9 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) {
             });
         }
     } else {
-        for (size_t index = 0; index < Maxwell::NumVertexArrays; ++index) {
+        const size_t num_vertex_arrays = std::min(
+            Maxwell::NumVertexArrays, static_cast<size_t>(device.GetMaxVertexInputBindings()));
+        for (size_t index = 0; index < num_vertex_arrays; ++index) {
             const bool instanced = key.state.binding_divisors[index] != 0;
             const auto rate =
                 instanced ? VK_VERTEX_INPUT_RATE_INSTANCE : VK_VERTEX_INPUT_RATE_VERTEX;
@@ -580,6 +584,8 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) {
             });
         }
     }
+    ASSERT(vertex_attributes.size() <= device.GetMaxVertexInputAttributes());
+
     VkPipelineVertexInputStateCreateInfo vertex_input_ci{
         .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
         .pNext = nullptr,
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
index 81f5f3e11..86fdde014 100644
--- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
@@ -341,6 +341,15 @@ PipelineCache::PipelineCache(RasterizerVulkan& rasterizer_, const Device& device
         .support_snorm_render_buffer = true,
         .support_viewport_index_layer = device.IsExtShaderViewportIndexLayerSupported(),
     };
+
+    if (device.GetMaxVertexInputAttributes() < Maxwell::NumVertexAttributes) {
+        LOG_WARNING(Render_Vulkan, "maxVertexInputAttributes is too low: {} < {}",
+                    device.GetMaxVertexInputAttributes(), Maxwell::NumVertexAttributes);
+    }
+    if (device.GetMaxVertexInputBindings() < Maxwell::NumVertexArrays) {
+        LOG_WARNING(Render_Vulkan, "maxVertexInputBindings is too low: {} < {}",
+                    device.GetMaxVertexInputBindings(), Maxwell::NumVertexArrays);
+    }
 }
 
 PipelineCache::~PipelineCache() = default;
diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp
index 6a2ad4b1d..67540cb80 100644
--- a/src/video_core/vulkan_common/vulkan_device.cpp
+++ b/src/video_core/vulkan_common/vulkan_device.cpp
@@ -1380,6 +1380,10 @@ void Device::SetupFeatures() {
     is_shader_storage_image_multisample = features.shaderStorageImageMultisample;
     is_blit_depth_stencil_supported = TestDepthStencilBlits();
     is_optimal_astc_supported = IsOptimalAstcSupported(features);
+
+    const VkPhysicalDeviceLimits& limits{properties.limits};
+    max_vertex_input_attributes = limits.maxVertexInputAttributes;
+    max_vertex_input_bindings = limits.maxVertexInputBindings;
 }
 
 void Device::SetupProperties() {
diff --git a/src/video_core/vulkan_common/vulkan_device.h b/src/video_core/vulkan_common/vulkan_device.h
index db802437c..391b7604c 100644
--- a/src/video_core/vulkan_common/vulkan_device.h
+++ b/src/video_core/vulkan_common/vulkan_device.h
@@ -368,6 +368,14 @@ public:
         return must_emulate_bgr565;
     }
 
+    u32 GetMaxVertexInputAttributes() const {
+        return max_vertex_input_attributes;
+    }
+
+    u32 GetMaxVertexInputBindings() const {
+        return max_vertex_input_bindings;
+    }
+
 private:
     /// Checks if the physical device is suitable.
     void CheckSuitability(bool requires_swapchain) const;
@@ -467,6 +475,8 @@ private:
     bool supports_d24_depth{};              ///< Supports D24 depth buffers.
     bool cant_blit_msaa{};                  ///< Does not support MSAA<->MSAA blitting.
     bool must_emulate_bgr565{};             ///< Emulates BGR565 by swizzling RGB565 format.
+    u32 max_vertex_input_attributes{};      ///< Max vertex input attributes in pipeline
+    u32 max_vertex_input_bindings{};        ///< Max vertex input buffers in pipeline
 
     // Telemetry parameters
     std::string vendor_name;                       ///< Device's driver name.