blob: 11842a10467df143cb0a470bfa7bd7edfc69dda9 [file] [log] [blame]
// 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