1 // Copyright 2019 The Amber Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "src/vulkan/command_buffer.h"
16
17 #include <cassert>
18
19 #include "src/vulkan/command_pool.h"
20 #include "src/vulkan/device.h"
21
22 namespace amber {
23 namespace vulkan {
24
CommandBuffer(Device * device,CommandPool * pool)25 CommandBuffer::CommandBuffer(Device* device, CommandPool* pool)
26 : device_(device), pool_(pool) {}
27
~CommandBuffer()28 CommandBuffer::~CommandBuffer() {
29 Reset();
30
31 if (fence_ != VK_NULL_HANDLE)
32 device_->GetPtrs()->vkDestroyFence(device_->GetVkDevice(), fence_, nullptr);
33
34 if (command_ != VK_NULL_HANDLE) {
35 device_->GetPtrs()->vkFreeCommandBuffers(
36 device_->GetVkDevice(), pool_->GetVkCommandPool(), 1, &command_);
37 }
38 }
39
Initialize()40 Result CommandBuffer::Initialize() {
41 VkCommandBufferAllocateInfo command_info = VkCommandBufferAllocateInfo();
42 command_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
43 command_info.commandPool = pool_->GetVkCommandPool();
44 command_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
45 command_info.commandBufferCount = 1;
46
47 if (device_->GetPtrs()->vkAllocateCommandBuffers(
48 device_->GetVkDevice(), &command_info, &command_) != VK_SUCCESS) {
49 return Result("Vulkan::Calling vkAllocateCommandBuffers Fail");
50 }
51
52 VkFenceCreateInfo fence_info = VkFenceCreateInfo();
53 fence_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
54 if (device_->GetPtrs()->vkCreateFence(device_->GetVkDevice(), &fence_info,
55 nullptr, &fence_) != VK_SUCCESS) {
56 return Result("Vulkan::Calling vkCreateFence Fail");
57 }
58
59 return {};
60 }
61
BeginRecording()62 Result CommandBuffer::BeginRecording() {
63 VkCommandBufferBeginInfo command_begin_info = VkCommandBufferBeginInfo();
64 command_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
65 command_begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
66 if (device_->GetPtrs()->vkBeginCommandBuffer(command_, &command_begin_info) !=
67 VK_SUCCESS) {
68 return Result("Vulkan::Calling vkBeginCommandBuffer Fail");
69 }
70 guarded_ = true;
71
72 return {};
73 }
74
SubmitAndReset(uint32_t timeout_ms)75 Result CommandBuffer::SubmitAndReset(uint32_t timeout_ms) {
76 if (device_->GetPtrs()->vkEndCommandBuffer(command_) != VK_SUCCESS)
77 return Result("Vulkan::Calling vkEndCommandBuffer Fail");
78
79 if (device_->GetPtrs()->vkResetFences(device_->GetVkDevice(), 1, &fence_) !=
80 VK_SUCCESS) {
81 return Result("Vulkan::Calling vkResetFences Fail");
82 }
83
84 VkSubmitInfo submit_info = VkSubmitInfo();
85 submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
86 submit_info.commandBufferCount = 1;
87 submit_info.pCommandBuffers = &command_;
88 if (device_->GetPtrs()->vkQueueSubmit(device_->GetVkQueue(), 1, &submit_info,
89 fence_) != VK_SUCCESS) {
90 return Result("Vulkan::Calling vkQueueSubmit Fail");
91 }
92
93 guarded_ = false;
94
95 VkResult r = device_->GetPtrs()->vkWaitForFences(
96 device_->GetVkDevice(), 1, &fence_, VK_TRUE,
97 static_cast<uint64_t>(timeout_ms) * 1000ULL * 1000ULL /* nanosecond */);
98 if (r == VK_TIMEOUT)
99 return Result("Vulkan::Calling vkWaitForFences Timeout");
100 if (r != VK_SUCCESS)
101 return Result("Vulkan::Calling vkWaitForFences Fail");
102
103 if (device_->GetPtrs()->vkResetCommandBuffer(command_, 0) != VK_SUCCESS)
104 return Result("Vulkan::Calling vkResetCommandBuffer Fail");
105
106 return {};
107 }
108
Reset()109 void CommandBuffer::Reset() {
110 if (guarded_) {
111 device_->GetPtrs()->vkEndCommandBuffer(command_);
112 device_->GetPtrs()->vkResetCommandBuffer(command_, 0);
113 guarded_ = false;
114 }
115 }
116
CommandBufferGuard(CommandBuffer * buffer)117 CommandBufferGuard::CommandBufferGuard(CommandBuffer* buffer)
118 : buffer_(buffer) {
119 assert(!buffer_->guarded_);
120 result_ = buffer_->BeginRecording();
121 }
122
~CommandBufferGuard()123 CommandBufferGuard::~CommandBufferGuard() {
124 if (buffer_->guarded_)
125 buffer_->Reset();
126 }
127
Submit(uint32_t timeout_ms)128 Result CommandBufferGuard::Submit(uint32_t timeout_ms) {
129 assert(buffer_->guarded_);
130 return buffer_->SubmitAndReset(timeout_ms);
131 }
132
133 } // namespace vulkan
134 } // namespace amber
135