blob: bcf0ac91cca62d39d5b36fc92574ed2e7dcf5eb5 [file] [log] [blame]
// Copyright 2019 The Amber Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "src/vulkan/command_buffer.h"
#include <cassert>
#include "src/vulkan/command_pool.h"
#include "src/vulkan/device.h"
namespace amber {
namespace vulkan {
CommandBuffer::CommandBuffer(Device* device, CommandPool* pool)
: device_(device), pool_(pool) {}
CommandBuffer::~CommandBuffer() {
if (fence_ != VK_NULL_HANDLE)
device_->GetPtrs()->vkDestroyFence(device_->GetVkDevice(), fence_, nullptr);
if (command_ != VK_NULL_HANDLE) {
device_->GetPtrs()->vkFreeCommandBuffers(
device_->GetVkDevice(), pool_->GetVkCommandPool(), 1, &command_);
}
}
Result CommandBuffer::Initialize() {
VkCommandBufferAllocateInfo command_info = VkCommandBufferAllocateInfo();
command_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
command_info.commandPool = pool_->GetVkCommandPool();
command_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
command_info.commandBufferCount = 1;
if (device_->GetPtrs()->vkAllocateCommandBuffers(
device_->GetVkDevice(), &command_info, &command_) != VK_SUCCESS) {
return Result("Vulkan::Calling vkAllocateCommandBuffers Fail");
}
VkFenceCreateInfo fence_info = VkFenceCreateInfo();
fence_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
if (device_->GetPtrs()->vkCreateFence(device_->GetVkDevice(), &fence_info,
nullptr, &fence_) != VK_SUCCESS) {
return Result("Vulkan::Calling vkCreateFence Fail");
}
return {};
}
Result CommandBuffer::BeginRecording() {
VkCommandBufferBeginInfo command_begin_info = VkCommandBufferBeginInfo();
command_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
command_begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
if (device_->GetPtrs()->vkBeginCommandBuffer(command_, &command_begin_info) !=
VK_SUCCESS) {
return Result("Vulkan::Calling vkBeginCommandBuffer Fail");
}
return {};
}
Result CommandBuffer::SubmitAndReset(uint32_t timeout_ms) {
if (device_->GetPtrs()->vkEndCommandBuffer(command_) != VK_SUCCESS)
return Result("Vulkan::Calling vkEndCommandBuffer Fail");
if (device_->GetPtrs()->vkResetFences(device_->GetVkDevice(), 1, &fence_) !=
VK_SUCCESS) {
return Result("Vulkan::Calling vkResetFences Fail");
}
VkSubmitInfo submit_info = VkSubmitInfo();
submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submit_info.commandBufferCount = 1;
submit_info.pCommandBuffers = &command_;
if (device_->GetPtrs()->vkQueueSubmit(device_->GetVkQueue(), 1, &submit_info,
fence_) != VK_SUCCESS) {
return Result("Vulkan::Calling vkQueueSubmit Fail");
}
VkResult r = device_->GetPtrs()->vkWaitForFences(
device_->GetVkDevice(), 1, &fence_, VK_TRUE,
static_cast<uint64_t>(timeout_ms) * 1000ULL * 1000ULL /* nanosecond */);
if (r == VK_TIMEOUT)
return Result("Vulkan::Calling vkWaitForFences Timeout");
if (r != VK_SUCCESS)
return Result("Vulkan::Calling vkWaitForFences Fail");
if (device_->GetPtrs()->vkResetCommandBuffer(command_, 0) != VK_SUCCESS)
return Result("Vulkan::Calling vkResetCommandBuffer Fail");
return {};
}
CommandBufferGuard::CommandBufferGuard(CommandBuffer* buffer)
: buffer_(buffer) {
assert(!buffer_->guarded_);
buffer_->guarded_ = true;
result_ = buffer_->BeginRecording();
}
CommandBufferGuard::~CommandBufferGuard() = default;
Result CommandBufferGuard::Submit(uint32_t timeout_ms) {
assert(buffer_->guarded_);
result_ = buffer_->SubmitAndReset(timeout_ms);
buffer_->guarded_ = false;
return result_;
}
} // namespace vulkan
} // namespace amber