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.
This commit is contained in:
Wunk 2023-11-05 12:26:09 -08:00 committed by GitHub
parent 1cf64ffaef
commit 3218af38d0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 36 additions and 24 deletions

View file

@ -89,6 +89,9 @@ struct DynamicState {
u8 stencil_compare_mask; u8 stencil_compare_mask;
u8 stencil_write_mask; u8 stencil_write_mask;
Common::Rectangle<u32> scissor;
Common::Rectangle<s32> viewport;
bool operator==(const DynamicState& other) const noexcept { bool operator==(const DynamicState& other) const noexcept {
return std::memcmp(this, &other, sizeof(DynamicState)) == 0; return std::memcmp(this, &other, sizeof(DynamicState)) == 0;
} }

View file

@ -206,6 +206,32 @@ bool PipelineCache::BindPipeline(const PipelineInfo& info, bool wait_built) {
current_depth_stencil = current_info.depth_stencil, current_depth_stencil = current_info.depth_stencil,
rasterization = info.rasterization, rasterization = info.rasterization,
depth_stencil = info.depth_stencil](vk::CommandBuffer cmdbuf) { depth_stencil = info.depth_stencil](vk::CommandBuffer cmdbuf) {
if (dynamic.viewport != current_dynamic.viewport || is_dirty) {
const vk::Viewport vk_viewport = {
.x = static_cast<f32>(dynamic.viewport.left),
.y = static_cast<f32>(dynamic.viewport.top),
.width = static_cast<f32>(dynamic.viewport.GetWidth()),
.height = static_cast<f32>(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<s32>(dynamic.scissor.left),
.y = static_cast<s32>(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) { if (dynamic.stencil_compare_mask != current_dynamic.stencil_compare_mask || is_dirty) {
cmdbuf.setStencilCompareMask(vk::StencilFaceFlagBits::eFrontAndBack, cmdbuf.setStencilCompareMask(vk::StencilFaceFlagBits::eFrontAndBack,
dynamic.stencil_compare_mask); dynamic.stencil_compare_mask);

View file

@ -512,30 +512,13 @@ bool RasterizerVulkan::Draw(bool accelerate, bool is_indexed) {
// Configure viewport and scissor // Configure viewport and scissor
const auto viewport = fb_helper.Viewport(); const auto viewport = fb_helper.Viewport();
scheduler.Record([viewport, draw_rect](vk::CommandBuffer cmdbuf) { pipeline_info.dynamic.viewport = Common::Rectangle<s32>{
const vk::Viewport vk_viewport = { viewport.x,
.x = static_cast<f32>(viewport.x), viewport.y,
.y = static_cast<f32>(viewport.y), viewport.x + viewport.width,
.width = static_cast<f32>(viewport.width), viewport.y + viewport.height,
.height = static_cast<f32>(viewport.height), };
.minDepth = 0.f, pipeline_info.dynamic.scissor = draw_rect;
.maxDepth = 1.f,
};
const vk::Rect2D scissor = {
.offset{
.x = static_cast<s32>(draw_rect.left),
.y = static_cast<s32>(draw_rect.bottom),
},
.extent{
.width = draw_rect.GetWidth(),
.height = draw_rect.GetHeight(),
},
};
cmdbuf.setViewport(0, vk_viewport);
cmdbuf.setScissor(0, scissor);
});
// Draw the vertex batch // Draw the vertex batch
bool succeeded = true; bool succeeded = true;