[Impeller] Add external synchronization to Vulkan queues access. (#40848)
Fixes https://github.com/flutter/flutter/issues/123883
diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter
index 6377aad..4217faa 100644
--- a/ci/licenses_golden/licenses_flutter
+++ b/ci/licenses_golden/licenses_flutter
@@ -1492,6 +1492,8 @@
ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/pipeline_library_vk.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/pipeline_vk.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/pipeline_vk.h + ../../../flutter/LICENSE
+ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/queue_vk.cc + ../../../flutter/LICENSE
+ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/queue_vk.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/render_pass_vk.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/render_pass_vk.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/sampler_library_vk.cc + ../../../flutter/LICENSE
@@ -4069,6 +4071,8 @@
FILE: ../../../flutter/impeller/renderer/backend/vulkan/pipeline_library_vk.h
FILE: ../../../flutter/impeller/renderer/backend/vulkan/pipeline_vk.cc
FILE: ../../../flutter/impeller/renderer/backend/vulkan/pipeline_vk.h
+FILE: ../../../flutter/impeller/renderer/backend/vulkan/queue_vk.cc
+FILE: ../../../flutter/impeller/renderer/backend/vulkan/queue_vk.h
FILE: ../../../flutter/impeller/renderer/backend/vulkan/render_pass_vk.cc
FILE: ../../../flutter/impeller/renderer/backend/vulkan/render_pass_vk.h
FILE: ../../../flutter/impeller/renderer/backend/vulkan/sampler_library_vk.cc
diff --git a/impeller/renderer/backend/vulkan/BUILD.gn b/impeller/renderer/backend/vulkan/BUILD.gn
index 2e9a091..303d5f6 100644
--- a/impeller/renderer/backend/vulkan/BUILD.gn
+++ b/impeller/renderer/backend/vulkan/BUILD.gn
@@ -38,6 +38,8 @@
"pipeline_library_vk.h",
"pipeline_vk.cc",
"pipeline_vk.h",
+ "queue_vk.cc",
+ "queue_vk.h",
"render_pass_vk.cc",
"render_pass_vk.h",
"sampler_library_vk.cc",
diff --git a/impeller/renderer/backend/vulkan/command_encoder_vk.cc b/impeller/renderer/backend/vulkan/command_encoder_vk.cc
index 5539708..35e0da7 100644
--- a/impeller/renderer/backend/vulkan/command_encoder_vk.cc
+++ b/impeller/renderer/backend/vulkan/command_encoder_vk.cc
@@ -82,12 +82,12 @@
};
CommandEncoderVK::CommandEncoderVK(vk::Device device,
- vk::Queue queue,
+ const std::shared_ptr<QueueVK>& queue,
const std::shared_ptr<CommandPoolVK>& pool,
std::shared_ptr<FenceWaiterVK> fence_waiter)
: fence_waiter_(std::move(fence_waiter)),
tracked_objects_(std::make_shared<TrackedObjectsVK>(device, pool)) {
- if (!fence_waiter_ || !tracked_objects_->IsValid()) {
+ if (!fence_waiter_ || !tracked_objects_->IsValid() || !queue) {
return;
}
vk::CommandBufferBeginInfo begin_info;
@@ -131,7 +131,7 @@
vk::SubmitInfo submit_info;
std::vector<vk::CommandBuffer> buffers = {command_buffer};
submit_info.setCommandBuffers(buffers);
- if (queue_.submit(submit_info, *fence) != vk::Result::eSuccess) {
+ if (queue_->Submit(submit_info, *fence) != vk::Result::eSuccess) {
return false;
}
@@ -207,9 +207,6 @@
if (auto command_buffer = GetCommandBuffer()) {
command_buffer.beginDebugUtilsLabelEXT(label_info);
}
- if (queue_) {
- queue_.beginDebugUtilsLabelEXT(label_info);
- }
}
void CommandEncoderVK::PopDebugGroup() const {
@@ -219,9 +216,6 @@
if (auto command_buffer = GetCommandBuffer()) {
command_buffer.endDebugUtilsLabelEXT();
}
- if (queue_) {
- queue_.endDebugUtilsLabelEXT();
- }
}
void CommandEncoderVK::InsertDebugMarker(const char* label) const {
@@ -234,7 +228,7 @@
command_buffer.insertDebugUtilsLabelEXT(label_info);
}
if (queue_) {
- queue_.insertDebugUtilsLabelEXT(label_info);
+ queue_->InsertDebugMarker(label);
}
}
diff --git a/impeller/renderer/backend/vulkan/command_encoder_vk.h b/impeller/renderer/backend/vulkan/command_encoder_vk.h
index 8db33b5..9e79fb3 100644
--- a/impeller/renderer/backend/vulkan/command_encoder_vk.h
+++ b/impeller/renderer/backend/vulkan/command_encoder_vk.h
@@ -10,6 +10,7 @@
#include "flutter/fml/macros.h"
#include "impeller/renderer/backend/vulkan/command_pool_vk.h"
#include "impeller/renderer/backend/vulkan/descriptor_pool_vk.h"
+#include "impeller/renderer/backend/vulkan/queue_vk.h"
#include "impeller/renderer/backend/vulkan/shared_object_vk.h"
#include "impeller/renderer/backend/vulkan/vk.h"
@@ -53,14 +54,13 @@
friend class ContextVK;
vk::Device device_ = {};
- vk::Queue queue_ = {};
-
+ std::shared_ptr<QueueVK> queue_;
std::shared_ptr<FenceWaiterVK> fence_waiter_;
std::shared_ptr<TrackedObjectsVK> tracked_objects_;
bool is_valid_ = false;
CommandEncoderVK(vk::Device device,
- vk::Queue queue,
+ const std::shared_ptr<QueueVK>& queue,
const std::shared_ptr<CommandPoolVK>& pool,
std::shared_ptr<FenceWaiterVK> fence_waiter);
diff --git a/impeller/renderer/backend/vulkan/command_pool_vk.cc b/impeller/renderer/backend/vulkan/command_pool_vk.cc
index 5ed2ed4..0ccac93 100644
--- a/impeller/renderer/backend/vulkan/command_pool_vk.cc
+++ b/impeller/renderer/backend/vulkan/command_pool_vk.cc
@@ -70,7 +70,7 @@
: owner_id_(std::this_thread::get_id()) {
vk::CommandPoolCreateInfo pool_info;
- pool_info.queueFamilyIndex = context->GetGraphicsQueueInfo().index;
+ pool_info.queueFamilyIndex = context->GetGraphicsQueue()->GetIndex().family;
pool_info.flags = vk::CommandPoolCreateFlagBits::eTransient;
auto pool = context->GetDevice().createCommandPoolUnique(pool_info);
if (pool.result != vk::Result::eSuccess) {
diff --git a/impeller/renderer/backend/vulkan/context_vk.cc b/impeller/renderer/backend/vulkan/context_vk.cc
index 1497e47..e0d65d0 100644
--- a/impeller/renderer/backend/vulkan/context_vk.cc
+++ b/impeller/renderer/backend/vulkan/context_vk.cc
@@ -50,7 +50,7 @@
}
static std::vector<vk::DeviceQueueCreateInfo> GetQueueCreateInfos(
- std::initializer_list<QueueVK> queues) {
+ std::initializer_list<QueueIndexVK> queues) {
std::map<size_t /* family */, size_t /* index */> family_index_map;
for (const auto& queue : queues) {
family_index_map[queue.family] = 0;
@@ -72,8 +72,8 @@
return infos;
}
-static std::optional<QueueVK> PickQueue(const vk::PhysicalDevice& device,
- vk::QueueFlagBits flags) {
+static std::optional<QueueIndexVK> PickQueue(const vk::PhysicalDevice& device,
+ vk::QueueFlagBits flags) {
// This can be modified to ensure that dedicated queues are returned for each
// queue type depending on support.
const auto families = device.getQueueFamilyProperties();
@@ -81,7 +81,7 @@
if (!(families[i].queueFlags & flags)) {
continue;
}
- return QueueVK{.family = i, .index = 0};
+ return QueueIndexVK{.family = i, .index = 0};
}
return std::nullopt;
}
@@ -332,6 +332,19 @@
}
//----------------------------------------------------------------------------
+ /// Fetch the queues.
+ ///
+ QueuesVK queues(device.value.get(), //
+ graphics_queue.value(), //
+ compute_queue.value(), //
+ transfer_queue.value() //
+ );
+ if (!queues.IsValid()) {
+ VALIDATION_LOG << "Could not fetch device queues.";
+ return;
+ }
+
+ //----------------------------------------------------------------------------
/// All done!
///
instance_ = std::move(instance.value);
@@ -342,15 +355,7 @@
shader_library_ = std::move(shader_library);
sampler_library_ = std::move(sampler_library);
pipeline_library_ = std::move(pipeline_library);
- graphics_queue_ =
- device_->getQueue(graphics_queue->family, graphics_queue->index);
- compute_queue_ =
- device_->getQueue(compute_queue->family, compute_queue->index);
- transfer_queue_ =
- device_->getQueue(transfer_queue->family, transfer_queue->index);
- graphics_queue_info_ = graphics_queue.value();
- compute_queue_info_ = compute_queue.value();
- transfer_queue_info_ = transfer_queue.value();
+ queues_ = std::move(queues);
device_capabilities_ = std::move(caps);
fence_waiter_ = std::move(fence_waiter);
is_valid_ = true;
@@ -360,11 +365,6 @@
/// messengers have had a chance to be setup.
///
SetDebugName(device_.get(), device_.get(), "ImpellerDevice");
- SetDebugName(device_.get(), graphics_queue_, "ImpellerGraphicsQ");
- SetDebugName(device_.get(), compute_queue_, "ImpellerComputeQ");
- if (transfer_queue_ != graphics_queue_) {
- SetDebugName(device_.get(), transfer_queue_, "ImpellerTransferQ");
- }
}
bool ContextVK::IsValid() const {
@@ -451,12 +451,8 @@
return device_capabilities_;
}
-vk::Queue ContextVK::GetGraphicsQueue() const {
- return graphics_queue_;
-}
-
-QueueVK ContextVK::GetGraphicsQueueInfo() const {
- return graphics_queue_info_;
+const std::shared_ptr<QueueVK>& ContextVK::GetGraphicsQueue() const {
+ return queues_.graphics_queue;
}
vk::PhysicalDevice ContextVK::GetPhysicalDevice() const {
@@ -474,10 +470,10 @@
return nullptr;
}
auto encoder = std::unique_ptr<CommandEncoderVK>(new CommandEncoderVK(
- *device_, //
- graphics_queue_, //
- tls_pool, //
- fence_waiter_ //
+ *device_, //
+ queues_.graphics_queue, //
+ tls_pool, //
+ fence_waiter_ //
));
if (!encoder->IsValid()) {
return nullptr;
diff --git a/impeller/renderer/backend/vulkan/context_vk.h b/impeller/renderer/backend/vulkan/context_vk.h
index 5c930ec..b7dcc82 100644
--- a/impeller/renderer/backend/vulkan/context_vk.h
+++ b/impeller/renderer/backend/vulkan/context_vk.h
@@ -13,6 +13,7 @@
#include "impeller/base/backend_cast.h"
#include "impeller/core/formats.h"
#include "impeller/renderer/backend/vulkan/pipeline_library_vk.h"
+#include "impeller/renderer/backend/vulkan/queue_vk.h"
#include "impeller/renderer/backend/vulkan/sampler_library_vk.h"
#include "impeller/renderer/backend/vulkan/shader_library_vk.h"
#include "impeller/renderer/backend/vulkan/swapchain_vk.h"
@@ -110,9 +111,7 @@
vk::UniqueSurfaceKHR CreateAndroidSurface(ANativeWindow* window) const;
#endif // FML_OS_ANDROID
- vk::Queue GetGraphicsQueue() const;
-
- QueueVK GetGraphicsQueueInfo() const;
+ const std::shared_ptr<QueueVK>& GetGraphicsQueue() const;
vk::PhysicalDevice GetPhysicalDevice() const;
@@ -127,12 +126,7 @@
std::shared_ptr<ShaderLibraryVK> shader_library_;
std::shared_ptr<SamplerLibraryVK> sampler_library_;
std::shared_ptr<PipelineLibraryVK> pipeline_library_;
- vk::Queue graphics_queue_ = {};
- vk::Queue compute_queue_ = {};
- vk::Queue transfer_queue_ = {};
- QueueVK graphics_queue_info_ = {};
- QueueVK compute_queue_info_ = {};
- QueueVK transfer_queue_info_ = {};
+ QueuesVK queues_;
std::shared_ptr<SwapchainVK> swapchain_;
std::shared_ptr<const Capabilities> device_capabilities_;
std::shared_ptr<FenceWaiterVK> fence_waiter_;
diff --git a/impeller/renderer/backend/vulkan/fence_waiter_vk.cc b/impeller/renderer/backend/vulkan/fence_waiter_vk.cc
index 06c4c09..d3b027c 100644
--- a/impeller/renderer/backend/vulkan/fence_waiter_vk.cc
+++ b/impeller/renderer/backend/vulkan/fence_waiter_vk.cc
@@ -7,6 +7,7 @@
#include <chrono>
#include "flutter/fml/thread.h"
+#include "flutter/fml/trace_event.h"
namespace impeller {
@@ -78,6 +79,7 @@
if (terminate_) {
return std::nullopt;
}
+ TRACE_EVENT0("impeller", "TrimFences");
std::vector<vk::Fence> fences;
fences.reserve(wait_set_.size());
for (auto it = wait_set_.begin(); it != wait_set_.end();) {
diff --git a/impeller/renderer/backend/vulkan/queue_vk.cc b/impeller/renderer/backend/vulkan/queue_vk.cc
new file mode 100644
index 0000000..a0c8234
--- /dev/null
+++ b/impeller/renderer/backend/vulkan/queue_vk.cc
@@ -0,0 +1,74 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "impeller/renderer/backend/vulkan/queue_vk.h"
+
+#include "impeller/renderer/backend/vulkan/context_vk.h"
+
+namespace impeller {
+
+QueueVK::QueueVK(QueueIndexVK index, vk::Queue queue)
+ : index_(index), queue_(queue) {}
+
+QueueVK::~QueueVK() = default;
+
+const QueueIndexVK& QueueVK::GetIndex() const {
+ return index_;
+}
+
+vk::Result QueueVK::Submit(const vk::SubmitInfo& submit_info,
+ const vk::Fence& fence) const {
+ Lock lock(queue_mutex_);
+ return queue_.submit(submit_info, fence);
+}
+
+void QueueVK::InsertDebugMarker(const char* label) const {
+ if (!HasValidationLayers()) {
+ return;
+ }
+ vk::DebugUtilsLabelEXT label_info;
+ label_info.pLabelName = label;
+ Lock lock(queue_mutex_);
+ queue_.insertDebugUtilsLabelEXT(label_info);
+}
+
+QueuesVK::QueuesVK() = default;
+
+QueuesVK::QueuesVK(const vk::Device& device,
+ QueueIndexVK graphics,
+ QueueIndexVK compute,
+ QueueIndexVK transfer) {
+ auto vk_graphics = device.getQueue(graphics.family, graphics.index);
+ auto vk_compute = device.getQueue(compute.family, compute.index);
+ auto vk_transfer = device.getQueue(transfer.family, transfer.index);
+
+ // Always setup the graphics queue.
+ graphics_queue = std::make_shared<QueueVK>(graphics, vk_graphics);
+ ContextVK::SetDebugName(device, vk_graphics, "ImpellerGraphicsQ");
+
+ // Setup the compute queue if its different from the graphics queue.
+ if (compute == graphics) {
+ compute_queue = graphics_queue;
+ } else {
+ compute_queue = std::make_shared<QueueVK>(compute, vk_compute);
+ ContextVK::SetDebugName(device, vk_compute, "ImpellerComputeQ");
+ }
+
+ // Setup the transfer queue if its different from the graphics or compute
+ // queues.
+ if (transfer == graphics) {
+ transfer_queue = graphics_queue;
+ } else if (transfer == compute) {
+ transfer_queue = compute_queue;
+ } else {
+ transfer_queue = std::make_shared<QueueVK>(transfer, vk_transfer);
+ ContextVK::SetDebugName(device, vk_transfer, "ImpellerTransferQ");
+ }
+}
+
+bool QueuesVK::IsValid() const {
+ return graphics_queue && compute_queue && transfer_queue;
+}
+
+} // namespace impeller
diff --git a/impeller/renderer/backend/vulkan/queue_vk.h b/impeller/renderer/backend/vulkan/queue_vk.h
new file mode 100644
index 0000000..6ba3b91
--- /dev/null
+++ b/impeller/renderer/backend/vulkan/queue_vk.h
@@ -0,0 +1,72 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#pragma once
+
+#include <memory>
+
+#include "flutter/fml/macros.h"
+#include "impeller/base/thread.h"
+#include "impeller/renderer/backend/vulkan/vk.h"
+
+namespace impeller {
+
+struct QueueIndexVK {
+ size_t family = 0;
+ size_t index = 0;
+
+ constexpr bool operator==(const QueueIndexVK& other) const {
+ return family == other.family && index == other.index;
+ }
+};
+
+//------------------------------------------------------------------------------
+/// @brief A thread safe object that can be used to access device queues.
+/// If multiple objects are created with the same underlying queue,
+/// then the external synchronization guarantees of Vulkan queues
+/// cannot be met. So care must be taken the same device queue
+/// doesn't form the basis of multiple `QueueVK`s.
+///
+class QueueVK {
+ public:
+ QueueVK(QueueIndexVK index, vk::Queue queue);
+
+ ~QueueVK();
+
+ const QueueIndexVK& GetIndex() const;
+
+ vk::Result Submit(const vk::SubmitInfo& submit_info,
+ const vk::Fence& fence) const;
+
+ void InsertDebugMarker(const char* label) const;
+
+ private:
+ mutable Mutex queue_mutex_;
+
+ const QueueIndexVK index_;
+ const vk::Queue queue_ IPLR_GUARDED_BY(queue_mutex_);
+
+ FML_DISALLOW_COPY_AND_ASSIGN(QueueVK);
+};
+
+//------------------------------------------------------------------------------
+/// @brief The collection of queues used by the context. The queues may all
+/// be the same.
+///
+struct QueuesVK {
+ std::shared_ptr<QueueVK> graphics_queue;
+ std::shared_ptr<QueueVK> compute_queue;
+ std::shared_ptr<QueueVK> transfer_queue;
+
+ QueuesVK();
+
+ QueuesVK(const vk::Device& device,
+ QueueIndexVK graphics,
+ QueueIndexVK compute,
+ QueueIndexVK transfer);
+
+ bool IsValid() const;
+};
+
+} // namespace impeller
diff --git a/impeller/renderer/backend/vulkan/swapchain_impl_vk.cc b/impeller/renderer/backend/vulkan/swapchain_impl_vk.cc
index 027c19d..9e4deb5 100644
--- a/impeller/renderer/backend/vulkan/swapchain_impl_vk.cc
+++ b/impeller/renderer/backend/vulkan/swapchain_impl_vk.cc
@@ -418,7 +418,7 @@
submit_info.setWaitSemaphores(*sync->render_ready);
submit_info.setSignalSemaphores(*sync->present_ready);
auto result =
- context.GetGraphicsQueue().submit(submit_info, *sync->acquire);
+ context.GetGraphicsQueue()->Submit(submit_info, *sync->acquire);
if (result != vk::Result::eSuccess) {
VALIDATION_LOG << "Could not wait on render semaphore: "
<< vk::to_string(result);
diff --git a/impeller/renderer/backend/vulkan/vk.h b/impeller/renderer/backend/vulkan/vk.h
index 788b41b..3eef9a3 100644
--- a/impeller/renderer/backend/vulkan/vk.h
+++ b/impeller/renderer/backend/vulkan/vk.h
@@ -69,12 +69,3 @@
static_assert(VK_HEADER_VERSION >= 215, "Vulkan headers must not be too old.");
#include "flutter/flutter_vma/flutter_vma.h"
-
-namespace impeller {
-
-struct QueueVK {
- size_t family = 0;
- size_t index = 0;
-};
-
-} // namespace impeller