From 3218af38d0c29f5b7bd427e62f681c40909662ac Mon Sep 17 00:00:00 2001 From: Wunk Date: Sun, 5 Nov 2023 12:26:09 -0800 Subject: [PATCH] renderer_vulkan: Add scissor and viewport to dynamic pipeline state (#7114) Adds the current viewport and scissor to the dynamic pipeline state to reduce redundant viewport/scissor assignments in the command buffer. This greatly reduces the amount of API calls to `vkCmdSetViewport` and `vkCmdSetScissor` by only emitting the API call when the state actually changes. --- .../renderer_vulkan/vk_graphics_pipeline.h | 3 ++ .../renderer_vulkan/vk_pipeline_cache.cpp | 26 ++++++++++++++++ .../renderer_vulkan/vk_rasterizer.cpp | 31 +++++-------------- 3 files changed, 36 insertions(+), 24 deletions(-) diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.h b/src/video_core/renderer_vulkan/vk_graphics_pipeline.h index 8d27a45e5..af2abd6d9 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.h +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.h @@ -89,6 +89,9 @@ struct DynamicState { u8 stencil_compare_mask; u8 stencil_write_mask; + Common::Rectangle scissor; + Common::Rectangle viewport; + bool operator==(const DynamicState& other) const noexcept { return std::memcmp(this, &other, sizeof(DynamicState)) == 0; } diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index bb8628f9f..aa1d2cbe8 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp @@ -206,6 +206,32 @@ bool PipelineCache::BindPipeline(const PipelineInfo& info, bool wait_built) { current_depth_stencil = current_info.depth_stencil, rasterization = info.rasterization, depth_stencil = info.depth_stencil](vk::CommandBuffer cmdbuf) { + if (dynamic.viewport != current_dynamic.viewport || is_dirty) { + const vk::Viewport vk_viewport = { + .x = static_cast(dynamic.viewport.left), + .y = static_cast(dynamic.viewport.top), + .width = static_cast(dynamic.viewport.GetWidth()), + .height = static_cast(dynamic.viewport.GetHeight()), + .minDepth = 0.f, + .maxDepth = 1.f, + }; + cmdbuf.setViewport(0, vk_viewport); + } + + if (dynamic.scissor != current_dynamic.scissor || is_dirty) { + const vk::Rect2D scissor = { + .offset{ + .x = static_cast(dynamic.scissor.left), + .y = static_cast(dynamic.scissor.bottom), + }, + .extent{ + .width = dynamic.scissor.GetWidth(), + .height = dynamic.scissor.GetHeight(), + }, + }; + cmdbuf.setScissor(0, scissor); + } + if (dynamic.stencil_compare_mask != current_dynamic.stencil_compare_mask || is_dirty) { cmdbuf.setStencilCompareMask(vk::StencilFaceFlagBits::eFrontAndBack, dynamic.stencil_compare_mask); diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index 68091a77f..f99066176 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -512,30 +512,13 @@ bool RasterizerVulkan::Draw(bool accelerate, bool is_indexed) { // Configure viewport and scissor const auto viewport = fb_helper.Viewport(); - scheduler.Record([viewport, draw_rect](vk::CommandBuffer cmdbuf) { - const vk::Viewport vk_viewport = { - .x = static_cast(viewport.x), - .y = static_cast(viewport.y), - .width = static_cast(viewport.width), - .height = static_cast(viewport.height), - .minDepth = 0.f, - .maxDepth = 1.f, - }; - - const vk::Rect2D scissor = { - .offset{ - .x = static_cast(draw_rect.left), - .y = static_cast(draw_rect.bottom), - }, - .extent{ - .width = draw_rect.GetWidth(), - .height = draw_rect.GetHeight(), - }, - }; - - cmdbuf.setViewport(0, vk_viewport); - cmdbuf.setScissor(0, scissor); - }); + pipeline_info.dynamic.viewport = Common::Rectangle{ + viewport.x, + viewport.y, + viewport.x + viewport.width, + viewport.y + viewport.height, + }; + pipeline_info.dynamic.scissor = draw_rect; // Draw the vertex batch bool succeeded = true;