diff --git a/src/video_core/renderer_vulkan/blit_image.cpp b/src/video_core/renderer_vulkan/blit_image.cpp index 079dee53a5..c92040691d 100644 --- a/src/video_core/renderer_vulkan/blit_image.cpp +++ b/src/video_core/renderer_vulkan/blit_image.cpp @@ -709,10 +709,12 @@ void BlitImageHelper::BlitColorMSAA(const Framebuffer* dst_framebuffer, const BlitMSAAPipelineKey key{ .renderpass = dst_framebuffer->RenderPass(), .samples = dst_framebuffer->Samples(), + .color_formats = dst_framebuffer->ColorAttachmentFormats(), + .depth_format = dst_framebuffer->DepthAttachmentFormat(), }; const VkPipelineLayout layout = *one_texture_pipeline_layout; const VkSampler sampler = *nearest_sampler; - const VkPipeline pipeline = FindOrEmplaceBlitColorMSAAPipeline(key); + const VkPipeline pipeline = FindOrEmplaceBlitColorMSAAPipeline(key, dst_framebuffer); const VkImageView src_view = src_image_view.Handle(Shader::TextureType::Color2D); RecordShaderReadBarrier(scheduler, src_image_view); @@ -736,7 +738,7 @@ void BlitImageHelper::ResolveDepthStencil(const Framebuffer* dst_framebuffer, const bool resolve_stencil = dst_framebuffer->HasAspectStencilBit() && device.IsExtShaderStencilExportSupported(); const VkPipeline pipeline = - FindOrEmplaceResolveDepthStencilPipeline(dst_framebuffer->RenderPass(), resolve_stencil); + FindOrEmplaceResolveDepthStencilPipeline(dst_framebuffer, resolve_stencil); const VkPipelineLayout layout = resolve_stencil ? *two_textures_pipeline_layout : *one_texture_pipeline_layout; const VkSampler sampler = *nearest_sampler; @@ -1382,12 +1384,14 @@ VkPipeline BlitImageHelper::FindOrEmplaceClearStencilPipeline( return *clear_stencil_pipelines.back(); } -VkPipeline BlitImageHelper::FindOrEmplaceBlitColorMSAAPipeline(const BlitMSAAPipelineKey& key) { +VkPipeline BlitImageHelper::FindOrEmplaceBlitColorMSAAPipeline(const BlitMSAAPipelineKey& key, + const Framebuffer* framebuffer) { const auto it = std::ranges::find(blit_msaa_color_keys, key); if (it != blit_msaa_color_keys.end()) { return *blit_msaa_color_pipelines[std::distance(blit_msaa_color_keys.begin(), it)]; } blit_msaa_color_keys.push_back(key); + const VkPipelineRenderingCreateInfo rendering_ci = MakePipelineRenderingCreateInfo(framebuffer); const std::array stages = MakeStages(*full_screen_vert, *blit_color_msaa_frag); const VkPipelineMultisampleStateCreateInfo multisample_ci{ .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, @@ -1403,7 +1407,7 @@ VkPipeline BlitImageHelper::FindOrEmplaceBlitColorMSAAPipeline(const BlitMSAAPip const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = GetPipelineInputAssemblyStateCreateInfo(device); blit_msaa_color_pipelines.push_back(device.GetLogical().CreateGraphicsPipeline({ .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, - .pNext = nullptr, + .pNext = key.renderpass ? nullptr : &rendering_ci, .flags = 0, .stageCount = static_cast(stages.size()), .pStages = stages.data(), @@ -1425,22 +1429,28 @@ VkPipeline BlitImageHelper::FindOrEmplaceBlitColorMSAAPipeline(const BlitMSAAPip return *blit_msaa_color_pipelines.back(); } -VkPipeline BlitImageHelper::FindOrEmplaceResolveDepthStencilPipeline(VkRenderPass renderpass, - bool resolve_stencil) { +VkPipeline BlitImageHelper::FindOrEmplaceResolveDepthStencilPipeline( + const Framebuffer* framebuffer, bool resolve_stencil) { + const VkRenderPass renderpass = framebuffer->RenderPass(); + const ResolveDepthStencilPipelineKey key{ + .renderpass = renderpass, + .depth_format = framebuffer->DepthAttachmentFormat(), + }; auto& keys = resolve_stencil ? resolve_depth_stencil_keys : resolve_depth_keys; auto& pipelines = resolve_stencil ? resolve_depth_stencil_pipelines : resolve_depth_pipelines; - const auto it = std::ranges::find(keys, renderpass); + const auto it = std::ranges::find(keys, key); if (it != keys.end()) { return *pipelines[std::distance(keys.begin(), it)]; } - keys.push_back(renderpass); + keys.push_back(key); + const VkPipelineRenderingCreateInfo rendering_ci = MakePipelineRenderingCreateInfo(framebuffer); const std::array stages = MakeStages(*full_screen_vert, resolve_stencil ? *blit_depth_stencil_msaa_frag : *blit_depth_msaa_frag); const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = GetPipelineInputAssemblyStateCreateInfo(device); pipelines.push_back(device.GetLogical().CreateGraphicsPipeline({ .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, - .pNext = nullptr, + .pNext = renderpass ? nullptr : &rendering_ci, .flags = 0, .stageCount = static_cast(stages.size()), .pStages = stages.data(), diff --git a/src/video_core/renderer_vulkan/blit_image.h b/src/video_core/renderer_vulkan/blit_image.h index ea8f37a48f..fd4db58a3b 100644 --- a/src/video_core/renderer_vulkan/blit_image.h +++ b/src/video_core/renderer_vulkan/blit_image.h @@ -62,6 +62,15 @@ struct BlitMSAAPipelineKey { VkRenderPass renderpass; VkSampleCountFlagBits samples; + std::array color_formats; + VkFormat depth_format; +}; + +struct ResolveDepthStencilPipelineKey { + constexpr auto operator<=>(const ResolveDepthStencilPipelineKey&) const noexcept = default; + + VkRenderPass renderpass; + VkFormat depth_format; }; class BlitImageHelper { @@ -138,8 +147,9 @@ private: [[nodiscard]] VkPipeline FindOrEmplaceClearStencilPipeline( const BlitDepthStencilPipelineKey& key, const Framebuffer* framebuffer); [[nodiscard]] VkPipeline FindOrEmplaceMSAACopyPipeline(const MSAACopyPipelineKey& key); - [[nodiscard]] VkPipeline FindOrEmplaceBlitColorMSAAPipeline(const BlitMSAAPipelineKey& key); - [[nodiscard]] VkPipeline FindOrEmplaceResolveDepthStencilPipeline(VkRenderPass renderpass, + [[nodiscard]] VkPipeline FindOrEmplaceBlitColorMSAAPipeline(const BlitMSAAPipelineKey& key, + const Framebuffer* framebuffer); + [[nodiscard]] VkPipeline FindOrEmplaceResolveDepthStencilPipeline(const Framebuffer* framebuffer, bool resolve_stencil); void ConvertPipeline(vk::Pipeline& pipeline, const Framebuffer* framebuffer, @@ -203,9 +213,9 @@ private: std::vector msaa_copy_pipelines; std::vector blit_msaa_color_keys; std::vector blit_msaa_color_pipelines; - std::vector resolve_depth_keys; + std::vector resolve_depth_keys; std::vector resolve_depth_pipelines; - std::vector resolve_depth_stencil_keys; + std::vector resolve_depth_stencil_keys; std::vector resolve_depth_stencil_pipelines; struct MSAACopyResources { u64 tick; diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp index 8884535f1c..4402550af9 100644 --- a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp @@ -197,7 +197,7 @@ public: } if (!host_visible) { - scheduler.RequestOutsideRenderPassOperationContext(true); + scheduler.RequestOutsideRenderPassOperationContext(); scheduler.Record([src_buffer = staging.buffer, src_offset = staging.offset, dst_buffer = *buffer, size_bytes](vk::CommandBuffer cmdbuf) { const VkBufferCopy copy{ @@ -454,7 +454,7 @@ void BufferCacheRuntime::CopyBuffer(VkBuffer dst_buffer, VkBuffer src_buffer, return; } - scheduler.RequestOutsideRenderPassOperationContext(true); + scheduler.RequestOutsideRenderPassOperationContext(); scheduler.Record([src_buffer, dst_buffer, vk_copies, barrier](vk::CommandBuffer cmdbuf) { if (barrier) { cmdbuf.PipelineBarrier(vk::PIPELINE_STAGE_GRAPHICS_COMPUTE_TRANSFER, @@ -475,7 +475,7 @@ void BufferCacheRuntime::PreCopyBarrier() { .srcAccessMask = VK_ACCESS_MEMORY_WRITE_BIT, .dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT, }; - scheduler.RequestOutsideRenderPassOperationContext(true); + scheduler.RequestOutsideRenderPassOperationContext(); scheduler.Record([](vk::CommandBuffer cmdbuf) { cmdbuf.PipelineBarrier(vk::PIPELINE_STAGE_GRAPHICS_COMPUTE_TRANSFER, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, READ_BARRIER); @@ -489,7 +489,7 @@ void BufferCacheRuntime::PostCopyBarrier() { .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, .dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT, }; - scheduler.RequestOutsideRenderPassOperationContext(true); + scheduler.RequestOutsideRenderPassOperationContext(); scheduler.Record([](vk::CommandBuffer cmdbuf) { cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, vk::PIPELINE_STAGE_GRAPHICS_COMPUTE, 0, WRITE_BARRIER); @@ -513,7 +513,7 @@ void BufferCacheRuntime::ClearBuffer(VkBuffer dest_buffer, u32 offset, size_t si .dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT, }; - scheduler.RequestOutsideRenderPassOperationContext(true); + scheduler.RequestOutsideRenderPassOperationContext(); scheduler.Record([dest_buffer, offset, size, value](vk::CommandBuffer cmdbuf) { cmdbuf.PipelineBarrier(vk::PIPELINE_STAGE_GRAPHICS_COMPUTE_TRANSFER, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, READ_BARRIER); @@ -695,7 +695,7 @@ vk::Buffer BufferCacheRuntime::CreateNullBuffer() { ret.SetObjectNameEXT("Null buffer"); } - scheduler.RequestOutsideRenderPassOperationContext(true); + scheduler.RequestOutsideRenderPassOperationContext(); scheduler.Record([buffer = *ret](vk::CommandBuffer cmdbuf) { cmdbuf.FillBuffer(buffer, 0, VK_WHOLE_SIZE, 0); }); diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index a937f8e0c1..720f3b868c 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -423,7 +423,6 @@ void RasterizerVulkan::Clear(u32 layer_count) { const bool can_defer_clear = ENABLE_DEFERRED_CLEAR && !regs.clear_control.use_scissor && regs.clear_surface.layer == 0 && !scheduler.IsRenderPassActive() && - !device.IsKhrDynamicRenderingSupported() && (!use_color || color_full_channels) && ds_deferrable; if (!can_defer_clear) { scheduler.RequestRenderpass(framebuffer); diff --git a/src/video_core/renderer_vulkan/vk_scheduler.cpp b/src/video_core/renderer_vulkan/vk_scheduler.cpp index af769faf35..5dba1ebdd9 100644 --- a/src/video_core/renderer_vulkan/vk_scheduler.cpp +++ b/src/video_core/renderer_vulkan/vk_scheduler.cpp @@ -93,40 +93,44 @@ void Scheduler::DispatchWork() { } } +void Scheduler::BeginDynamicRendering(const Framebuffer* framebuffer, const DeferredClear* clear) { + const VkExtent2D render_area = framebuffer->RenderArea(); + std::array attachment_views{}; + const auto& color_views = framebuffer->ColorAttachments(); + for (size_t index = 0; index < color_views.size(); ++index) { + attachment_views[index] = color_views[index]; + } + attachment_views[8] = framebuffer->DepthAttachment(); + state.renderpass = VkRenderPass{}; + state.framebuffer = VkFramebuffer{}; + state.attachment_views = attachment_views; + state.render_area = render_area; + state.num_color = framebuffer->NumColorAttachments(); + state.has_depth = framebuffer->HasAspectDepthBit(); + state.has_stencil = framebuffer->HasAspectStencilBit(); + state.layer_count = framebuffer->NumLayers(); + state.rendering = true; + + if (GPU::Logging::IsActive() && Settings::values.gpu_log_vulkan_calls.GetValue()) { + const std::string render_pass_info = + fmt::format("renderArea={}x{}, numImages={}", render_area.width, render_area.height, + framebuffer->NumImages()); + GPU::Logging::GPULogger::GetInstance().LogRenderPassBegin(render_pass_info); + } + + RecordDynamicBegin(clear); + num_renderpass_images = framebuffer->NumImages(); + renderpass_images = framebuffer->Images(); + renderpass_image_ranges = framebuffer->ImageRanges(); +} + void Scheduler::BeginRenderPassImpl(const Framebuffer* framebuffer, VkRenderPass renderpass, const VkClearValue* clear_values, u32 clear_value_count) { - const VkExtent2D render_area = framebuffer->RenderArea(); if (device.IsKhrDynamicRenderingSupported()) { - std::array attachment_views{}; - const auto& color_views = framebuffer->ColorAttachments(); - for (size_t index = 0; index < color_views.size(); ++index) { - attachment_views[index] = color_views[index]; - } - attachment_views[8] = framebuffer->DepthAttachment(); - state.renderpass = VkRenderPass{}; - state.framebuffer = VkFramebuffer{}; - state.attachment_views = attachment_views; - state.render_area = render_area; - state.num_color = framebuffer->NumColorAttachments(); - state.has_depth = framebuffer->HasAspectDepthBit(); - state.has_stencil = framebuffer->HasAspectStencilBit(); - state.layer_count = framebuffer->NumLayers(); - state.rendering = true; - state.suspended = false; - - if (GPU::Logging::IsActive() && Settings::values.gpu_log_vulkan_calls.GetValue()) { - const std::string render_pass_info = - fmt::format("renderArea={}x{}, numImages={}", render_area.width, render_area.height, - framebuffer->NumImages()); - GPU::Logging::GPULogger::GetInstance().LogRenderPassBegin(render_pass_info); - } - - RecordDynamicBegin(false, true); - num_renderpass_images = framebuffer->NumImages(); - renderpass_images = framebuffer->Images(); - renderpass_image_ranges = framebuffer->ImageRanges(); + BeginDynamicRendering(framebuffer, nullptr); return; } + const VkExtent2D render_area = framebuffer->RenderArea(); const VkFramebuffer framebuffer_handle = framebuffer->Handle(); state.renderpass = renderpass; state.framebuffer = framebuffer_handle; @@ -173,6 +177,12 @@ void Scheduler::RealizeDeferredClear() { const DeferredClear dc = deferred_clear; deferred_clear = {}; + if (device.IsKhrDynamicRenderingSupported()) { + EndRenderPass(); + BeginDynamicRendering(dc.framebuffer, &dc); + return; + } + std::array clear_values{}; u32 count = 0; const RenderPassKey& base = dc.framebuffer->RenderPassKeyBase(); @@ -235,20 +245,13 @@ void Scheduler::RequestRenderpass(const Framebuffer* framebuffer) { attachment_views[index] = color_views[index]; } attachment_views[8] = framebuffer->DepthAttachment(); - const bool same_target = state.rendering && - attachment_views == state.attachment_views && - render_area.width == state.render_area.width && - render_area.height == state.render_area.height; - if (same_target && !state.suspended) { - return; - } - if (same_target && state.suspended) { - RecordDynamicBegin(true, true); - state.suspended = false; + if (state.rendering && attachment_views == state.attachment_views && + render_area.width == state.render_area.width && + render_area.height == state.render_area.height) { return; } EndRenderPass(); - BeginRenderPassImpl(framebuffer, VkRenderPass{}, nullptr, 0); + BeginDynamicRendering(framebuffer, nullptr); return; } const VkRenderPass renderpass = framebuffer->RenderPass(); @@ -263,16 +266,7 @@ void Scheduler::RequestRenderpass(const Framebuffer* framebuffer) { BeginRenderPassImpl(framebuffer, renderpass, nullptr, 0); } -void Scheduler::RequestOutsideRenderPassOperationContext(bool allow_suspend) { - if (allow_suspend && device.IsKhrDynamicRenderingSupported() && state.rendering && - !state.suspended) { - query_cache->CounterClose(VideoCommon::QueryType::StreamingByteCount); - query_cache->CounterEnable(VideoCommon::QueryType::ZPassPixelCount64, false); - query_cache->NotifySegment(false); - Record([](vk::CommandBuffer cmdbuf) { cmdbuf.EndRendering(); }); - state.suspended = true; - return; - } +void Scheduler::RequestOutsideRenderPassOperationContext() { EndRenderPass(); } @@ -436,24 +430,23 @@ void Scheduler::InvalidateState() { state_tracker.InvalidateCommandBufferState(); } -void Scheduler::RecordDynamicBegin(bool resuming, bool suspending) { +void Scheduler::RecordDynamicBegin(const DeferredClear* clear) { const std::array views = state.attachment_views; const u32 num_color = state.num_color; const bool has_depth = state.has_depth; const bool has_stencil = state.has_stencil; const u32 layers = state.layer_count; const VkExtent2D render_area = state.render_area; - VkRenderingFlags flags = 0; - if (resuming) { - flags |= VK_RENDERING_RESUMING_BIT; - } - if (suspending) { - flags |= VK_RENDERING_SUSPENDING_BIT; - } - Record([views, num_color, has_depth, has_stencil, layers, render_area, - flags](vk::CommandBuffer cmdbuf) { + const u32 color_clear_mask = clear ? clear->color_clear_mask : 0u; + const std::array color_clear_values = + clear ? clear->color_values : std::array{}; + const bool ds_clear = clear != nullptr && clear->depth_stencil; + const VkClearValue ds_clear_value = clear ? clear->depth_stencil_value : VkClearValue{}; + Record([views, num_color, has_depth, has_stencil, layers, render_area, color_clear_mask, + color_clear_values, ds_clear, ds_clear_value](vk::CommandBuffer cmdbuf) { std::array color_infos{}; for (u32 index = 0; index < num_color; ++index) { + const bool clear_slot = ((color_clear_mask >> index) & 1u) != 0; color_infos[index] = VkRenderingAttachmentInfo{ .sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO, .pNext = nullptr, @@ -462,9 +455,9 @@ void Scheduler::RecordDynamicBegin(bool resuming, bool suspending) { .resolveMode = VK_RESOLVE_MODE_NONE, .resolveImageView = VK_NULL_HANDLE, .resolveImageLayout = VK_IMAGE_LAYOUT_UNDEFINED, - .loadOp = VK_ATTACHMENT_LOAD_OP_LOAD, + .loadOp = clear_slot ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD, .storeOp = VK_ATTACHMENT_STORE_OP_STORE, - .clearValue = {}, + .clearValue = clear_slot ? color_clear_values[index] : VkClearValue{}, }; } const VkRenderingAttachmentInfo depth_info{ @@ -475,14 +468,14 @@ void Scheduler::RecordDynamicBegin(bool resuming, bool suspending) { .resolveMode = VK_RESOLVE_MODE_NONE, .resolveImageView = VK_NULL_HANDLE, .resolveImageLayout = VK_IMAGE_LAYOUT_UNDEFINED, - .loadOp = VK_ATTACHMENT_LOAD_OP_LOAD, + .loadOp = ds_clear ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD, .storeOp = VK_ATTACHMENT_STORE_OP_STORE, - .clearValue = {}, + .clearValue = ds_clear ? ds_clear_value : VkClearValue{}, }; const VkRenderingInfo rendering_info{ .sType = VK_STRUCTURE_TYPE_RENDERING_INFO, .pNext = nullptr, - .flags = flags, + .flags = 0, .renderArea = { .offset = {.x = 0, .y = 0}, @@ -511,29 +504,16 @@ void Scheduler::EndRenderPass() return; } - const bool dynamic = device.IsKhrDynamicRenderingSupported(); - - if (!state.suspended) { - query_cache->CounterClose(VideoCommon::QueryType::StreamingByteCount); - - // Log render pass end - if (GPU::Logging::IsActive() && - Settings::values.gpu_log_vulkan_calls.GetValue()) { - GPU::Logging::GPULogger::GetInstance().LogRenderPassEnd(); - } - - query_cache->CounterEnable(VideoCommon::QueryType::ZPassPixelCount64, false); - query_cache->NotifySegment(false); + query_cache->CounterClose(VideoCommon::QueryType::StreamingByteCount); - if (dynamic) { - Record([](vk::CommandBuffer cmdbuf) { cmdbuf.EndRendering(); }); - state.suspended = true; - } + // Log render pass end + if (GPU::Logging::IsActive() && + Settings::values.gpu_log_vulkan_calls.GetValue()) { + GPU::Logging::GPULogger::GetInstance().LogRenderPassEnd(); } - if (dynamic && state.suspended) { - RecordDynamicBegin(true, false); - } + query_cache->CounterEnable(VideoCommon::QueryType::ZPassPixelCount64, false); + query_cache->NotifySegment(false); Record([num_images = num_renderpass_images, images = renderpass_images, @@ -601,7 +581,6 @@ void Scheduler::EndRenderPass() state.framebuffer = VkFramebuffer{}; state.attachment_views = {}; state.rendering = false; - state.suspended = false; num_renderpass_images = 0; } diff --git a/src/video_core/renderer_vulkan/vk_scheduler.h b/src/video_core/renderer_vulkan/vk_scheduler.h index f6a26b5557..1ebd80db2b 100644 --- a/src/video_core/renderer_vulkan/vk_scheduler.h +++ b/src/video_core/renderer_vulkan/vk_scheduler.h @@ -67,7 +67,7 @@ public: /// Requests the current execution context to be able to execute operations only allowed outside /// of a renderpass. - void RequestOutsideRenderPassOperationContext(bool allow_suspend = false); + void RequestOutsideRenderPassOperationContext(); /// Returns true when a render pass is currently active in the scheduler state. bool IsRenderPassActive() const { @@ -254,7 +254,6 @@ private: VkExtent2D render_area = {0, 0}; GraphicsPipeline* graphics_pipeline = nullptr; bool rendering = false; - bool suspended = false; u32 num_color = 0; bool has_depth = false; bool has_stencil = false; @@ -276,6 +275,9 @@ private: void BeginRenderPassImpl(const Framebuffer* framebuffer, VkRenderPass renderpass, const VkClearValue* clear_values, u32 clear_value_count); + /// Begins a dynamic rendering pass, optionally realizing a deferred clear via load ops. + void BeginDynamicRendering(const Framebuffer* framebuffer, const DeferredClear* clear); + /// If a deferred clear is pending. void RealizeDeferredClear(); @@ -289,7 +291,7 @@ private: void EndPendingOperations(); - void RecordDynamicBegin(bool resuming, bool suspending); + void RecordDynamicBegin(const DeferredClear* clear); void EndRenderPass(); diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index 5e6b702e3b..6e7507ad3e 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp @@ -2760,7 +2760,8 @@ void Framebuffer::CreateFramebuffer(TextureCacheRuntime& runtime, } renderpass_key.samples = samples; const bool do_resolve_color = - samples != VK_SAMPLE_COUNT_1_BIT && num_colors > 0 && runtime.device.IsTiler(); + samples != VK_SAMPLE_COUNT_1_BIT && num_colors > 0 && runtime.device.IsTiler() && + !runtime.device.IsKhrDynamicRenderingSupported(); renderpass_key.resolve_color = do_resolve_color; discard_msaa_color =