• 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,bool pipeline_runtime_layer_enabled)76 Result CommandBuffer::SubmitAndReset(uint32_t timeout_ms,
77                                      bool pipeline_runtime_layer_enabled) {
78   if (device_->GetPtrs()->vkEndCommandBuffer(command_) != VK_SUCCESS)
79     return Result("Vulkan::Calling vkEndCommandBuffer Fail");
80 
81   if (device_->GetPtrs()->vkResetFences(device_->GetVkDevice(), 1, &fence_) !=
82       VK_SUCCESS) {
83     return Result("Vulkan::Calling vkResetFences Fail");
84   }
85 
86   VkSubmitInfo submit_info = VkSubmitInfo();
87   submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
88   submit_info.commandBufferCount = 1;
89   submit_info.pCommandBuffers = &command_;
90 
91   if (device_->GetPtrs()->vkQueueSubmit(device_->GetVkQueue(), 1, &submit_info,
92                                         fence_) != VK_SUCCESS) {
93     return Result("Vulkan::Calling vkQueueSubmit Fail");
94   }
95 
96   guarded_ = false;
97 
98   const uint64_t timeout_ns =
99       timeout_ms == static_cast<uint32_t>(~0u)  // honor 32bit infinity
100           ? ~0ull
101           : static_cast<uint64_t>(timeout_ms) * 1000ULL * 1000ULL;
102   VkResult r = device_->GetPtrs()->vkWaitForFences(
103       device_->GetVkDevice(), 1, &fence_, VK_TRUE, timeout_ns);
104   if (r == VK_TIMEOUT)
105     return Result("Vulkan::Calling vkWaitForFences Timeout");
106   if (r != VK_SUCCESS) {
107     std::string result_str;
108     switch (r) {
109       case VK_ERROR_OUT_OF_HOST_MEMORY:
110         result_str = "OUT_OF_HOST_MEMORY";
111         break;
112       case VK_ERROR_OUT_OF_DEVICE_MEMORY:
113         result_str = "OUT_OF_DEVICE_MEMORY";
114         break;
115       case VK_ERROR_DEVICE_LOST:
116         result_str = "DEVICE_LOST";
117         break;
118       default:
119         result_str = "<UNEXPECTED RESULT>";
120         break;
121     }
122     return Result("Vulkan::Calling vkWaitForFences Fail (" + result_str + ")");
123   }
124 
125   /*
126 google/vulkan-performance-layers requires a call to vkDeviceWaitIdle or
127 vkQueueWaitIdle in order to report the information. Since we want to be
128 able to use that layer in conjunction with Amber we need to somehow
129 communicate that the Amber script has completed.
130 */
131   if (pipeline_runtime_layer_enabled)
132     device_->GetPtrs()->vkQueueWaitIdle(device_->GetVkQueue());
133 
134   if (device_->GetPtrs()->vkResetCommandBuffer(command_, 0) != VK_SUCCESS)
135     return Result("Vulkan::Calling vkResetCommandBuffer Fail");
136 
137   return {};
138 }
139 
Reset()140 void CommandBuffer::Reset() {
141   if (guarded_) {
142     device_->GetPtrs()->vkResetCommandBuffer(command_, 0);
143     guarded_ = false;
144   }
145 }
146 
CommandBufferGuard(CommandBuffer * buffer)147 CommandBufferGuard::CommandBufferGuard(CommandBuffer* buffer)
148     : buffer_(buffer) {
149   assert(!buffer_->guarded_);
150   result_ = buffer_->BeginRecording();
151 }
152 
~CommandBufferGuard()153 CommandBufferGuard::~CommandBufferGuard() {
154   if (buffer_->guarded_)
155     buffer_->Reset();
156 }
157 
Submit(uint32_t timeout_ms,bool pipeline_runtime_layer_enabled)158 Result CommandBufferGuard::Submit(uint32_t timeout_ms,
159                                   bool pipeline_runtime_layer_enabled) {
160   assert(buffer_->guarded_);
161   return buffer_->SubmitAndReset(timeout_ms, pipeline_runtime_layer_enabled);
162 }
163 
164 }  // namespace vulkan
165 }  // namespace amber
166