diff --git a/src/video_core/engines/draw_manager.cpp b/src/video_core/engines/draw_manager.cpp index 5891c25622..cbac98c8c6 100644 --- a/src/video_core/engines/draw_manager.cpp +++ b/src/video_core/engines/draw_manager.cpp @@ -14,6 +14,10 @@ namespace Tegra::Engines { void Maxwell3D::DrawManager::ProcessMethodCall(Maxwell3D& maxwell3d, u32 method, u32 argument) { + if (draw_state.draw_mode == DrawMode::InstanceArray && + method != MAXWELL3D_REG_INDEX(vertex_array_instance_subsequent)) { + DrawDeferred(maxwell3d); + } switch (method) { case MAXWELL3D_REG_INDEX(clear_surface): return Clear(maxwell3d, 1); @@ -73,6 +77,15 @@ void Maxwell3D::DrawManager::Clear(Maxwell3D& maxwell3d, u32 layer_count) { } void Maxwell3D::DrawManager::DrawDeferred(Maxwell3D& maxwell3d) { + if (draw_state.draw_mode == DrawMode::InstanceArray) { + const u32 instance_count = draw_state.instance_count + 1; + draw_state.draw_mode = DrawMode::General; + draw_state.instance_count = 0; + if (maxwell3d.ShouldExecute()) { + maxwell3d.rasterizer->Draw(false, instance_count); + } + return; + } if (draw_state.draw_mode != DrawMode::Instance || draw_state.instance_count == 0) { return; } @@ -89,16 +102,25 @@ void Maxwell3D::DrawManager::DrawArray(Maxwell3D& maxwell3d, Maxwell3D::Regs::Pr } void Maxwell3D::DrawManager::DrawArrayInstanced(Maxwell3D& maxwell3d, Maxwell3D::Regs::PrimitiveTopology topology, u32 vertex_first, u32 vertex_count, bool subsequent) { + if (subsequent && draw_state.draw_mode == DrawMode::InstanceArray && + instance_topology == topology && draw_state.vertex_buffer.first == vertex_first && + draw_state.vertex_buffer.count == vertex_count) { + ++draw_state.instance_count; + return; + } + u32 base_instance = 0; + if (subsequent) { + base_instance = draw_state.base_instance + draw_state.instance_count + 1; + } + DrawDeferred(maxwell3d); + instance_topology = topology; draw_state.topology = topology; draw_state.vertex_buffer.first = vertex_first; draw_state.vertex_buffer.count = vertex_count; - if (!subsequent) { - draw_state.instance_count = 1; - } - draw_state.base_instance = draw_state.instance_count - 1; - draw_state.draw_mode = DrawMode::Instance; - draw_state.instance_count++; - ProcessDraw(maxwell3d, false, 1); + draw_state.base_instance = base_instance; + draw_state.instance_count = 0; + draw_state.draw_mode = DrawMode::InstanceArray; + UpdateTopology(maxwell3d); } void Maxwell3D::DrawManager::DrawIndex(Maxwell3D& maxwell3d, Maxwell3D::Regs::PrimitiveTopology topology, u32 index_first, u32 index_count, u32 base_index, u32 base_instance, u32 num_instances) { diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h index 0cab2ae986..277304ed76 100644 --- a/src/video_core/engines/maxwell_3d.h +++ b/src/video_core/engines/maxwell_3d.h @@ -3034,7 +3034,7 @@ public: // clang-format on struct DrawManager { - enum class DrawMode : u32 { General = 0, Instance, InlineIndex }; + enum class DrawMode : u32 { General = 0, Instance, InlineIndex, InstanceArray }; struct State { Maxwell3D::Regs::PrimitiveTopology topology{}; DrawMode draw_mode{}; @@ -3086,6 +3086,7 @@ public: void ProcessDraw(Maxwell3D& maxwell3d, bool draw_indexed, u32 instance_count); void ProcessDrawIndirect(Maxwell3D& maxwell3d); State draw_state{}; + Maxwell3D::Regs::PrimitiveTopology instance_topology{}; DrawTextureState draw_texture_state{}; IndirectParams indirect_state{}; }; diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp index 8b5b0bc9c5..7ee1c608c0 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp @@ -705,7 +705,8 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) { if (instanced) { vertex_binding_divisors.push_back({ .binding = static_cast(index), - .divisor = key.state.binding_divisors[index], + .divisor = (std::min)(key.state.binding_divisors[index], + device.GetMaxVertexAttribDivisor()), }); } } diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index f43bea1220..92c5574691 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -1918,13 +1918,17 @@ void RasterizerVulkan::UpdateVertexInput(Tegra::Engines::Maxwell3D::Regs& regs) for (u32 binding = 0; binding < max_bindings; ++binding) { const auto& input_binding{regs.vertex_streams[binding]}; const bool is_instanced{regs.vertex_stream_instances.IsInstancingEnabled(binding)}; + u32 divisor = 1; + if (is_instanced) { + divisor = (std::min)(input_binding.frequency, device.GetMaxVertexAttribDivisor()); + } bindings.push_back({ .sType = VK_STRUCTURE_TYPE_VERTEX_INPUT_BINDING_DESCRIPTION_2_EXT, .pNext = nullptr, .binding = binding, .stride = input_binding.stride, .inputRate = is_instanced ? VK_VERTEX_INPUT_RATE_INSTANCE : VK_VERTEX_INPUT_RATE_VERTEX, - .divisor = is_instanced ? input_binding.frequency : 1, + .divisor = divisor, }); } diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp index d79e8d37fe..9a9bfdd43b 100644 --- a/src/video_core/vulkan_common/vulkan_device.cpp +++ b/src/video_core/vulkan_common/vulkan_device.cpp @@ -1130,11 +1130,19 @@ bool Device::GetSuitability(bool requires_swapchain) { SetNext(next, properties.custom_border_color); } + if (extensions.vertex_attribute_divisor) { + properties.vertex_attribute_divisor.sType = + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT; + SetNext(next, properties.vertex_attribute_divisor); + } + // Perform the property fetch. physical.GetProperties2(properties2); // Store base properties properties.properties = properties2.properties; + max_vertex_attrib_divisor = + (std::max)(1U, properties.vertex_attribute_divisor.maxVertexAttribDivisor); // Unload extensions if feature support is insufficient. RemoveUnsuitableExtensions(); diff --git a/src/video_core/vulkan_common/vulkan_device.h b/src/video_core/vulkan_common/vulkan_device.h index 45b0ad7b17..c6d6df16b1 100644 --- a/src/video_core/vulkan_common/vulkan_device.h +++ b/src/video_core/vulkan_common/vulkan_device.h @@ -984,6 +984,10 @@ FN_MAX_LIMIT_LIST return properties.properties.limits.maxVertexInputBindings; } + u32 GetMaxVertexAttribDivisor() const { + return max_vertex_attrib_divisor; + } + u32 GetMaxViewports() const { return properties.properties.limits.maxViewports; } @@ -1188,6 +1192,7 @@ private: VkPhysicalDeviceMaintenance5PropertiesKHR maintenance5{}; VkPhysicalDeviceDepthStencilResolveProperties depth_stencil_resolve{}; VkPhysicalDeviceCustomBorderColorPropertiesEXT custom_border_color{}; + VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT vertex_attribute_divisor{}; VkPhysicalDeviceProperties properties{}; }; @@ -1195,6 +1200,7 @@ private: Extensions extensions{}; Features features{}; Properties properties{}; + u32 max_vertex_attrib_divisor{1}; VkPhysicalDeviceFeatures2 features2{}; VkPhysicalDeviceProperties2 properties2{};