From 4fbdc133dd864ac752c69810ac79a8d4a8986f48 Mon Sep 17 00:00:00 2001 From: CamilleLaVey Date: Fri, 10 Jul 2026 00:27:01 -0400 Subject: [PATCH] [vulkan] Add resume/supend bits on renderpass --- .../renderer_vulkan/vk_buffer_cache.cpp | 12 +- .../renderer_vulkan/vk_scheduler.cpp | 173 +++++++++++------- src/video_core/renderer_vulkan/vk_scheduler.h | 9 +- 3 files changed, 124 insertions(+), 70 deletions(-) diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp index 4402550af9..8884535f1c 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(); + scheduler.RequestOutsideRenderPassOperationContext(true); 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(); + scheduler.RequestOutsideRenderPassOperationContext(true); 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(); + scheduler.RequestOutsideRenderPassOperationContext(true); 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(); + scheduler.RequestOutsideRenderPassOperationContext(true); 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(); + scheduler.RequestOutsideRenderPassOperationContext(true); 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(); + scheduler.RequestOutsideRenderPassOperationContext(true); scheduler.Record([buffer = *ret](vk::CommandBuffer cmdbuf) { cmdbuf.FillBuffer(buffer, 0, VK_WHOLE_SIZE, 0); }); diff --git a/src/video_core/renderer_vulkan/vk_scheduler.cpp b/src/video_core/renderer_vulkan/vk_scheduler.cpp index 5a40c28f42..af769faf35 100644 --- a/src/video_core/renderer_vulkan/vk_scheduler.cpp +++ b/src/video_core/renderer_vulkan/vk_scheduler.cpp @@ -107,7 +107,12 @@ void Scheduler::BeginRenderPassImpl(const Framebuffer* framebuffer, 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 = @@ -116,58 +121,7 @@ void Scheduler::BeginRenderPassImpl(const Framebuffer* framebuffer, VkRenderPass GPU::Logging::GPULogger::GetInstance().LogRenderPassBegin(render_pass_info); } - const u32 num_color = framebuffer->NumColorAttachments(); - const bool has_depth = framebuffer->HasAspectDepthBit(); - const bool has_stencil = framebuffer->HasAspectStencilBit(); - const VkImageView depth_view = framebuffer->DepthAttachment(); - const u32 layers = framebuffer->NumLayers(); - std::array color_infos{}; - for (u32 index = 0; index < num_color; ++index) { - color_infos[index] = VkRenderingAttachmentInfo{ - .sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO, - .pNext = nullptr, - .imageView = color_views[index], - .imageLayout = VK_IMAGE_LAYOUT_GENERAL, - .resolveMode = VK_RESOLVE_MODE_NONE, - .resolveImageView = VK_NULL_HANDLE, - .resolveImageLayout = VK_IMAGE_LAYOUT_UNDEFINED, - .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR, - .storeOp = VK_ATTACHMENT_STORE_OP_STORE, - .clearValue = {.color = {.float32 = {1.0f, 0.0f, 1.0f, 1.0f}}}, - }; - } - const VkRenderingAttachmentInfo depth_info{ - .sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO, - .pNext = nullptr, - .imageView = depth_view, - .imageLayout = VK_IMAGE_LAYOUT_GENERAL, - .resolveMode = VK_RESOLVE_MODE_NONE, - .resolveImageView = VK_NULL_HANDLE, - .resolveImageLayout = VK_IMAGE_LAYOUT_UNDEFINED, - .loadOp = VK_ATTACHMENT_LOAD_OP_LOAD, - .storeOp = VK_ATTACHMENT_STORE_OP_STORE, - .clearValue = {}, - }; - Record([color_infos, depth_info, num_color, has_depth, has_stencil, layers, - render_area](vk::CommandBuffer cmdbuf) { - const VkRenderingInfo rendering_info{ - .sType = VK_STRUCTURE_TYPE_RENDERING_INFO, - .pNext = nullptr, - .flags = 0, - .renderArea = - { - .offset = {.x = 0, .y = 0}, - .extent = render_area, - }, - .layerCount = layers, - .viewMask = 0, - .colorAttachmentCount = num_color, - .pColorAttachments = color_infos.data(), - .pDepthAttachment = has_depth ? &depth_info : nullptr, - .pStencilAttachment = has_stencil ? &depth_info : nullptr, - }; - cmdbuf.BeginRendering(rendering_info); - }); + RecordDynamicBegin(false, true); num_renderpass_images = framebuffer->NumImages(); renderpass_images = framebuffer->Images(); renderpass_image_ranges = framebuffer->ImageRanges(); @@ -281,9 +235,16 @@ void Scheduler::RequestRenderpass(const Framebuffer* framebuffer) { attachment_views[index] = color_views[index]; } attachment_views[8] = framebuffer->DepthAttachment(); - if (state.rendering && attachment_views == state.attachment_views && - render_area.width == state.render_area.width && - render_area.height == state.render_area.height) { + 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; return; } EndRenderPass(); @@ -302,7 +263,16 @@ void Scheduler::RequestRenderpass(const Framebuffer* framebuffer) { BeginRenderPassImpl(framebuffer, renderpass, nullptr, 0); } -void Scheduler::RequestOutsideRenderPassOperationContext() { +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; + } EndRenderPass(); } @@ -466,6 +436,69 @@ void Scheduler::InvalidateState() { state_tracker.InvalidateCommandBufferState(); } +void Scheduler::RecordDynamicBegin(bool resuming, bool suspending) { + 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) { + std::array color_infos{}; + for (u32 index = 0; index < num_color; ++index) { + color_infos[index] = VkRenderingAttachmentInfo{ + .sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO, + .pNext = nullptr, + .imageView = views[index], + .imageLayout = VK_IMAGE_LAYOUT_GENERAL, + .resolveMode = VK_RESOLVE_MODE_NONE, + .resolveImageView = VK_NULL_HANDLE, + .resolveImageLayout = VK_IMAGE_LAYOUT_UNDEFINED, + .loadOp = VK_ATTACHMENT_LOAD_OP_LOAD, + .storeOp = VK_ATTACHMENT_STORE_OP_STORE, + .clearValue = {}, + }; + } + const VkRenderingAttachmentInfo depth_info{ + .sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO, + .pNext = nullptr, + .imageView = views[8], + .imageLayout = VK_IMAGE_LAYOUT_GENERAL, + .resolveMode = VK_RESOLVE_MODE_NONE, + .resolveImageView = VK_NULL_HANDLE, + .resolveImageLayout = VK_IMAGE_LAYOUT_UNDEFINED, + .loadOp = VK_ATTACHMENT_LOAD_OP_LOAD, + .storeOp = VK_ATTACHMENT_STORE_OP_STORE, + .clearValue = {}, + }; + const VkRenderingInfo rendering_info{ + .sType = VK_STRUCTURE_TYPE_RENDERING_INFO, + .pNext = nullptr, + .flags = flags, + .renderArea = + { + .offset = {.x = 0, .y = 0}, + .extent = render_area, + }, + .layerCount = layers, + .viewMask = 0, + .colorAttachmentCount = num_color, + .pColorAttachments = color_infos.data(), + .pDepthAttachment = has_depth ? &depth_info : nullptr, + .pStencilAttachment = has_stencil ? &depth_info : nullptr, + }; + cmdbuf.BeginRendering(rendering_info); + }); +} + void Scheduler::EndPendingOperations() { query_cache->CounterReset(VideoCommon::QueryType::ZPassPixelCount64); EndRenderPass(); @@ -478,16 +511,29 @@ void Scheduler::EndRenderPass() return; } - query_cache->CounterClose(VideoCommon::QueryType::StreamingByteCount); + 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(); + // 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); + + if (dynamic) { + Record([](vk::CommandBuffer cmdbuf) { cmdbuf.EndRendering(); }); + state.suspended = true; + } } - query_cache->CounterEnable(VideoCommon::QueryType::ZPassPixelCount64, false); - query_cache->NotifySegment(false); + if (dynamic && state.suspended) { + RecordDynamicBegin(true, false); + } Record([num_images = num_renderpass_images, images = renderpass_images, @@ -555,6 +601,7 @@ 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 7f44fb22ec..f6a26b5557 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(); + void RequestOutsideRenderPassOperationContext(bool allow_suspend = false); /// Returns true when a render pass is currently active in the scheduler state. bool IsRenderPassActive() const { @@ -254,6 +254,11 @@ 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; + u32 layer_count = 1; bool is_rescaling = false; bool rescaling_defined = false; bool needs_state_enable_refresh = false; @@ -284,6 +289,8 @@ private: void EndPendingOperations(); + void RecordDynamicBegin(bool resuming, bool suspending); + void EndRenderPass(); void AcquireNewChunk();