| // 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 "fml/status.h" | |
| #include "impeller/renderer/backend/vulkan/command_queue_vk.h" | |
| #include "impeller/base/validation.h" | |
| #include "impeller/renderer/backend/vulkan/command_buffer_vk.h" | |
| #include "impeller/renderer/backend/vulkan/command_encoder_vk.h" | |
| #include "impeller/renderer/backend/vulkan/context_vk.h" | |
| #include "impeller/renderer/backend/vulkan/fence_waiter_vk.h" | |
| #include "impeller/renderer/backend/vulkan/tracked_objects_vk.h" | |
| #include "impeller/renderer/command_buffer.h" | |
| namespace impeller { | |
| CommandQueueVK::CommandQueueVK(const std::weak_ptr<ContextVK>& context) | |
| : context_(context) {} | |
| CommandQueueVK::~CommandQueueVK() = default; | |
| fml::Status CommandQueueVK::Submit( | |
| const std::vector<std::shared_ptr<CommandBuffer>>& buffers, | |
| const CompletionCallback& completion_callback) { | |
| if (buffers.empty()) { | |
| return fml::Status(fml::StatusCode::kInvalidArgument, | |
| "No command buffers provided."); | |
| } | |
| // Success or failure, you only get to submit once. | |
| fml::ScopedCleanupClosure reset([&]() { | |
| if (completion_callback) { | |
| completion_callback(CommandBuffer::Status::kError); | |
| } | |
| }); | |
| std::vector<vk::CommandBuffer> vk_buffers; | |
| std::vector<std::shared_ptr<TrackedObjectsVK>> tracked_objects; | |
| vk_buffers.reserve(buffers.size()); | |
| tracked_objects.reserve(buffers.size()); | |
| for (const std::shared_ptr<CommandBuffer>& buffer : buffers) { | |
| auto encoder = CommandBufferVK::Cast(*buffer).GetEncoder(); | |
| if (!encoder->EndCommandBuffer()) { | |
| return fml::Status(fml::StatusCode::kCancelled, | |
| "Failed to end command buffer."); | |
| } | |
| tracked_objects.push_back(encoder->tracked_objects_); | |
| vk_buffers.push_back(encoder->GetCommandBuffer()); | |
| encoder->Reset(); | |
| } | |
| auto context = context_.lock(); | |
| if (!context) { | |
| VALIDATION_LOG << "Device lost."; | |
| return fml::Status(fml::StatusCode::kCancelled, "Device lost."); | |
| } | |
| auto [fence_result, fence] = context->GetDevice().createFenceUnique({}); | |
| if (fence_result != vk::Result::eSuccess) { | |
| VALIDATION_LOG << "Failed to create fence: " << vk::to_string(fence_result); | |
| return fml::Status(fml::StatusCode::kCancelled, "Failed to create fence."); | |
| } | |
| vk::SubmitInfo submit_info; | |
| submit_info.setCommandBuffers(vk_buffers); | |
| auto status = context->GetGraphicsQueue()->Submit(submit_info, *fence); | |
| if (status != vk::Result::eSuccess) { | |
| VALIDATION_LOG << "Failed to submit queue: " << vk::to_string(status); | |
| return fml::Status(fml::StatusCode::kCancelled, "Failed to submit queue: "); | |
| } | |
| // Submit will proceed, call callback with true when it is done and do not | |
| // call when `reset` is collected. | |
| auto added_fence = context->GetFenceWaiter()->AddFence( | |
| std::move(fence), [completion_callback, tracked_objects = std::move( | |
| tracked_objects)]() mutable { | |
| // Ensure tracked objects are destructed before calling any final | |
| // callbacks. | |
| tracked_objects.clear(); | |
| if (completion_callback) { | |
| completion_callback(CommandBuffer::Status::kCompleted); | |
| } | |
| }); | |
| if (!added_fence) { | |
| return fml::Status(fml::StatusCode::kCancelled, "Failed to add fence."); | |
| } | |
| reset.Release(); | |
| return fml::Status(); | |
| } | |
| } // namespace impeller |