diff --git a/impeller/renderer/backend/vulkan/BUILD.gn b/impeller/renderer/backend/vulkan/BUILD.gn index 6db2d4df534ea..3ba6c17ccdc53 100644 --- a/impeller/renderer/backend/vulkan/BUILD.gn +++ b/impeller/renderer/backend/vulkan/BUILD.gn @@ -18,10 +18,14 @@ impeller_component("vulkan") { "command_pool_vk.h", "context_vk.cc", "context_vk.h", + "deletion_queue_vk.cc", + "deletion_queue_vk.h", "descriptor_pool_vk.cc", "descriptor_pool_vk.h", "device_buffer_vk.cc", "device_buffer_vk.h", + "fenced_command_buffer_vk.cc", + "fenced_command_buffer_vk.h", "formats_vk.cc", "formats_vk.h", "pipeline_library_vk.cc", diff --git a/impeller/renderer/backend/vulkan/command_buffer_vk.cc b/impeller/renderer/backend/vulkan/command_buffer_vk.cc index 6db5c36c2c391..6e6096a8412c6 100644 --- a/impeller/renderer/backend/vulkan/command_buffer_vk.cc +++ b/impeller/renderer/backend/vulkan/command_buffer_vk.cc @@ -4,11 +4,13 @@ #include "impeller/renderer/backend/vulkan/command_buffer_vk.h" +#include #include #include "flutter/fml/logging.h" #include "impeller/base/validation.h" #include "impeller/renderer/backend/vulkan/context_vk.h" +#include "impeller/renderer/backend/vulkan/fenced_command_buffer_vk.h" #include "impeller/renderer/backend/vulkan/formats_vk.h" #include "impeller/renderer/backend/vulkan/render_pass_vk.h" #include "impeller/renderer/command_buffer.h" @@ -17,37 +19,30 @@ namespace impeller { std::shared_ptr CommandBufferVK::Create( - const std::weak_ptr& context, + const std::weak_ptr& context_arg, vk::Device device, - vk::CommandPool command_pool, - SurfaceProducerVK* surface_producer) { - vk::CommandBufferAllocateInfo allocate_info; - allocate_info.setLevel(vk::CommandBufferLevel::ePrimary); - allocate_info.setCommandBufferCount(1); - allocate_info.setCommandPool(command_pool); - - auto res = device.allocateCommandBuffersUnique(allocate_info); - if (res.result != vk::Result::eSuccess) { - VALIDATION_LOG << "Failed to allocate command buffer: " - << vk::to_string(res.result); + vk::CommandPool command_pool) { + if (auto context = context_arg.lock()) { + auto queue = + reinterpret_cast(context.get())->GetGraphicsQueue(); + auto fenced_command_buffer = + std::make_shared(device, queue, command_pool); + return std::make_shared(context, device, command_pool, + fenced_command_buffer); + } else { return nullptr; } - - vk::UniqueCommandBuffer cmd = std::move(res.value[0]); - return std::make_shared(context, device, surface_producer, - command_pool, std::move(cmd)); } -CommandBufferVK::CommandBufferVK(std::weak_ptr context, - vk::Device device, - SurfaceProducerVK* surface_producer, - vk::CommandPool command_pool, - vk::UniqueCommandBuffer command_buffer) +CommandBufferVK::CommandBufferVK( + std::weak_ptr context, + vk::Device device, + vk::CommandPool command_pool, + std::shared_ptr command_buffer) : CommandBuffer(std::move(context)), device_(device), command_pool_(command_pool), - command_buffer_(std::move(command_buffer)), - surface_producer_(surface_producer) { + fenced_command_buffer_(std::move(command_buffer)) { is_valid_ = true; } @@ -56,7 +51,7 @@ CommandBufferVK::~CommandBufferVK() = default; void CommandBufferVK::SetLabel(const std::string& label) const { if (auto context = context_.lock()) { reinterpret_cast(context.get()) - ->SetDebugName(*command_buffer_, label); + ->SetDebugName(fenced_command_buffer_->Get(), label); } } @@ -65,16 +60,12 @@ bool CommandBufferVK::IsValid() const { } bool CommandBufferVK::OnSubmitCommands(CompletionCallback callback) { - // TODO(https://github.com/flutter/flutter/issues/112387) - // This needs to be the place where the command buffer, renderpass, - // and the various descriptor sets in use by the command buffer are - // disposed of. - + bool submit = fenced_command_buffer_->Submit(); if (callback) { - callback(CommandBuffer::Status::kCompleted); + callback(submit ? CommandBuffer::Status::kCompleted + : CommandBuffer::Status::kError); } - - return true; + return submit; } std::shared_ptr CommandBufferVK::OnCreateRenderPass( @@ -115,17 +106,16 @@ std::shared_ptr CommandBufferVK::OnCreateRenderPass( render_pass_create.setSubpassCount(1); render_pass_create.setPSubpasses(&subpass_desc); - auto render_pass_create_res = - device_.createRenderPassUnique(render_pass_create); + auto render_pass_create_res = device_.createRenderPass(render_pass_create); if (render_pass_create_res.result != vk::Result::eSuccess) { VALIDATION_LOG << "Failed to create render pass: " << vk::to_string(render_pass_create_res.result); return nullptr; } - return std::make_shared( - context_, device_, std::move(target), std::move(command_buffer_), - std::move(render_pass_create_res.value), surface_producer_); + vk::RenderPass render_pass = render_pass_create_res.value; + return std::make_shared(context_, device_, std::move(target), + fenced_command_buffer_, render_pass); } std::shared_ptr CommandBufferVK::OnCreateBlitPass() const { diff --git a/impeller/renderer/backend/vulkan/command_buffer_vk.h b/impeller/renderer/backend/vulkan/command_buffer_vk.h index 2b004071d683e..941c110c6c35e 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/fenced_command_buffer_vk.h" #include "impeller/renderer/backend/vulkan/surface_producer_vk.h" #include "impeller/renderer/backend/vulkan/vk.h" #include "impeller/renderer/command_buffer.h" @@ -16,14 +17,12 @@ class CommandBufferVK final : public CommandBuffer { static std::shared_ptr Create( const std::weak_ptr& context, vk::Device device, - vk::CommandPool command_pool, - SurfaceProducerVK* surface_producer); + vk::CommandPool command_pool); CommandBufferVK(std::weak_ptr context, vk::Device device, - SurfaceProducerVK* surface_producer, vk::CommandPool command_pool, - vk::UniqueCommandBuffer command_buffer); + std::shared_ptr command_buffer); // |CommandBuffer| ~CommandBufferVK() override; @@ -33,9 +32,8 @@ class CommandBufferVK final : public CommandBuffer { vk::Device device_; vk::CommandPool command_pool_; - vk::UniqueCommandBuffer command_buffer_; vk::UniqueRenderPass render_pass_; - SurfaceProducerVK* surface_producer_; + std::shared_ptr fenced_command_buffer_; bool is_valid_ = false; // |CommandBuffer| diff --git a/impeller/renderer/backend/vulkan/context_vk.cc b/impeller/renderer/backend/vulkan/context_vk.cc index e2002204cd13c..8b12838b01dbb 100644 --- a/impeller/renderer/backend/vulkan/context_vk.cc +++ b/impeller/renderer/backend/vulkan/context_vk.cc @@ -21,6 +21,7 @@ #include "impeller/renderer/backend/vulkan/allocator_vk.h" #include "impeller/renderer/backend/vulkan/capabilities_vk.h" #include "impeller/renderer/backend/vulkan/command_buffer_vk.h" +#include "impeller/renderer/backend/vulkan/deletion_queue_vk.h" #include "impeller/renderer/backend/vulkan/formats_vk.h" #include "impeller/renderer/backend/vulkan/surface_producer_vk.h" #include "impeller/renderer/backend/vulkan/swapchain_details_vk.h" @@ -491,7 +492,7 @@ ContextVK::ContextVK( device_->getQueue(transfer_queue->family, transfer_queue->index); graphics_command_pool_ = CommandPoolVK::Create(*device_, graphics_queue->index); - descriptor_pool_ = std::make_shared(*device_); + is_valid_ = true; } @@ -524,8 +525,7 @@ std::shared_ptr ContextVK::GetWorkQueue() const { std::shared_ptr ContextVK::CreateCommandBuffer() const { return CommandBufferVK::Create(weak_from_this(), *device_, - graphics_command_pool_->Get(), - surface_producer_.get()); + graphics_command_pool_->Get()); } vk::Instance ContextVK::GetInstance() const { @@ -588,12 +588,16 @@ bool ContextVK::SupportsOffscreenMSAA() const { return true; } -std::shared_ptr ContextVK::GetDescriptorPool() const { - return descriptor_pool_; +std::unique_ptr ContextVK::CreateDescriptorPool() const { + return std::make_unique(*device_); } PixelFormat ContextVK::GetColorAttachmentPixelFormat() const { return ToPixelFormat(surface_format_); } +vk::Queue ContextVK::GetGraphicsQueue() const { + return graphics_queue_; +} + } // namespace impeller diff --git a/impeller/renderer/backend/vulkan/context_vk.h b/impeller/renderer/backend/vulkan/context_vk.h index 44806548cd5af..eaefae0621837 100644 --- a/impeller/renderer/backend/vulkan/context_vk.h +++ b/impeller/renderer/backend/vulkan/context_vk.h @@ -11,6 +11,7 @@ #include "flutter/fml/mapping.h" #include "impeller/base/backend_cast.h" #include "impeller/renderer/backend/vulkan/command_pool_vk.h" +#include "impeller/renderer/backend/vulkan/deletion_queue_vk.h" #include "impeller/renderer/backend/vulkan/descriptor_pool_vk.h" #include "impeller/renderer/backend/vulkan/pipeline_library_vk.h" #include "impeller/renderer/backend/vulkan/sampler_library_vk.h" @@ -85,12 +86,14 @@ class ContextVK final : public Context, public BackendCast { std::unique_ptr AcquireSurface(size_t current_frame); - std::shared_ptr GetDescriptorPool() const; + std::unique_ptr CreateDescriptorPool() const; #ifdef FML_OS_ANDROID vk::UniqueSurfaceKHR CreateAndroidSurface(ANativeWindow* window) const; #endif // FML_OS_ANDROID + vk::Queue GetGraphicsQueue() const; + private: std::shared_ptr worker_task_runner_; vk::UniqueInstance instance_; @@ -111,7 +114,6 @@ class ContextVK final : public Context, public BackendCast { std::unique_ptr graphics_command_pool_; std::unique_ptr surface_producer_; std::shared_ptr work_queue_; - std::shared_ptr descriptor_pool_; bool is_valid_ = false; ContextVK( diff --git a/impeller/renderer/backend/vulkan/deletion_queue_vk.cc b/impeller/renderer/backend/vulkan/deletion_queue_vk.cc new file mode 100644 index 0000000000000..2c202e7ed81f2 --- /dev/null +++ b/impeller/renderer/backend/vulkan/deletion_queue_vk.cc @@ -0,0 +1,27 @@ +// 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/deletion_queue_vk.h" + +namespace impeller { + +DeletionQueueVK::DeletionQueueVK() = default; + +DeletionQueueVK::~DeletionQueueVK() { + Flush(); +} + +void DeletionQueueVK::Flush() { + for (auto it = deletors_.rbegin(); it != deletors_.rend(); ++it) { + (*it)(); + } + + deletors_.clear(); +} + +void DeletionQueueVK::Push(Deletor&& deletor) { + deletors_.push_back(std::move(deletor)); +} + +} // namespace impeller diff --git a/impeller/renderer/backend/vulkan/deletion_queue_vk.h b/impeller/renderer/backend/vulkan/deletion_queue_vk.h new file mode 100644 index 0000000000000..427844f752680 --- /dev/null +++ b/impeller/renderer/backend/vulkan/deletion_queue_vk.h @@ -0,0 +1,32 @@ +// 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 +#include + +#include "flutter/fml/macros.h" + +namespace impeller { + +class DeletionQueueVK { + public: + using Deletor = std::function; + + explicit DeletionQueueVK(); + + ~DeletionQueueVK(); + + void Flush(); + + void Push(Deletor&& deletor); + + private: + std::deque deletors_; + + FML_DISALLOW_COPY_AND_ASSIGN(DeletionQueueVK); +}; + +} // namespace impeller diff --git a/impeller/renderer/backend/vulkan/descriptor_pool_vk.cc b/impeller/renderer/backend/vulkan/descriptor_pool_vk.cc index b4e44282f3b06..47e2cfe444103 100644 --- a/impeller/renderer/backend/vulkan/descriptor_pool_vk.cc +++ b/impeller/renderer/backend/vulkan/descriptor_pool_vk.cc @@ -10,7 +10,7 @@ namespace impeller { -DescriptorPoolVK::DescriptorPoolVK(vk::Device device) : device_(device) { +DescriptorPoolVK::DescriptorPoolVK(vk::Device device) { constexpr size_t kPoolSize = 1024; std::vector pool_sizes = { @@ -48,10 +48,6 @@ vk::DescriptorPool DescriptorPoolVK::GetPool() { return pool_; } -DescriptorPoolVK::~DescriptorPoolVK() { - if (is_valid_) { - device_.destroyDescriptorPool(pool_); - } -} +DescriptorPoolVK::~DescriptorPoolVK() = default; } // namespace impeller diff --git a/impeller/renderer/backend/vulkan/descriptor_pool_vk.h b/impeller/renderer/backend/vulkan/descriptor_pool_vk.h index c4d33d9289a05..e7ff29ee9215b 100644 --- a/impeller/renderer/backend/vulkan/descriptor_pool_vk.h +++ b/impeller/renderer/backend/vulkan/descriptor_pool_vk.h @@ -22,7 +22,6 @@ class DescriptorPoolVK { vk::DescriptorPool GetPool(); private: - vk::Device device_; vk::DescriptorPool pool_; 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 new file mode 100644 index 0000000000000..895c0f62b6ab2 --- /dev/null +++ b/impeller/renderer/backend/vulkan/fenced_command_buffer_vk.cc @@ -0,0 +1,100 @@ +// 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/fenced_command_buffer_vk.h" + +#include + +#include "impeller/base/validation.h" +#include "impeller/renderer/backend/vulkan/deletion_queue_vk.h" + +namespace impeller { + +static vk::CommandBuffer CreateCommandBuffer(vk::Device device, + vk::CommandPool pool) { + vk::CommandBufferAllocateInfo allocate_info; + allocate_info.setLevel(vk::CommandBufferLevel::ePrimary); + allocate_info.setCommandBufferCount(1); + allocate_info.setCommandPool(pool); + + auto res = device.allocateCommandBuffers(allocate_info); + if (res.result != vk::Result::eSuccess) { + VALIDATION_LOG << "Failed to allocate command buffer: " + << vk::to_string(res.result); + return nullptr; + } + + return res.value[0]; +} + +FencedCommandBufferVK::FencedCommandBufferVK(vk::Device device, + vk::Queue queue, + vk::CommandPool command_pool) + : device_(device), + queue_(queue), + command_pool_(command_pool), + deletion_queue_(std::make_unique()) { + command_buffer_ = CreateCommandBuffer(device_, command_pool_); +} + +vk::CommandBuffer FencedCommandBufferVK::Get() const { + return command_buffer_; +} + +vk::CommandBuffer FencedCommandBufferVK::GetSingleUseChild() { + auto child = CreateCommandBuffer(device_, command_pool_); + children_.push_back(child); + return child; +} + +FencedCommandBufferVK::~FencedCommandBufferVK() { + if (!submitted_) { + VALIDATION_LOG + << "FencedCommandBufferVK is being destroyed without being submitted."; + } + device_.freeCommandBuffers(command_pool_, children_); +} + +bool FencedCommandBufferVK::Submit() { + if (submitted_) { + VALIDATION_LOG << "Command buffer already submitted."; + return false; + } + + children_.push_back(command_buffer_); + + auto fence_res = device_.createFenceUnique(vk::FenceCreateInfo()); + if (fence_res.result != vk::Result::eSuccess) { + VALIDATION_LOG << "Failed to create fence: " + << vk::to_string(fence_res.result); + return false; + } + vk::UniqueFence fence = std::move(fence_res.value); + + vk::SubmitInfo submit_info; + submit_info.setCommandBuffers(children_); + auto res = queue_.submit(submit_info, *fence); + if (res != vk::Result::eSuccess) { + VALIDATION_LOG << "Failed to submit command buffer: " << vk::to_string(res); + return false; + } + + auto wait = device_.waitForFences(fence.get(), true, UINT64_MAX); + if (wait != vk::Result::eSuccess) { + VALIDATION_LOG << "Failed to wait for fence: " << vk::to_string(wait); + return false; + } + + // cleanup all the resources held by the command buffer and its children. + deletion_queue_->Flush(); + + submitted_ = true; + return true; +} + +DeletionQueueVK* FencedCommandBufferVK::GetDeletionQueue() const { + return deletion_queue_.get(); +} + +} // namespace impeller diff --git a/impeller/renderer/backend/vulkan/fenced_command_buffer_vk.h b/impeller/renderer/backend/vulkan/fenced_command_buffer_vk.h new file mode 100644 index 0000000000000..760d6f44d7e2f --- /dev/null +++ b/impeller/renderer/backend/vulkan/fenced_command_buffer_vk.h @@ -0,0 +1,44 @@ +// 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 + +#include "flutter/fml/macros.h" +#include "impeller/renderer/backend/vulkan/deletion_queue_vk.h" +#include "impeller/renderer/backend/vulkan/vk.h" + +namespace impeller { + +class FencedCommandBufferVK { + public: + FencedCommandBufferVK(vk::Device device, + vk::Queue queue, + vk::CommandPool command_pool); + + ~FencedCommandBufferVK(); + + vk::CommandBuffer Get() const; + + vk::CommandBuffer GetSingleUseChild(); + + // this is a blocking call that waits for the fence to be signaled. + bool Submit(); + + DeletionQueueVK* GetDeletionQueue() const; + + private: + vk::Device device_; + vk::Queue queue_; + vk::CommandPool command_pool_; + std::unique_ptr deletion_queue_; + vk::CommandBuffer command_buffer_; + std::vector children_; + bool submitted_ = false; + + FML_DISALLOW_COPY_AND_ASSIGN(FencedCommandBufferVK); +}; + +} // namespace impeller diff --git a/impeller/renderer/backend/vulkan/render_pass_vk.cc b/impeller/renderer/backend/vulkan/render_pass_vk.cc index 8ee31b70ea267..7006dd244bf2a 100644 --- a/impeller/renderer/backend/vulkan/render_pass_vk.cc +++ b/impeller/renderer/backend/vulkan/render_pass_vk.cc @@ -25,17 +25,16 @@ namespace impeller { static uint32_t color_flash = 0; -RenderPassVK::RenderPassVK(std::weak_ptr context, - vk::Device device, - const RenderTarget& target, - vk::UniqueCommandBuffer command_buffer, - vk::UniqueRenderPass render_pass, - SurfaceProducerVK* surface_producer) +RenderPassVK::RenderPassVK( + std::weak_ptr context, + vk::Device device, + const RenderTarget& target, + std::shared_ptr command_buffer, + vk::RenderPass render_pass) : RenderPass(std::move(context), target), device_(device), command_buffer_(std::move(command_buffer)), - render_pass_(std::move(render_pass)), - surface_producer_(surface_producer) { + render_pass_(render_pass) { is_valid_ = true; } @@ -60,7 +59,7 @@ bool RenderPassVK::OnEncodeCommands(const Context& context) const { } vk::CommandBufferBeginInfo begin_info; - auto res = command_buffer_->begin(begin_info); + auto res = command_buffer_->Get().begin(begin_info); if (res != vk::Result::eSuccess) { VALIDATION_LOG << "Failed to begin command buffer: " << vk::to_string(res); return false; @@ -70,19 +69,16 @@ bool RenderPassVK::OnEncodeCommands(const Context& context) const { const auto& depth0 = render_target.GetDepthAttachment(); const auto& stencil0 = render_target.GetStencilAttachment(); - auto& wrapped_texture = TextureVK::Cast(*color0.texture); - FML_CHECK(wrapped_texture.IsWrapped()); + auto& texture = TextureVK::Cast(*color0.texture); + vk::Framebuffer framebuffer = CreateFrameBuffer(texture); - auto tex_info = wrapped_texture.GetTextureInfo()->wrapped_texture; - // TODO (https://github.com/flutter/flutter/issues/112387) - // this frame buffer has to be destroyed when the command buffer is destroyed. - vk::Framebuffer framebuffer = CreateFrameBuffer(tex_info); - - const uint32_t frame_num = tex_info.frame_num; + command_buffer_->GetDeletionQueue()->Push( + [device = device_, fbo = framebuffer]() { + device.destroyFramebuffer(fbo); + }); // layout transition. - if (!TransitionImageLayout(frame_num, tex_info.swapchain_image->GetImage(), - vk::ImageLayout::eUndefined, + if (!TransitionImageLayout(texture.GetImage(), vk::ImageLayout::eUndefined, vk::ImageLayout::eColorAttachmentOptimal)) { return false; } @@ -91,18 +87,19 @@ bool RenderPassVK::OnEncodeCommands(const Context& context) const { clear_value.color = vk::ClearColorValue(std::array{0.0f, 0.0f, 0.0, 0.0f}); - const auto& size = tex_info.swapchain_image->GetSize(); + const auto& size = texture.GetTextureDescriptor().size; vk::Rect2D render_area = vk::Rect2D() .setOffset(vk::Offset2D(0, 0)) .setExtent(vk::Extent2D(size.width, size.height)); auto rp_begin_info = vk::RenderPassBeginInfo() - .setRenderPass(*render_pass_) + .setRenderPass(render_pass_) .setFramebuffer(framebuffer) .setRenderArea(render_area) .setClearValues(clear_value); - command_buffer_->beginRenderPass(rp_begin_info, vk::SubpassContents::eInline); + command_buffer_->Get().beginRenderPass(rp_begin_info, + vk::SubpassContents::eInline); const auto& transients_allocator = context.GetResourceAllocator(); @@ -120,53 +117,53 @@ bool RenderPassVK::OnEncodeCommands(const Context& context) const { continue; } - if (!EncodeCommand(frame_num, context, command)) { + if (!EncodeCommand(context, command)) { return false; } } - if (!TransitionImageLayout(frame_num, tex_info.swapchain_image->GetImage(), - vk::ImageLayout::eUndefined, + if (!TransitionImageLayout(texture.GetImage(), vk::ImageLayout::eUndefined, vk::ImageLayout::eColorAttachmentOptimal)) { return false; } - command_buffer_->endRenderPass(); + command_buffer_->Get().endRenderPass(); - return const_cast(this)->EndCommandBuffer(frame_num); + return const_cast(this)->EndCommandBuffer(); } -bool RenderPassVK::EndCommandBuffer(uint32_t frame_num) { +bool RenderPassVK::EndCommandBuffer() { if (command_buffer_) { - auto res = command_buffer_->end(); + auto res = command_buffer_->Get().end(); if (res != vk::Result::eSuccess) { VALIDATION_LOG << "Failed to end command buffer: " << vk::to_string(res); return false; } - surface_producer_->StashRP(frame_num, std::move(render_pass_)); + const auto& context_vk = GetContextVK(); + command_buffer_->GetDeletionQueue()->Push( + [device = device_, render_pass = render_pass_]() { + device.destroyRenderPass(render_pass); + }); - return surface_producer_->QueueCommandBuffer(frame_num, - std::move(command_buffer_)); + return true; } return false; } -bool RenderPassVK::EncodeCommand(uint32_t frame_num, - const Context& context, +bool RenderPassVK::EncodeCommand(const Context& context, const Command& command) const { SetViewportAndScissor(command); auto& pipeline_vk = PipelineVK::Cast(*command.pipeline); PipelineCreateInfoVK* pipeline_create_info = pipeline_vk.GetCreateInfo(); - if (!AllocateAndBindDescriptorSets(frame_num, context, command, - pipeline_create_info)) { + if (!AllocateAndBindDescriptorSets(context, command, pipeline_create_info)) { return false; } - command_buffer_->bindPipeline(vk::PipelineBindPoint::eGraphics, - pipeline_create_info->GetVKPipeline()); + command_buffer_->Get().bindPipeline(vk::PipelineBindPoint::eGraphics, + pipeline_create_info->GetVKPipeline()); auto vertex_buffer_view = command.GetVertexBuffer(); auto index_buffer_view = command.index_buffer; @@ -192,24 +189,24 @@ bool RenderPassVK::EncodeCommand(uint32_t frame_num, DeviceBufferVK::Cast(*vertex_buffer).GetVKBufferHandle(); vk::Buffer vertex_buffers[] = {vertex_buffer_handle}; vk::DeviceSize vertex_buffer_offsets[] = {vertex_buffer_view.range.offset}; - command_buffer_->bindVertexBuffers(0, 1, vertex_buffers, - vertex_buffer_offsets); + command_buffer_->Get().bindVertexBuffers(0, 1, vertex_buffers, + vertex_buffer_offsets); // index buffer auto index_buffer_handle = DeviceBufferVK::Cast(*index_buffer).GetVKBufferHandle(); - command_buffer_->bindIndexBuffer(index_buffer_handle, - index_buffer_view.range.offset, - ToVKIndexType(command.index_type)); + command_buffer_->Get().bindIndexBuffer(index_buffer_handle, + index_buffer_view.range.offset, + ToVKIndexType(command.index_type)); // execute draw - command_buffer_->drawIndexed(command.index_count, command.instance_count, 0, - 0, 0); + command_buffer_->Get().drawIndexed(command.index_count, + command.instance_count, 0, 0, 0); return true; } bool RenderPassVK::AllocateAndBindDescriptorSets( - uint32_t frame_num, + const Context& context, const Command& command, PipelineCreateInfoVK* pipeline_create_info) const { @@ -217,8 +214,13 @@ bool RenderPassVK::AllocateAndBindDescriptorSets( vk::PipelineLayout pipeline_layout = pipeline_create_info->GetPipelineLayout(); - const auto& context_vk = ContextVK::Cast(context); - const auto& pool = context_vk.GetDescriptorPool(); + const auto& context_vk = GetContextVK(); + const auto& pool = context_vk.CreateDescriptorPool(); + + command_buffer_->GetDeletionQueue()->Push( + [pool = pool->GetPool(), device = device_]() { + device.destroyDescriptorPool(pool); + }); vk::DescriptorSetAllocateInfo alloc_info; std::array dsls = { @@ -236,26 +238,23 @@ bool RenderPassVK::AllocateAndBindDescriptorSets( } auto desc_sets = desc_sets_res.value; - bool update_vertex_descriptors = - UpdateDescriptorSets(frame_num, "vertex_bindings", - command.vertex_bindings, allocator, desc_sets[0]); + bool update_vertex_descriptors = UpdateDescriptorSets( + "vertex_bindings", command.vertex_bindings, allocator, desc_sets[0]); if (!update_vertex_descriptors) { return false; } - bool update_frag_descriptors = - UpdateDescriptorSets(frame_num, "fragment_bindings", - command.fragment_bindings, allocator, desc_sets[0]); + bool update_frag_descriptors = UpdateDescriptorSets( + "fragment_bindings", command.fragment_bindings, allocator, desc_sets[0]); if (!update_frag_descriptors) { return false; } - command_buffer_->bindDescriptorSets(vk::PipelineBindPoint::eGraphics, - pipeline_layout, 0, desc_sets, nullptr); + command_buffer_->Get().bindDescriptorSets( + vk::PipelineBindPoint::eGraphics, pipeline_layout, 0, desc_sets, nullptr); return true; } -bool RenderPassVK::UpdateDescriptorSets(uint32_t frame_num, - const char* label, +bool RenderPassVK::UpdateDescriptorSets(const char* label, const Bindings& bindings, Allocator& allocator, vk::DescriptorSet desc_set) const { @@ -316,15 +315,15 @@ bool RenderPassVK::UpdateDescriptorSets(uint32_t frame_num, const SampledImageSlot& slot = bindings.sampled_images.at(index); - if (!TransitionImageLayout(frame_num, texture_vk.GetImage(), + if (!TransitionImageLayout(texture_vk.GetImage(), vk::ImageLayout::eUndefined, vk::ImageLayout::eTransferDstOptimal)) { return false; } - CopyBufferToImage(frame_num, texture_vk); + CopyBufferToImage(texture_vk); - if (!TransitionImageLayout(frame_num, texture_vk.GetImage(), + if (!TransitionImageLayout(texture_vk.GetImage(), vk::ImageLayout::eTransferDstOptimal, vk::ImageLayout::eShaderReadOnlyOptimal)) { return false; @@ -362,7 +361,7 @@ void RenderPassVK::SetViewportAndScissor(const Command& command) const { .setY(vp.rect.size.height) .setMinDepth(0.0f) .setMaxDepth(1.0f); - command_buffer_->setViewport(0, 1, &viewport); + command_buffer_->Get().setViewport(0, 1, &viewport); // scissor const auto& sc = @@ -371,15 +370,15 @@ void RenderPassVK::SetViewportAndScissor(const Command& command) const { vk::Rect2D() .setOffset(vk::Offset2D(sc.origin.x, sc.origin.y)) .setExtent(vk::Extent2D(sc.size.width, sc.size.height)); - command_buffer_->setScissor(0, 1, &scissor); + command_buffer_->Get().setScissor(0, 1, &scissor); } vk::Framebuffer RenderPassVK::CreateFrameBuffer( - const WrappedTextureInfoVK& wrapped_texture_info) const { - auto img_view = wrapped_texture_info.swapchain_image->GetImageView(); - auto size = wrapped_texture_info.swapchain_image->GetSize(); + const TextureVK& texture) const { + auto img_view = texture.GetImageView(); + auto size = texture.GetTextureDescriptor().size; vk::FramebufferCreateInfo fb_create_info = vk::FramebufferCreateInfo() - .setRenderPass(*render_pass_) + .setRenderPass(render_pass_) .setAttachmentCount(1) .setPAttachments(&img_view) .setWidth(size.width) @@ -390,26 +389,14 @@ vk::Framebuffer RenderPassVK::CreateFrameBuffer( return res.value; } -bool RenderPassVK::TransitionImageLayout(uint32_t frame_num, - vk::Image image, +bool RenderPassVK::TransitionImageLayout(vk::Image image, vk::ImageLayout layout_old, vk::ImageLayout layout_new) const { - auto pool = command_buffer_.getPool(); - vk::CommandBufferAllocateInfo alloc_info = - vk::CommandBufferAllocateInfo() - .setCommandPool(pool) - .setLevel(vk::CommandBufferLevel::ePrimary) - .setCommandBufferCount(1); - auto cmd_buf_res = device_.allocateCommandBuffersUnique(alloc_info); - if (cmd_buf_res.result != vk::Result::eSuccess) { - VALIDATION_LOG << "Failed to allocate command buffer: " - << vk::to_string(cmd_buf_res.result); - return false; - } - auto transition_cmd = std::move(cmd_buf_res.value[0]); + auto transition_cmd = command_buffer_->GetSingleUseChild(); vk::CommandBufferBeginInfo begin_info; - auto res = transition_cmd->begin(begin_info); + begin_info.setFlags(vk::CommandBufferUsageFlagBits::eOneTimeSubmit); + auto res = transition_cmd.begin(begin_info); if (res != vk::Result::eSuccess) { VALIDATION_LOG << "Failed to begin command buffer: " << vk::to_string(res); @@ -434,36 +421,21 @@ bool RenderPassVK::TransitionImageLayout(uint32_t frame_num, .setLevelCount(1) .setBaseArrayLayer(0) .setLayerCount(1)); - transition_cmd->pipelineBarrier(vk::PipelineStageFlagBits::eAllGraphics, - vk::PipelineStageFlagBits::eAllGraphics, {}, - nullptr, nullptr, barrier); + transition_cmd.pipelineBarrier(vk::PipelineStageFlagBits::eAllGraphics, + vk::PipelineStageFlagBits::eAllGraphics, {}, + nullptr, nullptr, barrier); - res = transition_cmd->end(); + res = transition_cmd.end(); if (res != vk::Result::eSuccess) { VALIDATION_LOG << "Failed to end command buffer: " << vk::to_string(res); return false; } - surface_producer_->QueueCommandBuffer(frame_num, std::move(transition_cmd)); return true; } -bool RenderPassVK::CopyBufferToImage(uint32_t frame_num, - const TextureVK& texture_vk) const { - auto pool = command_buffer_.getPool(); - vk::CommandBufferAllocateInfo alloc_info = - vk::CommandBufferAllocateInfo() - .setCommandPool(pool) - .setLevel(vk::CommandBufferLevel::ePrimary) - .setCommandBufferCount(1); - auto cmd_buf_res = device_.allocateCommandBuffersUnique(alloc_info); - if (cmd_buf_res.result != vk::Result::eSuccess) { - VALIDATION_LOG << "Failed to allocate command buffer: " - << vk::to_string(cmd_buf_res.result); - return false; - } - - auto copy_cmd = std::move(cmd_buf_res.value[0]); +bool RenderPassVK::CopyBufferToImage(const TextureVK& texture_vk) const { + auto copy_cmd = command_buffer_->GetSingleUseChild(); const auto& size = texture_vk.GetTextureDescriptor().size; @@ -483,25 +455,34 @@ bool RenderPassVK::CopyBufferToImage(uint32_t frame_num, .setImageExtent(vk::Extent3D(size.width, size.height, 1)); vk::CommandBufferBeginInfo begin_info; - auto res = copy_cmd->begin(begin_info); + begin_info.setFlags(vk::CommandBufferUsageFlagBits::eOneTimeSubmit); + auto res = copy_cmd.begin(begin_info); if (res != vk::Result::eSuccess) { VALIDATION_LOG << "Failed to begin command buffer: " << vk::to_string(res); return false; } - copy_cmd->copyBufferToImage(texture_vk.GetStagingBuffer(), - texture_vk.GetImage(), - vk::ImageLayout::eTransferDstOptimal, region); + copy_cmd.copyBufferToImage(texture_vk.GetStagingBuffer(), + texture_vk.GetImage(), + vk::ImageLayout::eTransferDstOptimal, region); - res = copy_cmd->end(); + res = copy_cmd.end(); if (res != vk::Result::eSuccess) { VALIDATION_LOG << "Failed to end command buffer: " << vk::to_string(res); return false; } - surface_producer_->QueueCommandBuffer(frame_num, std::move(copy_cmd)); return true; } +const ContextVK& RenderPassVK::GetContextVK() const { + if (auto context = context_.lock()) { + const auto& context_vk = ContextVK::Cast(*context); + return context_vk; + } + + FML_UNREACHABLE(); +} + } // namespace impeller diff --git a/impeller/renderer/backend/vulkan/render_pass_vk.h b/impeller/renderer/backend/vulkan/render_pass_vk.h index 9bf05412b5eee..811267e41021a 100644 --- a/impeller/renderer/backend/vulkan/render_pass_vk.h +++ b/impeller/renderer/backend/vulkan/render_pass_vk.h @@ -5,6 +5,8 @@ #pragma once #include "flutter/fml/macros.h" +#include "impeller/renderer/backend/vulkan/context_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/texture_vk.h" #include "impeller/renderer/backend/vulkan/vk.h" @@ -19,9 +21,8 @@ class RenderPassVK final : public RenderPass { RenderPassVK(std::weak_ptr context, vk::Device device, const RenderTarget& target, - vk::UniqueCommandBuffer command_buffer, - vk::UniqueRenderPass render_pass, - SurfaceProducerVK* surface_producer); + std::shared_ptr command_buffer, + vk::RenderPass render_pass); // |RenderPass| ~RenderPassVK() override; @@ -30,10 +31,8 @@ class RenderPassVK final : public RenderPass { friend class CommandBufferVK; vk::Device device_; - vk::UniqueCommandBuffer command_buffer_; - vk::UniqueRenderPass render_pass_; - SurfaceProducerVK* surface_producer_; - + std::shared_ptr command_buffer_; + vk::RenderPass render_pass_; std::string label_ = ""; bool is_valid_ = false; @@ -46,35 +45,31 @@ class RenderPassVK final : public RenderPass { // |RenderPass| bool OnEncodeCommands(const Context& context) const override; - bool EncodeCommand(uint32_t frame_num, - const Context& context, - const Command& command) const; + bool EncodeCommand(const Context& context, const Command& command) const; bool AllocateAndBindDescriptorSets( - uint32_t frame_num, const Context& context, const Command& command, PipelineCreateInfoVK* pipeline_create_info) const; - bool EndCommandBuffer(uint32_t frame_num); + bool EndCommandBuffer(); - bool UpdateDescriptorSets(uint32_t frame_num, - const char* label, + bool UpdateDescriptorSets(const char* label, const Bindings& bindings, Allocator& allocator, vk::DescriptorSet desc_set) const; void SetViewportAndScissor(const Command& command) const; - vk::Framebuffer CreateFrameBuffer( - const WrappedTextureInfoVK& wrapped_texture_info) const; + vk::Framebuffer CreateFrameBuffer(const TextureVK& texture) const; - bool TransitionImageLayout(uint32_t frame_num, - vk::Image image, + bool TransitionImageLayout(vk::Image image, vk::ImageLayout layout_old, vk::ImageLayout layout_new) const; - bool CopyBufferToImage(uint32_t frame_num, const TextureVK& texture_vk) const; + bool CopyBufferToImage(const TextureVK& texture_vk) const; + + const ContextVK& GetContextVK() const; FML_DISALLOW_COPY_AND_ASSIGN(RenderPassVK); }; diff --git a/impeller/renderer/backend/vulkan/surface_producer_vk.cc b/impeller/renderer/backend/vulkan/surface_producer_vk.cc index b3a0f7a0f79de..8bd94893753ee 100644 --- a/impeller/renderer/backend/vulkan/surface_producer_vk.cc +++ b/impeller/renderer/backend/vulkan/surface_producer_vk.cc @@ -133,12 +133,6 @@ bool SurfaceProducerVK::SetupSyncObjects() { return true; } -bool SurfaceProducerVK::QueueCommandBuffer(uint32_t frame_num, - vk::UniqueCommandBuffer buffer) { - command_buffers_[frame_num].push_back(std::move(buffer)); - return true; -} - bool SurfaceProducerVK::Submit(uint32_t frame_num) { auto& sync_objects = sync_objects_[frame_num]; vk::SubmitInfo submit_info; @@ -154,12 +148,6 @@ bool SurfaceProducerVK::Submit(uint32_t frame_num) { *sync_objects->render_finished_semaphore}; submit_info.setSignalSemaphores(signal_semaphores); - std::vector command_buffers = {}; - for (auto& buf : command_buffers_[frame_num]) { - command_buffers.push_back(*buf); - } - submit_info.setCommandBuffers(command_buffers); - auto graphics_submit_res = create_info_.graphics_queue.submit( {submit_info}, *sync_objects->in_flight_fence); if (graphics_submit_res != vk::Result::eSuccess) { @@ -199,13 +187,9 @@ bool SurfaceProducerVK::Present(size_t frame_num, uint32_t image_index) { auto present_res = create_info_.present_queue.presentKHR(present_info); if ((present_res != vk::Result::eSuccess) && (present_res != vk::Result::eSuboptimalKHR)) { - command_buffers_[frame_num].clear(); - stash_rp_[frame_num].clear(); return false; } - command_buffers_[frame_num].clear(); - stash_rp_[frame_num].clear(); return true; } diff --git a/impeller/renderer/backend/vulkan/surface_producer_vk.h b/impeller/renderer/backend/vulkan/surface_producer_vk.h index 2b8a823bf723c..88133ea6e9d48 100644 --- a/impeller/renderer/backend/vulkan/surface_producer_vk.h +++ b/impeller/renderer/backend/vulkan/surface_producer_vk.h @@ -43,13 +43,6 @@ class SurfaceProducerVK { std::unique_ptr AcquireSurface(size_t current_frame); - // take ownership of the command buffer until present. - bool QueueCommandBuffer(uint32_t frame_num, vk::UniqueCommandBuffer buffer); - - void StashRP(uint32_t frame_num, vk::UniqueRenderPass data) { - stash_rp_[frame_num].push_back(std::move(data)); - } - private: std::weak_ptr context_; @@ -63,8 +56,6 @@ class SurfaceProducerVK { // sync objects std::unique_ptr sync_objects_[kMaxFramesInFlight]; - std::vector command_buffers_[kMaxFramesInFlight]; - std::vector stash_rp_[kMaxFramesInFlight]; FML_DISALLOW_COPY_AND_ASSIGN(SurfaceProducerVK); };