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