Create a unique command pool per render pass (#37965)
This ensures that the command pool is not accessed from multiple threads
at the same time. This fixes the validation errors:
```
Check failed: false. Error[337425955][UNASSIGNED-Threading-MultipleThreads] : Validation Error: [ UNASSIGNED-Threading-MultipleThreads ] Object 0: handle = 0x59ffe0000000003d, type = VK_OBJECT_TYPE_COMMAND_POOL; | MessageID = 0x141cb623 | THREADING ERROR : vkFreeCommandBuffers(): object of type VkCommandPool is simultaneously used in thread 471586061488 and thread 471275924656'
```
diff --git a/impeller/renderer/backend/vulkan/command_buffer_vk.cc b/impeller/renderer/backend/vulkan/command_buffer_vk.cc
index 6e6096a..98f1e86 100644
--- a/impeller/renderer/backend/vulkan/command_buffer_vk.cc
+++ b/impeller/renderer/backend/vulkan/command_buffer_vk.cc
@@ -20,15 +20,15 @@
std::shared_ptr<CommandBufferVK> CommandBufferVK::Create(
const std::weak_ptr<const Context>& context_arg,
- vk::Device device,
- vk::CommandPool command_pool) {
+ vk::Device device) {
if (auto context = context_arg.lock()) {
- auto queue =
- reinterpret_cast<const ContextVK*>(context.get())->GetGraphicsQueue();
- auto fenced_command_buffer =
- std::make_shared<FencedCommandBufferVK>(device, queue, command_pool);
- return std::make_shared<CommandBufferVK>(context, device, command_pool,
- fenced_command_buffer);
+ auto context_vk = reinterpret_cast<const ContextVK*>(context.get());
+ auto queue = context_vk->GetGraphicsQueue();
+ auto command_pool = context_vk->CreateGraphicsCommandPool();
+ auto fenced_command_buffer = std::make_shared<FencedCommandBufferVK>(
+ device, queue, command_pool->Get());
+ return std::make_shared<CommandBufferVK>(
+ context, device, std::move(command_pool), fenced_command_buffer);
} else {
return nullptr;
}
@@ -37,11 +37,11 @@
CommandBufferVK::CommandBufferVK(
std::weak_ptr<const Context> context,
vk::Device device,
- vk::CommandPool command_pool,
+ std::unique_ptr<CommandPoolVK> command_pool,
std::shared_ptr<FencedCommandBufferVK> command_buffer)
: CommandBuffer(std::move(context)),
device_(device),
- command_pool_(command_pool),
+ command_pool_(std::move(command_pool)),
fenced_command_buffer_(std::move(command_buffer)) {
is_valid_ = true;
}
diff --git a/impeller/renderer/backend/vulkan/command_buffer_vk.h b/impeller/renderer/backend/vulkan/command_buffer_vk.h
index 941c110..74be5d9 100644
--- a/impeller/renderer/backend/vulkan/command_buffer_vk.h
+++ b/impeller/renderer/backend/vulkan/command_buffer_vk.h
@@ -5,6 +5,7 @@
#pragma once
#include "flutter/fml/macros.h"
+#include "impeller/renderer/backend/vulkan/command_pool_vk.h"
#include "impeller/renderer/backend/vulkan/fenced_command_buffer_vk.h"
#include "impeller/renderer/backend/vulkan/surface_producer_vk.h"
#include "impeller/renderer/backend/vulkan/vk.h"
@@ -16,12 +17,11 @@
public:
static std::shared_ptr<CommandBufferVK> Create(
const std::weak_ptr<const Context>& context,
- vk::Device device,
- vk::CommandPool command_pool);
+ vk::Device device);
CommandBufferVK(std::weak_ptr<const Context> context,
vk::Device device,
- vk::CommandPool command_pool,
+ std::unique_ptr<CommandPoolVK> command_pool,
std::shared_ptr<FencedCommandBufferVK> command_buffer);
// |CommandBuffer|
@@ -31,7 +31,7 @@
friend class ContextVK;
vk::Device device_;
- vk::CommandPool command_pool_;
+ std::unique_ptr<CommandPoolVK> command_pool_;
vk::UniqueRenderPass render_pass_;
std::shared_ptr<FencedCommandBufferVK> fenced_command_buffer_;
bool is_valid_ = false;
diff --git a/impeller/renderer/backend/vulkan/context_vk.cc b/impeller/renderer/backend/vulkan/context_vk.cc
index 6a9ceca..db5574c 100644
--- a/impeller/renderer/backend/vulkan/context_vk.cc
+++ b/impeller/renderer/backend/vulkan/context_vk.cc
@@ -398,6 +398,7 @@
auto graphics_queue =
PickQueue(physical_device.value(), vk::QueueFlagBits::eGraphics);
+ graphics_queue_idx_ = graphics_queue->index;
auto transfer_queue =
PickQueue(physical_device.value(), vk::QueueFlagBits::eTransfer);
auto compute_queue =
@@ -491,8 +492,6 @@
device_->getQueue(compute_queue->family, compute_queue->index);
transfer_queue_ =
device_->getQueue(transfer_queue->family, transfer_queue->index);
- graphics_command_pool_ =
- CommandPoolVK::Create(*device_, graphics_queue->index);
is_valid_ = true;
}
@@ -525,8 +524,7 @@
}
std::shared_ptr<CommandBuffer> ContextVK::CreateCommandBuffer() const {
- return CommandBufferVK::Create(weak_from_this(), *device_,
- graphics_command_pool_->Get());
+ return CommandBufferVK::Create(weak_from_this(), *device_);
}
vk::Instance ContextVK::GetInstance() const {
@@ -605,4 +603,8 @@
return graphics_queue_;
}
+std::unique_ptr<CommandPoolVK> ContextVK::CreateGraphicsCommandPool() const {
+ return CommandPoolVK::Create(*device_, graphics_queue_idx_);
+}
+
} // namespace impeller
diff --git a/impeller/renderer/backend/vulkan/context_vk.h b/impeller/renderer/backend/vulkan/context_vk.h
index 207d5ee..4ed7ddf 100644
--- a/impeller/renderer/backend/vulkan/context_vk.h
+++ b/impeller/renderer/backend/vulkan/context_vk.h
@@ -94,6 +94,8 @@
vk::Queue GetGraphicsQueue() const;
+ std::unique_ptr<CommandPoolVK> CreateGraphicsCommandPool() const;
+
private:
std::shared_ptr<fml::ConcurrentTaskRunner> worker_task_runner_;
vk::UniqueInstance instance_;
@@ -104,6 +106,7 @@
std::shared_ptr<ShaderLibraryVK> shader_library_;
std::shared_ptr<SamplerLibraryVK> sampler_library_;
std::shared_ptr<PipelineLibraryVK> pipeline_library_;
+ uint32_t graphics_queue_idx_;
vk::Queue graphics_queue_;
vk::Queue compute_queue_;
vk::Queue transfer_queue_;
@@ -111,7 +114,6 @@
vk::UniqueSurfaceKHR surface_;
vk::Format surface_format_;
std::unique_ptr<SwapchainVK> swapchain_;
- std::unique_ptr<CommandPoolVK> graphics_command_pool_;
std::unique_ptr<SurfaceProducerVK> surface_producer_;
std::shared_ptr<WorkQueue> work_queue_;
bool is_valid_ = false;
diff --git a/impeller/renderer/backend/vulkan/fenced_command_buffer_vk.cc b/impeller/renderer/backend/vulkan/fenced_command_buffer_vk.cc
index 895c0f6..4ebda5e 100644
--- a/impeller/renderer/backend/vulkan/fenced_command_buffer_vk.cc
+++ b/impeller/renderer/backend/vulkan/fenced_command_buffer_vk.cc
@@ -50,8 +50,9 @@
FencedCommandBufferVK::~FencedCommandBufferVK() {
if (!submitted_) {
- VALIDATION_LOG
+ FML_LOG(WARNING)
<< "FencedCommandBufferVK is being destroyed without being submitted.";
+ children_.push_back(command_buffer_);
}
device_.freeCommandBuffers(command_pool_, children_);
}
diff --git a/impeller/renderer/backend/vulkan/render_pass_vk.cc b/impeller/renderer/backend/vulkan/render_pass_vk.cc
index 7006dd2..5c3e398 100644
--- a/impeller/renderer/backend/vulkan/render_pass_vk.cc
+++ b/impeller/renderer/backend/vulkan/render_pass_vk.cc
@@ -346,7 +346,9 @@
}
std::array<vk::CopyDescriptorSet, 0> copies;
- device_.updateDescriptorSets(writes, copies);
+ if (!writes.empty()) {
+ device_.updateDescriptorSets(writes, copies);
+ }
return true;
}