| // 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/command_encoder_vk.h" |
| |
| #include "flutter/fml/closure.h" |
| #include "flutter/fml/trace_event.h" |
| #include "impeller/renderer/backend/vulkan/context_vk.h" |
| #include "impeller/renderer/backend/vulkan/fence_waiter_vk.h" |
| #include "impeller/renderer/backend/vulkan/texture_vk.h" |
| |
| namespace impeller { |
| |
| class TrackedObjectsVK { |
| public: |
| explicit TrackedObjectsVK(const vk::Device& device, |
| const std::shared_ptr<CommandPoolVK>& pool) |
| : desc_pool_(device) { |
| if (!pool) { |
| return; |
| } |
| auto buffer = pool->CreateGraphicsCommandBuffer(); |
| if (!buffer) { |
| return; |
| } |
| pool_ = pool; |
| buffer_ = std::move(buffer); |
| is_valid_ = true; |
| } |
| |
| ~TrackedObjectsVK() { |
| if (!buffer_) { |
| return; |
| } |
| auto pool = pool_.lock(); |
| if (!pool) { |
| VALIDATION_LOG |
| << "Command pool died before a command buffer could be recycled."; |
| return; |
| } |
| pool->CollectGraphicsCommandBuffer(std::move(buffer_)); |
| } |
| |
| bool IsValid() const { return is_valid_; } |
| |
| void Track(std::shared_ptr<SharedObjectVK> object) { |
| tracked_objects_.insert(std::move(object)); |
| } |
| |
| void Track(std::shared_ptr<const DeviceBuffer> buffer) { |
| tracked_buffers_.insert(std::move(buffer)); |
| } |
| |
| void Track(std::shared_ptr<const TextureSourceVK> texture) { |
| tracked_textures_.insert(std::move(texture)); |
| } |
| |
| vk::CommandBuffer GetCommandBuffer() const { return *buffer_; } |
| |
| DescriptorPoolVK& GetDescriptorPool() { return desc_pool_; } |
| |
| private: |
| DescriptorPoolVK desc_pool_; |
| std::weak_ptr<CommandPoolVK> pool_; |
| vk::UniqueCommandBuffer buffer_; |
| std::set<std::shared_ptr<SharedObjectVK>> tracked_objects_; |
| std::set<std::shared_ptr<const DeviceBuffer>> tracked_buffers_; |
| std::set<std::shared_ptr<const TextureSourceVK>> tracked_textures_; |
| bool is_valid_ = false; |
| |
| FML_DISALLOW_COPY_AND_ASSIGN(TrackedObjectsVK); |
| }; |
| |
| CommandEncoderVK::CommandEncoderVK(vk::Device device, |
| vk::Queue 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()) { |
| return; |
| } |
| vk::CommandBufferBeginInfo begin_info; |
| begin_info.flags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit; |
| if (tracked_objects_->GetCommandBuffer().begin(begin_info) != |
| vk::Result::eSuccess) { |
| VALIDATION_LOG << "Could not begin command buffer."; |
| return; |
| } |
| device_ = device; |
| queue_ = queue; |
| is_valid_ = true; |
| } |
| |
| CommandEncoderVK::~CommandEncoderVK() = default; |
| |
| bool CommandEncoderVK::IsValid() const { |
| return is_valid_; |
| } |
| |
| bool CommandEncoderVK::Submit() { |
| if (!IsValid()) { |
| return false; |
| } |
| |
| // Success or failure, you only get to submit once. |
| fml::ScopedCleanupClosure reset([&]() { Reset(); }); |
| |
| InsertDebugMarker("QueueSubmit"); |
| |
| auto command_buffer = GetCommandBuffer(); |
| |
| if (command_buffer.end() != vk::Result::eSuccess) { |
| return false; |
| } |
| auto [fence_result, fence] = device_.createFenceUnique({}); |
| if (fence_result != vk::Result::eSuccess) { |
| return false; |
| } |
| |
| vk::SubmitInfo submit_info; |
| std::vector<vk::CommandBuffer> buffers = {command_buffer}; |
| submit_info.setCommandBuffers(buffers); |
| if (queue_.submit(submit_info, *fence) != vk::Result::eSuccess) { |
| return false; |
| } |
| |
| return fence_waiter_->AddFence( |
| std::move(fence), [tracked_objects = std::move(tracked_objects_)] { |
| // Nothing to do, we just drop the tracked objects on the floor. |
| }); |
| } |
| |
| vk::CommandBuffer CommandEncoderVK::GetCommandBuffer() const { |
| if (tracked_objects_) { |
| return tracked_objects_->GetCommandBuffer(); |
| } |
| return {}; |
| } |
| |
| void CommandEncoderVK::Reset() { |
| tracked_objects_.reset(); |
| |
| queue_ = nullptr; |
| device_ = nullptr; |
| is_valid_ = false; |
| } |
| |
| bool CommandEncoderVK::Track(std::shared_ptr<SharedObjectVK> object) { |
| if (!IsValid()) { |
| return false; |
| } |
| tracked_objects_->Track(std::move(object)); |
| return true; |
| } |
| |
| bool CommandEncoderVK::Track(std::shared_ptr<const DeviceBuffer> buffer) { |
| if (!IsValid()) { |
| return false; |
| } |
| tracked_objects_->Track(std::move(buffer)); |
| return true; |
| } |
| |
| bool CommandEncoderVK::Track(std::shared_ptr<const TextureSourceVK> texture) { |
| if (!IsValid()) { |
| return false; |
| } |
| tracked_objects_->Track(std::move(texture)); |
| return true; |
| } |
| |
| bool CommandEncoderVK::Track(const std::shared_ptr<const Texture>& texture) { |
| if (!texture) { |
| return false; |
| } |
| return Track(TextureVK::Cast(*texture).GetTextureSource()); |
| } |
| |
| std::optional<vk::DescriptorSet> CommandEncoderVK::AllocateDescriptorSet( |
| const vk::DescriptorSetLayout& layout) { |
| if (!IsValid()) { |
| return std::nullopt; |
| } |
| return tracked_objects_->GetDescriptorPool().AllocateDescriptorSet(layout); |
| } |
| |
| void CommandEncoderVK::PushDebugGroup(const char* label) const { |
| if (!HasValidationLayers()) { |
| return; |
| } |
| vk::DebugUtilsLabelEXT label_info; |
| label_info.pLabelName = label; |
| if (auto command_buffer = GetCommandBuffer()) { |
| command_buffer.beginDebugUtilsLabelEXT(label_info); |
| } |
| if (queue_) { |
| queue_.beginDebugUtilsLabelEXT(label_info); |
| } |
| } |
| |
| void CommandEncoderVK::PopDebugGroup() const { |
| if (!HasValidationLayers()) { |
| return; |
| } |
| if (auto command_buffer = GetCommandBuffer()) { |
| command_buffer.endDebugUtilsLabelEXT(); |
| } |
| if (queue_) { |
| queue_.endDebugUtilsLabelEXT(); |
| } |
| } |
| |
| void CommandEncoderVK::InsertDebugMarker(const char* label) const { |
| if (!HasValidationLayers()) { |
| return; |
| } |
| vk::DebugUtilsLabelEXT label_info; |
| label_info.pLabelName = label; |
| if (auto command_buffer = GetCommandBuffer()) { |
| command_buffer.insertDebugUtilsLabelEXT(label_info); |
| } |
| if (queue_) { |
| queue_.insertDebugUtilsLabelEXT(label_info); |
| } |
| } |
| |
| } // namespace impeller |