From 9b80a6551a106f7849ad42af37cd0326eb0760b0 Mon Sep 17 00:00:00 2001 From: CamilleLaVey Date: Wed, 1 Jul 2026 22:20:26 -0400 Subject: [PATCH] [vulkan] ARM workaround to ensure safety operations with viewports --- src/video_core/renderer_vulkan/blit_image.cpp | 90 ++++++++++++------- .../renderer_vulkan/present/fsr.cpp | 6 +- .../renderer_vulkan/present/fxaa.cpp | 4 +- .../renderer_vulkan/present/sgsr.cpp | 4 +- .../renderer_vulkan/present/smaa.cpp | 8 +- .../renderer_vulkan/present/util.cpp | 20 +++-- src/video_core/renderer_vulkan/present/util.h | 4 +- .../present/window_adapt_pass.cpp | 4 +- .../vulkan_common/vulkan_device.cpp | 6 ++ src/video_core/vulkan_common/vulkan_device.h | 5 ++ 10 files changed, 94 insertions(+), 57 deletions(-) diff --git a/src/video_core/renderer_vulkan/blit_image.cpp b/src/video_core/renderer_vulkan/blit_image.cpp index d99e528bc0..f6fddc94a9 100644 --- a/src/video_core/renderer_vulkan/blit_image.cpp +++ b/src/video_core/renderer_vulkan/blit_image.cpp @@ -5,6 +5,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include +#include #include "video_core/renderer_vulkan/vk_texture_cache.h" @@ -135,15 +136,18 @@ VkPipelineInputAssemblyStateCreateInfo GetPipelineInputAssemblyStateCreateInfo(c .primitiveRestartEnable = device.IsMoltenVK() ? VK_TRUE : VK_FALSE, }; } -constexpr VkPipelineViewportStateCreateInfo PIPELINE_VIEWPORT_STATE_CREATE_INFO{ - .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, - .pNext = nullptr, - .flags = 0, - .viewportCount = 1, - .pViewports = nullptr, - .scissorCount = 1, - .pScissors = nullptr, -}; +VkPipelineViewportStateCreateInfo GetPipelineViewportStateCreateInfo(const Device& device) { + const u32 viewport_count = device.GetViewportCount(); + return VkPipelineViewportStateCreateInfo{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .viewportCount = viewport_count, + .pViewports = nullptr, + .scissorCount = viewport_count, + .pScissors = nullptr, + }; +} constexpr VkPipelineRasterizationStateCreateInfo PIPELINE_RASTERIZATION_STATE_CREATE_INFO{ .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, .pNext = nullptr, @@ -361,7 +365,7 @@ void UpdateTwoTexturesDescriptorSet(const Device& device, VkDescriptorSet descri device.GetLogical().UpdateDescriptorSets(write_descriptor_sets, nullptr); } -void BindBlitState(vk::CommandBuffer cmdbuf, const Region2D& dst_region) { +void BindBlitState(const Device& device, vk::CommandBuffer cmdbuf, const Region2D& dst_region) { const VkOffset2D offset{ .x = (std::min)(dst_region.start.x, dst_region.end.x), .y = (std::min)(dst_region.start.y, dst_region.end.y), @@ -383,13 +387,17 @@ void BindBlitState(vk::CommandBuffer cmdbuf, const Region2D& dst_region) { .offset = offset, .extent = extent, }; - cmdbuf.SetViewport(0, viewport); - cmdbuf.SetScissor(0, scissor); + const u32 viewport_count = device.GetViewportCount(); + const std::array viewports{viewport, viewport}; + const std::array scissors{scissor, scissor}; + cmdbuf.SetViewport(0, vk::Span(viewports.data(), viewport_count)); + cmdbuf.SetScissor(0, vk::Span(scissors.data(), viewport_count)); } -void BindBlitState(vk::CommandBuffer cmdbuf, VkPipelineLayout layout, const Region2D& dst_region, - const Region2D& src_region, const Extent3D& src_size = {1, 1, 1}) { - BindBlitState(cmdbuf, dst_region); +void BindBlitState(const Device& device, vk::CommandBuffer cmdbuf, VkPipelineLayout layout, + const Region2D& dst_region, const Region2D& src_region, + const Extent3D& src_size = {1, 1, 1}) { + BindBlitState(device, cmdbuf, dst_region); const float scale_x = static_cast(src_region.end.x - src_region.start.x) / static_cast(src_size.width); const float scale_y = static_cast(src_region.end.y - src_region.start.y) / @@ -559,7 +567,7 @@ void BlitImageHelper::BlitColor(const Framebuffer* dst_framebuffer, const ImageV cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, descriptor_set, nullptr); - BindBlitState(cmdbuf, layout, dst_region, src_region); + BindBlitState(device, cmdbuf, layout, dst_region, src_region); cmdbuf.Draw(3, 1, 0, 0); }); scheduler.InvalidateState(); @@ -585,7 +593,7 @@ void BlitImageHelper::BlitColor(const Framebuffer* dst_framebuffer, VkImageView cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, descriptor_set, nullptr); - BindBlitState(cmdbuf, layout, dst_region, src_region, src_size); + BindBlitState(device, cmdbuf, layout, dst_region, src_region, src_size); cmdbuf.Draw(3, 1, 0, 0); cmdbuf.EndRenderPass(); }); @@ -621,7 +629,7 @@ void BlitImageHelper::BlitDepthStencil(const Framebuffer* dst_framebuffer, cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, descriptor_set, nullptr); - BindBlitState(cmdbuf, layout, dst_region, src_region); + BindBlitState(device, cmdbuf, layout, dst_region, src_region); cmdbuf.Draw(3, 1, 0, 0); }); scheduler.InvalidateState(); @@ -702,13 +710,13 @@ void BlitImageHelper::ClearColor(const Framebuffer* dst_framebuffer, u8 color_ma const VkPipelineLayout layout = *clear_color_pipeline_layout; scheduler.RequestRenderpass(dst_framebuffer); scheduler.Record( - [pipeline, layout, color_mask, clear_color, dst_region](vk::CommandBuffer cmdbuf) { + [pipeline, layout, color_mask, clear_color, dst_region, this](vk::CommandBuffer cmdbuf) { cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); const std::array blend_color = { (color_mask & 0x1) ? 1.0f : 0.0f, (color_mask & 0x2) ? 1.0f : 0.0f, (color_mask & 0x4) ? 1.0f : 0.0f, (color_mask & 0x8) ? 1.0f : 0.0f}; cmdbuf.SetBlendConstants(blend_color.data()); - BindBlitState(cmdbuf, dst_region); + BindBlitState(device, cmdbuf, dst_region); cmdbuf.PushConstants(layout, VK_SHADER_STAGE_FRAGMENT_BIT, clear_color); cmdbuf.Draw(3, 1, 0, 0); }); @@ -728,11 +736,11 @@ void BlitImageHelper::ClearDepthStencil(const Framebuffer* dst_framebuffer, bool const VkPipeline pipeline = FindOrEmplaceClearStencilPipeline(key); const VkPipelineLayout layout = *clear_color_pipeline_layout; scheduler.RequestRenderpass(dst_framebuffer); - scheduler.Record([pipeline, layout, clear_depth, dst_region](vk::CommandBuffer cmdbuf) { + scheduler.Record([pipeline, layout, clear_depth, dst_region, this](vk::CommandBuffer cmdbuf) { constexpr std::array blend_constants{0.0f, 0.0f, 0.0f, 0.0f}; cmdbuf.SetBlendConstants(blend_constants.data()); cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); - BindBlitState(cmdbuf, dst_region); + BindBlitState(device, cmdbuf, dst_region); cmdbuf.PushConstants(layout, VK_SHADER_STAGE_FRAGMENT_BIT, clear_depth); cmdbuf.Draw(3, 1, 0, 0); }); @@ -775,8 +783,11 @@ void BlitImageHelper::Convert(VkPipeline pipeline, const Framebuffer* dst_frameb cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, descriptor_set, nullptr); - cmdbuf.SetViewport(0, viewport); - cmdbuf.SetScissor(0, scissor); + const u32 viewport_count = device.GetViewportCount(); + const std::array viewports{viewport, viewport}; + const std::array scissors{scissor, scissor}; + cmdbuf.SetViewport(0, vk::Span(viewports.data(), viewport_count)); + cmdbuf.SetScissor(0, vk::Span(scissors.data(), viewport_count)); cmdbuf.PushConstants(layout, VK_SHADER_STAGE_VERTEX_BIT, push_constants); cmdbuf.Draw(3, 1, 0, 0); }); @@ -821,8 +832,11 @@ void BlitImageHelper::ConvertDepthStencil(VkPipeline pipeline, const Framebuffer cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, descriptor_set, nullptr); - cmdbuf.SetViewport(0, viewport); - cmdbuf.SetScissor(0, scissor); + const u32 viewport_count = device.GetViewportCount(); + const std::array viewports{viewport, viewport}; + const std::array scissors{scissor, scissor}; + cmdbuf.SetViewport(0, vk::Span(viewports.data(), viewport_count)); + cmdbuf.SetScissor(0, vk::Span(scissors.data(), viewport_count)); cmdbuf.PushConstants(layout, VK_SHADER_STAGE_VERTEX_BIT, push_constants); cmdbuf.Draw(3, 1, 0, 0); }); @@ -860,6 +874,7 @@ VkPipeline BlitImageHelper::FindOrEmplaceColorPipeline(const BlitImagePipelineKe .blendConstants = {0.0f, 0.0f, 0.0f, 0.0f}, }; const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = GetPipelineInputAssemblyStateCreateInfo(device); + const VkPipelineViewportStateCreateInfo viewport_ci = GetPipelineViewportStateCreateInfo(device); blit_color_pipelines.push_back(device.GetLogical().CreateGraphicsPipeline({ .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, .pNext = nullptr, @@ -869,7 +884,7 @@ VkPipeline BlitImageHelper::FindOrEmplaceColorPipeline(const BlitImagePipelineKe .pVertexInputState = &PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, .pInputAssemblyState = &input_assembly_ci, .pTessellationState = nullptr, - .pViewportState = &PIPELINE_VIEWPORT_STATE_CREATE_INFO, + .pViewportState = &viewport_ci, .pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO, .pMultisampleState = &PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, .pDepthStencilState = nullptr, @@ -892,6 +907,7 @@ VkPipeline BlitImageHelper::FindOrEmplaceDepthStencilPipeline(const BlitImagePip blit_depth_stencil_keys.push_back(key); const std::array stages = MakeStages(*full_screen_vert, *blit_depth_stencil_frag); const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = GetPipelineInputAssemblyStateCreateInfo(device); + const VkPipelineViewportStateCreateInfo viewport_ci = GetPipelineViewportStateCreateInfo(device); blit_depth_stencil_pipelines.push_back(device.GetLogical().CreateGraphicsPipeline({ .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, .pNext = nullptr, @@ -901,7 +917,7 @@ VkPipeline BlitImageHelper::FindOrEmplaceDepthStencilPipeline(const BlitImagePip .pVertexInputState = &PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, .pInputAssemblyState = &input_assembly_ci, .pTessellationState = nullptr, - .pViewportState = &PIPELINE_VIEWPORT_STATE_CREATE_INFO, + .pViewportState = &viewport_ci, .pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO, .pMultisampleState = &PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, .pDepthStencilState = &PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, @@ -945,6 +961,7 @@ VkPipeline BlitImageHelper::FindOrEmplaceClearColorPipeline(const BlitImagePipel .blendConstants = {0.0f, 0.0f, 0.0f, 0.0f}, }; const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = GetPipelineInputAssemblyStateCreateInfo(device); + const VkPipelineViewportStateCreateInfo viewport_ci = GetPipelineViewportStateCreateInfo(device); clear_color_pipelines.push_back(device.GetLogical().CreateGraphicsPipeline({ .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, .pNext = nullptr, @@ -954,7 +971,7 @@ VkPipeline BlitImageHelper::FindOrEmplaceClearColorPipeline(const BlitImagePipel .pVertexInputState = &PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, .pInputAssemblyState = &input_assembly_ci, .pTessellationState = nullptr, - .pViewportState = &PIPELINE_VIEWPORT_STATE_CREATE_INFO, + .pViewportState = &viewport_ci, .pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO, .pMultisampleState = &PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, .pDepthStencilState = &PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, @@ -1001,6 +1018,7 @@ VkPipeline BlitImageHelper::FindOrEmplaceClearStencilPipeline( .maxDepthBounds = 0.0f, }; const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = GetPipelineInputAssemblyStateCreateInfo(device); + const VkPipelineViewportStateCreateInfo viewport_ci = GetPipelineViewportStateCreateInfo(device); clear_stencil_pipelines.push_back(device.GetLogical().CreateGraphicsPipeline({ .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, .pNext = nullptr, @@ -1010,7 +1028,7 @@ VkPipeline BlitImageHelper::FindOrEmplaceClearStencilPipeline( .pVertexInputState = &PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, .pInputAssemblyState = &input_assembly_ci, .pTessellationState = nullptr, - .pViewportState = &PIPELINE_VIEWPORT_STATE_CREATE_INFO, + .pViewportState = &viewport_ci, .pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO, .pMultisampleState = &PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, .pDepthStencilState = &depth_stencil_ci, @@ -1032,6 +1050,7 @@ void BlitImageHelper::ConvertDepthToColorPipeline(vk::Pipeline& pipeline, VkRend VkShaderModule frag_shader = *convert_float_to_depth_frag; const std::array stages = MakeStages(*full_screen_vert, frag_shader); const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = GetPipelineInputAssemblyStateCreateInfo(device); + const VkPipelineViewportStateCreateInfo viewport_ci = GetPipelineViewportStateCreateInfo(device); pipeline = device.GetLogical().CreateGraphicsPipeline(VkGraphicsPipelineCreateInfo{ .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, .pNext = nullptr, @@ -1041,7 +1060,7 @@ void BlitImageHelper::ConvertDepthToColorPipeline(vk::Pipeline& pipeline, VkRend .pVertexInputState = &PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, .pInputAssemblyState = &input_assembly_ci, .pTessellationState = nullptr, - .pViewportState = &PIPELINE_VIEWPORT_STATE_CREATE_INFO, + .pViewportState = &viewport_ci, .pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO, .pMultisampleState = &PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, .pDepthStencilState = &PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, @@ -1062,6 +1081,7 @@ void BlitImageHelper::ConvertColorToDepthPipeline(vk::Pipeline& pipeline, VkRend VkShaderModule frag_shader = *convert_depth_to_float_frag; const std::array stages = MakeStages(*full_screen_vert, frag_shader); const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = GetPipelineInputAssemblyStateCreateInfo(device); + const VkPipelineViewportStateCreateInfo viewport_ci = GetPipelineViewportStateCreateInfo(device); pipeline = device.GetLogical().CreateGraphicsPipeline(VkGraphicsPipelineCreateInfo{ .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, .pNext = nullptr, @@ -1071,7 +1091,7 @@ void BlitImageHelper::ConvertColorToDepthPipeline(vk::Pipeline& pipeline, VkRend .pVertexInputState = &PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, .pInputAssemblyState = &input_assembly_ci, .pTessellationState = nullptr, - .pViewportState = &PIPELINE_VIEWPORT_STATE_CREATE_INFO, + .pViewportState = &viewport_ci, .pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO, .pMultisampleState = &PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, .pDepthStencilState = &PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, @@ -1093,6 +1113,7 @@ void BlitImageHelper::ConvertPipelineEx(vk::Pipeline& pipeline, VkRenderPass ren } const std::array stages = MakeStages(*full_screen_vert, *module); const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = GetPipelineInputAssemblyStateCreateInfo(device); + const VkPipelineViewportStateCreateInfo viewport_ci = GetPipelineViewportStateCreateInfo(device); pipeline = device.GetLogical().CreateGraphicsPipeline(VkGraphicsPipelineCreateInfo{ .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, .pNext = nullptr, @@ -1102,7 +1123,7 @@ void BlitImageHelper::ConvertPipelineEx(vk::Pipeline& pipeline, VkRenderPass ren .pVertexInputState = &PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, .pInputAssemblyState = &input_assembly_ci, .pTessellationState = nullptr, - .pViewportState = &PIPELINE_VIEWPORT_STATE_CREATE_INFO, + .pViewportState = &viewport_ci, .pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO, .pMultisampleState = &PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, .pDepthStencilState = is_target_depth ? &PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO : nullptr, @@ -1135,6 +1156,7 @@ void BlitImageHelper::ConvertPipeline(vk::Pipeline& pipeline, VkRenderPass rende is_target_depth ? *convert_float_to_depth_frag : *convert_depth_to_float_frag; const std::array stages = MakeStages(*full_screen_vert, frag_shader); const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = GetPipelineInputAssemblyStateCreateInfo(device); + const VkPipelineViewportStateCreateInfo viewport_ci = GetPipelineViewportStateCreateInfo(device); pipeline = device.GetLogical().CreateGraphicsPipeline(VkGraphicsPipelineCreateInfo{ .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, .pNext = nullptr, @@ -1144,7 +1166,7 @@ void BlitImageHelper::ConvertPipeline(vk::Pipeline& pipeline, VkRenderPass rende .pVertexInputState = &PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, .pInputAssemblyState = &input_assembly_ci, .pTessellationState = nullptr, - .pViewportState = &PIPELINE_VIEWPORT_STATE_CREATE_INFO, + .pViewportState = &viewport_ci, .pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO, .pMultisampleState = &PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, .pDepthStencilState = is_target_depth ? &PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO : nullptr, diff --git a/src/video_core/renderer_vulkan/present/fsr.cpp b/src/video_core/renderer_vulkan/present/fsr.cpp index 894fb144f0..ef6766e24b 100644 --- a/src/video_core/renderer_vulkan/present/fsr.cpp +++ b/src/video_core/renderer_vulkan/present/fsr.cpp @@ -183,10 +183,10 @@ VkImageView FSR::Draw(const Device& device, Scheduler& scheduler, size_t image_i UpdateDescriptorSets(device, source_image_view, image_index); scheduler.RequestOutsideRenderPassOperationContext(); - scheduler.Record([=](vk::CommandBuffer cmdbuf) { + scheduler.Record([=, &device](vk::CommandBuffer cmdbuf) { TransitionImageLayout(cmdbuf, source_image, VK_IMAGE_LAYOUT_GENERAL); TransitionImageLayout(cmdbuf, easu_image, VK_IMAGE_LAYOUT_GENERAL); - BeginRenderPass(cmdbuf, renderpass, easu_framebuffer, extent); + BeginRenderPass(device, cmdbuf, renderpass, easu_framebuffer, extent); cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, easu_pipeline); cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, easu_descriptor_set, {}); @@ -196,7 +196,7 @@ VkImageView FSR::Draw(const Device& device, Scheduler& scheduler, size_t image_i TransitionImageLayout(cmdbuf, easu_image, VK_IMAGE_LAYOUT_GENERAL); TransitionImageLayout(cmdbuf, rcas_image, VK_IMAGE_LAYOUT_GENERAL); - BeginRenderPass(cmdbuf, renderpass, rcas_framebuffer, extent); + BeginRenderPass(device, cmdbuf, renderpass, rcas_framebuffer, extent); cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, rcas_pipeline); cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, rcas_descriptor_set, {}); diff --git a/src/video_core/renderer_vulkan/present/fxaa.cpp b/src/video_core/renderer_vulkan/present/fxaa.cpp index 62f79d490c..b77c3d6fef 100644 --- a/src/video_core/renderer_vulkan/present/fxaa.cpp +++ b/src/video_core/renderer_vulkan/present/fxaa.cpp @@ -129,10 +129,10 @@ void FXAA::Draw(const Device& device, Scheduler& scheduler, size_t image_index, UpdateDescriptorSets(device, *inout_image_view, image_index); scheduler.RequestOutsideRenderPassOperationContext(); - scheduler.Record([=](vk::CommandBuffer cmdbuf) { + scheduler.Record([=, &device](vk::CommandBuffer cmdbuf) { TransitionImageLayout(cmdbuf, input_image, VK_IMAGE_LAYOUT_GENERAL); TransitionImageLayout(cmdbuf, output_image, VK_IMAGE_LAYOUT_GENERAL); - BeginRenderPass(cmdbuf, renderpass, framebuffer, extent); + BeginRenderPass(device, cmdbuf, renderpass, framebuffer, extent); cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, descriptor_set, {}); cmdbuf.Draw(3, 1, 0, 0); diff --git a/src/video_core/renderer_vulkan/present/sgsr.cpp b/src/video_core/renderer_vulkan/present/sgsr.cpp index 5fc746458d..25d672bbd4 100644 --- a/src/video_core/renderer_vulkan/present/sgsr.cpp +++ b/src/video_core/renderer_vulkan/present/sgsr.cpp @@ -125,10 +125,10 @@ VkImageView SGSR::Draw(const Device& device, Scheduler& scheduler, size_t image_ UpdateDescriptorSets(device, source_image_view, image_index); scheduler.RequestOutsideRenderPassOperationContext(); - scheduler.Record([=](vk::CommandBuffer cmdbuf) { + scheduler.Record([=, &device](vk::CommandBuffer cmdbuf) { TransitionImageLayout(cmdbuf, source_image, VK_IMAGE_LAYOUT_GENERAL); TransitionImageLayout(cmdbuf, output_image, VK_IMAGE_LAYOUT_GENERAL); - BeginRenderPass(cmdbuf, renderpass, framebuffer, extent); + BeginRenderPass(device, cmdbuf, renderpass, framebuffer, extent); cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, descriptor_set, {}); cmdbuf.PushConstants(layout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, viewport_con); diff --git a/src/video_core/renderer_vulkan/present/smaa.cpp b/src/video_core/renderer_vulkan/present/smaa.cpp index 28b0427fa0..54d5c55ddd 100644 --- a/src/video_core/renderer_vulkan/present/smaa.cpp +++ b/src/video_core/renderer_vulkan/present/smaa.cpp @@ -237,10 +237,10 @@ void SMAA::Draw(const Device& device, Scheduler& scheduler, size_t image_index, UpdateDescriptorSets(device, *inout_image_view, image_index); scheduler.RequestOutsideRenderPassOperationContext(); - scheduler.Record([=, this](vk::CommandBuffer cmdbuf) { + scheduler.Record([=, this, &device](vk::CommandBuffer cmdbuf) { TransitionImageLayout(cmdbuf, input_image, VK_IMAGE_LAYOUT_GENERAL); TransitionImageLayout(cmdbuf, edges_image, VK_IMAGE_LAYOUT_GENERAL); - BeginRenderPass(cmdbuf, *m_renderpasses[EdgeDetection], edge_detection_framebuffer, + BeginRenderPass(device, cmdbuf, *m_renderpasses[EdgeDetection], edge_detection_framebuffer, m_extent); cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipelines[EdgeDetection]); cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, @@ -251,7 +251,7 @@ void SMAA::Draw(const Device& device, Scheduler& scheduler, size_t image_index, TransitionImageLayout(cmdbuf, edges_image, VK_IMAGE_LAYOUT_GENERAL); TransitionImageLayout(cmdbuf, blend_image, VK_IMAGE_LAYOUT_GENERAL); - BeginRenderPass(cmdbuf, *m_renderpasses[BlendingWeightCalculation], + BeginRenderPass(device, cmdbuf, *m_renderpasses[BlendingWeightCalculation], blending_weight_calculation_framebuffer, m_extent); cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipelines[BlendingWeightCalculation]); @@ -263,7 +263,7 @@ void SMAA::Draw(const Device& device, Scheduler& scheduler, size_t image_index, TransitionImageLayout(cmdbuf, blend_image, VK_IMAGE_LAYOUT_GENERAL); TransitionImageLayout(cmdbuf, output_image, VK_IMAGE_LAYOUT_GENERAL); - BeginRenderPass(cmdbuf, *m_renderpasses[NeighborhoodBlending], + BeginRenderPass(device, cmdbuf, *m_renderpasses[NeighborhoodBlending], neighborhood_blending_framebuffer, m_extent); cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipelines[NeighborhoodBlending]); cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, diff --git a/src/video_core/renderer_vulkan/present/util.cpp b/src/video_core/renderer_vulkan/present/util.cpp index 2b83902bc0..23a4f75de1 100644 --- a/src/video_core/renderer_vulkan/present/util.cpp +++ b/src/video_core/renderer_vulkan/present/util.cpp @@ -5,6 +5,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include "common/assert.h" +#include #include #include #include "video_core/renderer_vulkan/present/util.h" @@ -408,14 +409,14 @@ static vk::Pipeline CreateWrappedPipelineImpl( .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, .primitiveRestartEnable = device.IsMoltenVK() ? VK_TRUE : VK_FALSE, }; - - constexpr VkPipelineViewportStateCreateInfo viewport_state_ci{ + const u32 viewport_count = device.GetViewportCount(); + const VkPipelineViewportStateCreateInfo viewport_state_ci{ .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, .pNext = nullptr, .flags = 0, - .viewportCount = 1, + .viewportCount = viewport_count, .pViewports = nullptr, - .scissorCount = 1, + .scissorCount = viewport_count, .pScissors = nullptr, }; @@ -669,8 +670,8 @@ void ClearColorImage(vk::CommandBuffer& cmdbuf, VkImage image) { cmdbuf.ClearColorImage(image, VK_IMAGE_LAYOUT_GENERAL, {}, subresources); } -void BeginRenderPass(vk::CommandBuffer& cmdbuf, VkRenderPass render_pass, VkFramebuffer framebuffer, - VkExtent2D extent) { +void BeginRenderPass(const Device& device, vk::CommandBuffer& cmdbuf, VkRenderPass render_pass, + VkFramebuffer framebuffer, VkExtent2D extent) { const VkRenderPassBeginInfo renderpass_bi{ .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, .pNext = nullptr, @@ -697,8 +698,11 @@ void BeginRenderPass(vk::CommandBuffer& cmdbuf, VkRenderPass render_pass, VkFram .offset = {0, 0}, .extent = extent, }; - cmdbuf.SetViewport(0, viewport); - cmdbuf.SetScissor(0, scissor); + const u32 viewport_count = device.GetViewportCount(); + const std::array viewports{viewport, viewport}; + const std::array scissors{scissor, scissor}; + cmdbuf.SetViewport(0, vk::Span(viewports.data(), viewport_count)); + cmdbuf.SetScissor(0, vk::Span(scissors.data(), viewport_count)); } } // namespace Vulkan diff --git a/src/video_core/renderer_vulkan/present/util.h b/src/video_core/renderer_vulkan/present/util.h index 38cc6203c5..75f4571379 100644 --- a/src/video_core/renderer_vulkan/present/util.h +++ b/src/video_core/renderer_vulkan/present/util.h @@ -59,7 +59,7 @@ vk::Sampler CreateBilinearSampler(const Device& device); vk::Sampler CreateNearestNeighborSampler(const Device& device); vk::Sampler CreateCubicSampler(const Device& device, VkCubicFilterWeightsQCOM qcom_weights); -void BeginRenderPass(vk::CommandBuffer& cmdbuf, VkRenderPass render_pass, VkFramebuffer framebuffer, - VkExtent2D extent); +void BeginRenderPass(const Device& device, vk::CommandBuffer& cmdbuf, VkRenderPass render_pass, + VkFramebuffer framebuffer, VkExtent2D extent); } // namespace Vulkan diff --git a/src/video_core/renderer_vulkan/present/window_adapt_pass.cpp b/src/video_core/renderer_vulkan/present/window_adapt_pass.cpp index 549b0660c1..257df24c81 100644 --- a/src/video_core/renderer_vulkan/present/window_adapt_pass.cpp +++ b/src/video_core/renderer_vulkan/present/window_adapt_pass.cpp @@ -69,7 +69,7 @@ void WindowAdaptPass::Draw(const Device& device, RasterizerVulkan& rasterizer, S layer_it++; } - scheduler.Record([=](vk::CommandBuffer cmdbuf) { + scheduler.Record([=, &device](vk::CommandBuffer cmdbuf) { const f32 bg_red = Settings::values.bg_red.GetValue() / 255.0f; const f32 bg_green = Settings::values.bg_green.GetValue() / 255.0f; const f32 bg_blue = Settings::values.bg_blue.GetValue() / 255.0f; @@ -91,7 +91,7 @@ void WindowAdaptPass::Draw(const Device& device, RasterizerVulkan& rasterizer, S .layerCount = 1, }; - BeginRenderPass(cmdbuf, renderpass, host_framebuffer, render_area); + BeginRenderPass(device, cmdbuf, renderpass, host_framebuffer, render_area); cmdbuf.ClearAttachments({clear_attachment}, {clear_rect}); for (size_t i = 0; i < layer_count; i++) { diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp index cd42bd22af..41dd086495 100644 --- a/src/video_core/vulkan_common/vulkan_device.cpp +++ b/src/video_core/vulkan_common/vulkan_device.cpp @@ -441,6 +441,7 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR const bool is_mvk = driver_id == VK_DRIVER_ID_MOLTENVK; const bool is_qualcomm = driver_id == VK_DRIVER_ID_QUALCOMM_PROPRIETARY; const bool is_turnip = driver_id == VK_DRIVER_ID_MESA_TURNIP; + const bool is_arm = driver_id == VK_DRIVER_ID_ARM_PROPRIETARY; if (!is_suitable) LOG_WARNING(Render_Vulkan, "Unsuitable driver - continuing anyways"); @@ -656,6 +657,11 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR properties.properties.limits.maxVertexInputBindings = 32; } + if (is_arm && SupportsMultiViewport()) { + LOG_WARNING(Render_Vulkan, "ARM driver requires setting multiple viewports on command buffer reuse"); + requires_setting_multi_viewports_on_cmdbuf_reuse = true; + } + const auto dyna_state = Settings::values.dyna_state.GetValue(); // Base dynamic states (VIEWPORT, SCISSOR, DEPTH_BIAS, etc.) are ALWAYS active in vk_graphics_pipeline.cpp diff --git a/src/video_core/vulkan_common/vulkan_device.h b/src/video_core/vulkan_common/vulkan_device.h index 7f2c29519f..17c1adf447 100644 --- a/src/video_core/vulkan_common/vulkan_device.h +++ b/src/video_core/vulkan_common/vulkan_device.h @@ -834,6 +834,10 @@ public: return features2.features.multiViewport; } + u32 GetViewportCount() const noexcept { + return requires_setting_multi_viewports_on_cmdbuf_reuse ? 2U : 1U; + } + /// Returns true if the device supports VK_KHR_maintenance1. bool IsKhrMaintenance1Supported() const { return extensions.maintenance1; @@ -1046,6 +1050,7 @@ private: bool supports_d24_depth{}; ///< Supports D24 depth buffers. bool cant_blit_msaa{}; ///< Does not support MSAA<->MSAA blitting. bool must_emulate_scaled_formats{}; ///< Requires scaled vertex format emulation + bool requires_setting_multi_viewports_on_cmdbuf_reuse{}; ///< ARM workaround to always set 2+ viewports. bool dynamic_state3_blending{}; ///< Has blending features of dynamic_state3. bool dynamic_state3_enables{}; ///< Has at least one enable feature of dynamic_state3. bool dynamic_state3_depth_clamp_enable{};