From 075090569f3b91ba956b958dbc1f32e574d2603d Mon Sep 17 00:00:00 2001 From: GPUCode Date: Thu, 29 Sep 2022 19:51:25 +0300 Subject: [PATCH] renderer_vulkan: Handle scheduler switches properly --- .../renderer_vulkan/vk_pipeline_cache.cpp | 10 +++++++++- src/video_core/renderer_vulkan/vk_pipeline_cache.h | 5 +++-- src/video_core/renderer_vulkan/vk_rasterizer.cpp | 4 +--- .../renderer_vulkan/vk_task_scheduler.cpp | 14 +------------- src/video_core/renderer_vulkan/vk_task_scheduler.h | 7 ++++--- 5 files changed, 18 insertions(+), 22 deletions(-) diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index 207eab4f0..69da9797b 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp @@ -180,6 +180,13 @@ PipelineCache::~PipelineCache() { void PipelineCache::BindPipeline(const PipelineInfo& info) { ApplyDynamic(info); + // When texture downloads occur the runtime will flush the GPU and cause + // a scheduler slot switch behind our back. This might invalidate any + // cached descriptor sets/require pipeline rebinding. + if (timestamp != scheduler.GetHostFenceCounter()) { + MarkDirty(); + } + u64 shader_hash = 0; for (u32 i = 0; i < MAX_SHADER_STAGES; i++) { shader_hash = Common::HashCombine(shader_hash, shader_hashes[i]); @@ -303,9 +310,10 @@ void PipelineCache::SetScissor(s32 x, s32 y, u32 width, u32 height) { command_buffer.setScissor(0, vk::Rect2D{{x, y}, {width, height}}); } -void PipelineCache::MarkDescriptorSetsDirty() { +void PipelineCache::MarkDirty() { descriptor_dirty.fill(true); current_pipeline = VK_NULL_HANDLE; + timestamp = scheduler.GetHostFenceCounter(); } void PipelineCache::ApplyDynamic(const PipelineInfo& info) { diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.h b/src/video_core/renderer_vulkan/vk_pipeline_cache.h index da4a2a24a..46cd21be8 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.h +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.h @@ -195,8 +195,8 @@ public: /// Sets the scissor rectange to the provided values void SetScissor(s32 x, s32 y, u32 width, u32 height); - /// Marks all descriptor sets as dirty - void MarkDescriptorSetsDirty(); + /// Marks all cached pipeline cache state as dirty + void MarkDirty(); private: /// Binds a resource to the provided binding @@ -248,6 +248,7 @@ private: std::array update_data{}; std::array descriptor_dirty{}; std::array descriptor_sets; + u64 timestamp = 0; // Bound shader modules enum ProgramType : u32 { diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index c66a4c419..d958de7f6 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -784,8 +784,6 @@ bool RasterizerVulkan::Draw(bool accelerate, bool is_indexed) { // Enable scissor test to prevent drawing outside of the framebuffer region pipeline_cache.SetScissor(draw_rect.left, draw_rect.bottom, draw_rect.GetWidth(), draw_rect.GetHeight()); - //return true; - auto valid_surface = color_surface ? color_surface : depth_surface; const FramebufferInfo framebuffer_info = { .color = color_surface ? color_surface->alloc.image_view : VK_NULL_HANDLE, @@ -834,6 +832,7 @@ bool RasterizerVulkan::Draw(bool accelerate, bool is_indexed) { if (accelerate) { succeeded = AccelerateDrawBatchInternal(is_indexed); } else { + pipeline_info.rasterization.topology.Assign(Pica::PipelineRegs::TriangleTopology::List); pipeline_cache.UseTrivialVertexShader(); pipeline_cache.UseTrivialGeometryShader(); pipeline_cache.BindPipeline(pipeline_info); @@ -1625,7 +1624,6 @@ void RasterizerVulkan::FlushBuffers() { index_buffer.Flush(); texture_buffer.Flush(); texture_lf_buffer.Flush(); - pipeline_cache.MarkDescriptorSetsDirty(); } void RasterizerVulkan::SetShader() { diff --git a/src/video_core/renderer_vulkan/vk_task_scheduler.cpp b/src/video_core/renderer_vulkan/vk_task_scheduler.cpp index ee60984a1..08b3f7b96 100644 --- a/src/video_core/renderer_vulkan/vk_task_scheduler.cpp +++ b/src/video_core/renderer_vulkan/vk_task_scheduler.cpp @@ -119,25 +119,13 @@ void TaskScheduler::Synchronize(u32 slot) { LOG_ERROR(Render_Vulkan, "Waiting for fence counter {} failed!", command.fence_counter); UNREACHABLE(); } - - completed_fence_counter = command.fence_counter; } + completed_fence_counter = command.fence_counter; device.resetFences(command.fence); device.resetDescriptorPool(command.descriptor_pool); } -void TaskScheduler::WaitFence(u32 counter) { - for (u32 i = 0; i < SCHEDULER_COMMAND_COUNT; i++) { - if (commands[i].fence_counter == counter) { - return Synchronize(i); - } - } - - LOG_CRITICAL(Render_Vulkan,"Invalid fence counter {}!", counter); - UNREACHABLE(); -} - void TaskScheduler::Submit(SubmitMode mode) { const auto& command = commands[current_command]; command.render_command_buffer.end(); diff --git a/src/video_core/renderer_vulkan/vk_task_scheduler.h b/src/video_core/renderer_vulkan/vk_task_scheduler.h index 1fde47f65..6cfb7cead 100644 --- a/src/video_core/renderer_vulkan/vk_task_scheduler.h +++ b/src/video_core/renderer_vulkan/vk_task_scheduler.h @@ -32,9 +32,6 @@ public: /// Blocks the host until the current command completes execution void Synchronize(u32 slot); - /// Waits for the fence counter to be reached by the GPU - void WaitFence(u32 counter); - /// Submits the current command to the graphics queue void Submit(SubmitMode mode); @@ -59,6 +56,10 @@ public: return current_command; } + u64 GetHostFenceCounter() const { + return next_fence_counter - 1; + } + vk::Semaphore GetImageAcquiredSemaphore() const { return commands[current_command].image_acquired; }