From 3c111202e16eed3abda04409bde2521a63217d0d Mon Sep 17 00:00:00 2001 From: squidbus <175574877+squidbus@users.noreply.github.com> Date: Wed, 25 Dec 2024 06:05:51 -0800 Subject: [PATCH] renderer_vulkan: Make sure at least one viewport is set (#1859) --- .../renderer_vulkan/vk_graphics_pipeline.cpp | 30 ++---- .../renderer_vulkan/vk_rasterizer.cpp | 97 ++++++++++--------- 2 files changed, 61 insertions(+), 66 deletions(-) diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp index c01d4cbe..ffa474a1 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp @@ -133,37 +133,23 @@ GraphicsPipeline::GraphicsPipeline( .sampleShadingEnable = false, }; - const vk::Viewport viewport = { - .x = 0.0f, - .y = 0.0f, - .width = 1.0f, - .height = 1.0f, - .minDepth = 0.0f, - .maxDepth = 1.0f, - }; - - const vk::Rect2D scissor = { - .offset = {0, 0}, - .extent = {1, 1}, - }; - const vk::PipelineViewportDepthClipControlCreateInfoEXT clip_control = { .negativeOneToOne = key.clip_space == Liverpool::ClipSpace::MinusWToW, }; const vk::PipelineViewportStateCreateInfo viewport_info = { .pNext = instance.IsDepthClipControlSupported() ? &clip_control : nullptr, - .viewportCount = 1, - .pViewports = &viewport, - .scissorCount = 1, - .pScissors = &scissor, }; boost::container::static_vector dynamic_states = { - vk::DynamicState::eViewport, vk::DynamicState::eScissor, - vk::DynamicState::eBlendConstants, vk::DynamicState::eDepthBounds, - vk::DynamicState::eDepthBias, vk::DynamicState::eStencilReference, - vk::DynamicState::eStencilCompareMask, vk::DynamicState::eStencilWriteMask, + vk::DynamicState::eViewportWithCountEXT, + vk::DynamicState::eScissorWithCountEXT, + vk::DynamicState::eBlendConstants, + vk::DynamicState::eDepthBounds, + vk::DynamicState::eDepthBias, + vk::DynamicState::eStencilReference, + vk::DynamicState::eStencilCompareMask, + vk::DynamicState::eStencilWriteMask, vk::DynamicState::eStencilOpEXT, }; diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index 1e698bf6..d458fa12 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -1019,17 +1019,44 @@ void Rasterizer::UpdateDynamicState(const GraphicsPipeline& pipeline) { } void Rasterizer::UpdateViewportScissorState() { - auto& regs = liverpool->regs; + const auto& regs = liverpool->regs; + + const auto combined_scissor_value_tl = [](s16 scr, s16 win, s16 gen, s16 win_offset) { + return std::max({scr, s16(win + win_offset), s16(gen + win_offset)}); + }; + const auto combined_scissor_value_br = [](s16 scr, s16 win, s16 gen, s16 win_offset) { + return std::min({scr, s16(win + win_offset), s16(gen + win_offset)}); + }; + const bool enable_offset = !regs.window_scissor.window_offset_disable.Value(); + + Liverpool::Scissor scsr{}; + scsr.top_left_x = combined_scissor_value_tl( + regs.screen_scissor.top_left_x, s16(regs.window_scissor.top_left_x.Value()), + s16(regs.generic_scissor.top_left_x.Value()), + enable_offset ? regs.window_offset.window_x_offset : 0); + scsr.top_left_y = combined_scissor_value_tl( + regs.screen_scissor.top_left_y, s16(regs.window_scissor.top_left_y.Value()), + s16(regs.generic_scissor.top_left_y.Value()), + enable_offset ? regs.window_offset.window_y_offset : 0); + scsr.bottom_right_x = combined_scissor_value_br( + regs.screen_scissor.bottom_right_x, regs.window_scissor.bottom_right_x, + regs.generic_scissor.bottom_right_x, + enable_offset ? regs.window_offset.window_x_offset : 0); + scsr.bottom_right_y = combined_scissor_value_br( + regs.screen_scissor.bottom_right_y, regs.window_scissor.bottom_right_y, + regs.generic_scissor.bottom_right_y, + enable_offset ? regs.window_offset.window_y_offset : 0); boost::container::static_vector viewports; boost::container::static_vector scissors; + const auto& vp_ctl = regs.viewport_control; const float reduce_z = instance.IsDepthClipControlSupported() && regs.clipper_control.clip_space == AmdGpu::Liverpool::ClipSpace::MinusWToW ? 1.0f : 0.0f; - const auto vp_ctl = regs.viewport_control; + for (u32 i = 0; i < Liverpool::NumViewports; i++) { const auto& vp = regs.viewports[i]; const auto& vp_d = regs.viewport_depths[i]; @@ -1050,53 +1077,17 @@ void Rasterizer::UpdateViewportScissorState() { .minDepth = zoffset - zscale * reduce_z, .maxDepth = zscale + zoffset, }); - } - const bool enable_offset = !regs.window_scissor.window_offset_disable.Value(); - Liverpool::Scissor scsr{}; - const auto combined_scissor_value_tl = [](s16 scr, s16 win, s16 gen, s16 win_offset) { - return std::max({scr, s16(win + win_offset), s16(gen + win_offset)}); - }; - - scsr.top_left_x = combined_scissor_value_tl( - regs.screen_scissor.top_left_x, s16(regs.window_scissor.top_left_x.Value()), - s16(regs.generic_scissor.top_left_x.Value()), - enable_offset ? regs.window_offset.window_x_offset : 0); - - scsr.top_left_y = combined_scissor_value_tl( - regs.screen_scissor.top_left_y, s16(regs.window_scissor.top_left_y.Value()), - s16(regs.generic_scissor.top_left_y.Value()), - enable_offset ? regs.window_offset.window_y_offset : 0); - - const auto combined_scissor_value_br = [](s16 scr, s16 win, s16 gen, s16 win_offset) { - return std::min({scr, s16(win + win_offset), s16(gen + win_offset)}); - }; - - scsr.bottom_right_x = combined_scissor_value_br( - regs.screen_scissor.bottom_right_x, regs.window_scissor.bottom_right_x, - regs.generic_scissor.bottom_right_x, - enable_offset ? regs.window_offset.window_x_offset : 0); - - scsr.bottom_right_y = combined_scissor_value_br( - regs.screen_scissor.bottom_right_y, regs.window_scissor.bottom_right_y, - regs.generic_scissor.bottom_right_y, - enable_offset ? regs.window_offset.window_y_offset : 0); - - for (u32 idx = 0; idx < Liverpool::NumViewports; idx++) { - if (regs.viewports[idx].xscale == 0) { - // Scissor and viewport counts should be equal. - continue; - } auto vp_scsr = scsr; if (regs.mode_control.vport_scissor_enable) { vp_scsr.top_left_x = - std::max(vp_scsr.top_left_x, s16(regs.viewport_scissors[idx].top_left_x.Value())); + std::max(vp_scsr.top_left_x, s16(regs.viewport_scissors[i].top_left_x.Value())); vp_scsr.top_left_y = - std::max(vp_scsr.top_left_y, s16(regs.viewport_scissors[idx].top_left_y.Value())); + std::max(vp_scsr.top_left_y, s16(regs.viewport_scissors[i].top_left_y.Value())); vp_scsr.bottom_right_x = - std::min(vp_scsr.bottom_right_x, regs.viewport_scissors[idx].bottom_right_x); + std::min(vp_scsr.bottom_right_x, regs.viewport_scissors[i].bottom_right_x); vp_scsr.bottom_right_y = - std::min(vp_scsr.bottom_right_y, regs.viewport_scissors[idx].bottom_right_y); + std::min(vp_scsr.bottom_right_y, regs.viewport_scissors[i].bottom_right_y); } scissors.push_back({ .offset = {vp_scsr.top_left_x, vp_scsr.top_left_y}, @@ -1104,9 +1095,27 @@ void Rasterizer::UpdateViewportScissorState() { }); } + if (viewports.empty()) { + // Vulkan requires providing at least one viewport. + constexpr vk::Viewport empty_viewport = { + .x = 0.0f, + .y = 0.0f, + .width = 1.0f, + .height = 1.0f, + .minDepth = 0.0f, + .maxDepth = 1.0f, + }; + constexpr vk::Rect2D empty_scissor = { + .offset = {0, 0}, + .extent = {1, 1}, + }; + viewports.push_back(empty_viewport); + scissors.push_back(empty_scissor); + } + const auto cmdbuf = scheduler.CommandBuffer(); - cmdbuf.setViewport(0, viewports); - cmdbuf.setScissor(0, scissors); + cmdbuf.setViewportWithCountEXT(viewports); + cmdbuf.setScissorWithCountEXT(scissors); } void Rasterizer::ScopeMarkerBegin(const std::string_view& str) {