• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include <string>
19 
20 #include "src/vulkan/command_pool.h"
21 #include "src/vulkan/device.h"
22 
23 namespace amber {
24 namespace vulkan {
25 
CommandBuffer(Device * device,CommandPool * pool)26 CommandBuffer::CommandBuffer(Device* device, CommandPool* pool)
27     : device_(device), pool_(pool) {}
28 
~CommandBuffer()29 CommandBuffer::~CommandBuffer() {
30   Reset();
31 
32   if (fence_ != VK_NULL_HANDLE)
33     device_->GetPtrs()->vkDestroyFence(device_->GetVkDevice(), fence_, nullptr);
34 
35   if (command_ != VK_NULL_HANDLE) {
36     device_->GetPtrs()->vkFreeCommandBuffers(
37         device_->GetVkDevice(), pool_->GetVkCommandPool(), 1, &command_);
38   }
39 }
40 
Initialize()41 Result CommandBuffer::Initialize() {
42   VkCommandBufferAllocateInfo command_info = VkCommandBufferAllocateInfo();
43   command_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
44   command_info.commandPool = pool_->GetVkCommandPool();
45   command_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
46   command_info.commandBufferCount = 1;
47 
48   if (device_->GetPtrs()->vkAllocateCommandBuffers(
49           device_->GetVkDevice(), &command_info, &command_) != VK_SUCCESS) {
50     return Result("Vulkan::Calling vkAllocateCommandBuffers Fail");
51   }
52 
53   VkFenceCreateInfo fence_info = VkFenceCreateInfo();
54   fence_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
55   if (device_->GetPtrs()->vkCreateFence(device_->GetVkDevice(), &fence_info,
56                                         nullptr, &fence_) != VK_SUCCESS) {
57     return Result("Vulkan::Calling vkCreateFence Fail");
58   }
59 
60   return {};
61 }
62 
BeginRecording()63 Result CommandBuffer::BeginRecording() {
64   VkCommandBufferBeginInfo command_begin_info = VkCommandBufferBeginInfo();
65   command_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
66   command_begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
67   if (device_->GetPtrs()->vkBeginCommandBuffer(command_, &command_begin_info) !=
68       VK_SUCCESS) {
69     return Result("Vulkan::Calling vkBeginCommandBuffer Fail");
70   }
71   guarded_ = true;
72 
73   return {};
74 }
75 
SubmitAndReset(uint32_t timeout_ms)76 Result CommandBuffer::SubmitAndReset(uint32_t timeout_ms) {
77   if (device_->GetPtrs()->vkEndCommandBuffer(command_) != VK_SUCCESS)
78     return Result("Vulkan::Calling vkEndCommandBuffer Fail");
79 
80   if (device_->GetPtrs()->vkResetFences(device_->GetVkDevice(), 1, &fence_) !=
81       VK_SUCCESS) {
82     return Result("Vulkan::Calling vkResetFences Fail");
83   }
84 
85   VkSubmitInfo submit_info = VkSubmitInfo();
86   submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
87   submit_info.commandBufferCount = 1;
88   submit_info.pCommandBuffers = &command_;
89   if (device_->GetPtrs()->vkQueueSubmit(device_->GetVkQueue(), 1, &submit_info,
90                                         fence_) != VK_SUCCESS) {
91     return Result("Vulkan::Calling vkQueueSubmit Fail");
92   }
93 
94   guarded_ = false;
95 
96   VkResult r = device_->GetPtrs()->vkWaitForFences(
97       device_->GetVkDevice(), 1, &fence_, VK_TRUE,
98       static_cast<uint64_t>(timeout_ms) * 1000ULL * 1000ULL /* nanosecond */);
99   if (r == VK_TIMEOUT)
100     return Result("Vulkan::Calling vkWaitForFences Timeout");
101   if (r != VK_SUCCESS) {
102     std::string result_str;
103     switch (r) {
104       case VK_ERROR_OUT_OF_HOST_MEMORY:
105         result_str = "OUT_OF_HOST_MEMORY";
106         break;
107       case VK_ERROR_OUT_OF_DEVICE_MEMORY:
108         result_str = "OUT_OF_DEVICE_MEMORY";
109         break;
110       case VK_ERROR_DEVICE_LOST:
111         result_str = "DEVICE_LOST";
112         break;
113       default:
114         result_str = "<UNEXPECTED RESULT>";
115         break;
116     }
117     return Result("Vulkan::Calling vkWaitForFences Fail (" + result_str + ")");
118   }
119 
120   if (device_->GetPtrs()->vkResetCommandBuffer(command_, 0) != VK_SUCCESS)
121     return Result("Vulkan::Calling vkResetCommandBuffer Fail");
122 
123   return {};
124 }
125 
Reset()126 void CommandBuffer::Reset() {
127   if (guarded_) {
128     device_->GetPtrs()->vkResetCommandBuffer(command_, 0);
129     guarded_ = false;
130   }
131 }
132 
CommandBufferGuard(CommandBuffer * buffer)133 CommandBufferGuard::CommandBufferGuard(CommandBuffer* buffer)
134     : buffer_(buffer) {
135   assert(!buffer_->guarded_);
136   result_ = buffer_->BeginRecording();
137 }
138 
~CommandBufferGuard()139 CommandBufferGuard::~CommandBufferGuard() {
140   if (buffer_->guarded_)
141     buffer_->Reset();
142 }
143 
Submit(uint32_t timeout_ms)144 Result CommandBufferGuard::Submit(uint32_t timeout_ms) {
145   assert(buffer_->guarded_);
146   return buffer_->SubmitAndReset(timeout_ms);
147 }
148 
149 }  // namespace vulkan
150 }  // namespace amber
151