diff --git a/impeller/renderer/backend/vulkan/context_vk.cc b/impeller/renderer/backend/vulkan/context_vk.cc index 8204f5965e39f..d57018ffdc523 100644 --- a/impeller/renderer/backend/vulkan/context_vk.cc +++ b/impeller/renderer/backend/vulkan/context_vk.cc @@ -4,6 +4,8 @@ #include "impeller/renderer/backend/vulkan/context_vk.h" +#include "fml/concurrent_message_loop.h" + #ifdef FML_OS_ANDROID #include #include @@ -128,6 +130,12 @@ void ContextVK::Setup(Settings settings) { return; } + queue_submit_thread_ = std::make_unique("QueueSubmitThread"); + queue_submit_thread_->GetTaskRunner()->PostTask([]() { + // submitKHR is extremely cheap and mostly blocks on an internal fence. + fml::RequestAffinity(fml::CpuAffinity::kEfficiency); + }); + raster_message_loop_ = fml::ConcurrentMessageLoop::Create( std::min(4u, std::thread::hardware_concurrency())); raster_message_loop_->PostTaskToAllWorkers([]() { @@ -486,6 +494,10 @@ const vk::Device& ContextVK::GetDevice() const { return device_holder_->device.get(); } +const fml::RefPtr ContextVK::GetQueueSubmitRunner() const { + return queue_submit_thread_->GetTaskRunner(); +} + const std::shared_ptr ContextVK::GetConcurrentWorkerTaskRunner() const { return raster_message_loop_->GetTaskRunner(); @@ -500,6 +512,7 @@ void ContextVK::Shutdown() { fence_waiter_.reset(); resource_manager_.reset(); + queue_submit_thread_->Join(); raster_message_loop_->Terminate(); } diff --git a/impeller/renderer/backend/vulkan/context_vk.h b/impeller/renderer/backend/vulkan/context_vk.h index 0febc8b03da15..b4cc241c7e475 100644 --- a/impeller/renderer/backend/vulkan/context_vk.h +++ b/impeller/renderer/backend/vulkan/context_vk.h @@ -10,6 +10,7 @@ #include "flutter/fml/macros.h" #include "flutter/fml/mapping.h" #include "flutter/fml/unique_fd.h" +#include "fml/thread.h" #include "impeller/base/backend_cast.h" #include "impeller/core/formats.h" #include "impeller/renderer/backend/vulkan/command_pool_vk.h" @@ -133,6 +134,18 @@ class ContextVK final : public Context, const std::shared_ptr GetConcurrentWorkerTaskRunner() const; + /// @brief A single-threaded task runner that should only be used for + /// submitKHR. + /// + /// SubmitKHR will block until all previously submitted command buffers have + /// been scheduled. If there are no platform views in the scene (excluding + /// texture backed platform views). Then it is safe for SwapchainImpl::Present + /// to return before submit has completed. To do so, we offload the submit + /// command to a specialized single threaded task runner. The single thread + /// ensures that we do not queue up too much work and that the submissions + /// proceed in order. + const fml::RefPtr GetQueueSubmitRunner() const; + std::shared_ptr CreateSurfaceContext(); const std::shared_ptr& GetGraphicsQueue() const; @@ -176,6 +189,7 @@ class ContextVK final : public Context, std::shared_ptr command_pool_recycler_; std::string device_name_; std::shared_ptr raster_message_loop_; + std::unique_ptr queue_submit_thread_; std::shared_ptr gpu_tracer_; bool sync_presentation_ = false; diff --git a/impeller/renderer/backend/vulkan/gpu_tracer_vk.cc b/impeller/renderer/backend/vulkan/gpu_tracer_vk.cc index ea738ad269ce4..921677408697c 100644 --- a/impeller/renderer/backend/vulkan/gpu_tracer_vk.cc +++ b/impeller/renderer/backend/vulkan/gpu_tracer_vk.cc @@ -16,7 +16,7 @@ namespace impeller { -static constexpr uint32_t kPoolSize = 64u; +static constexpr uint32_t kPoolSize = 1024u; GPUTracerVK::GPUTracerVK(const std::shared_ptr& device_holder) : device_holder_(device_holder) { diff --git a/impeller/renderer/backend/vulkan/swapchain_impl_vk.cc b/impeller/renderer/backend/vulkan/swapchain_impl_vk.cc index eb089e44ec45d..3063451f570ad 100644 --- a/impeller/renderer/backend/vulkan/swapchain_impl_vk.cc +++ b/impeller/renderer/backend/vulkan/swapchain_impl_vk.cc @@ -522,7 +522,7 @@ bool SwapchainImplVK::Present(const std::shared_ptr& image, if (context.GetSyncPresentation()) { task(); } else { - context.GetConcurrentWorkerTaskRunner()->PostTask(task); + context.GetQueueSubmitRunner()->PostTask(task); } return true; } diff --git a/impeller/renderer/context.h b/impeller/renderer/context.h index 3d0cb9d97ad6e..45cb62cbaeb78 100644 --- a/impeller/renderer/context.h +++ b/impeller/renderer/context.h @@ -175,7 +175,9 @@ class Context { /// /// This is required for correct rendering on Android when using /// the hybrid composition mode. This has no effect on other - /// backends. + /// backends. This is analogous to the check for isMainThread in + /// surface_mtl.mm to block presentation on scheduling of all + /// pending work. virtual void SetSyncPresentation(bool value) {} //----------------------------------------------------------------------------