• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2018 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/resource.h"
16 
17 #include <cstring>
18 #include <limits>
19 
20 #include "src/vulkan/command_buffer.h"
21 #include "src/vulkan/device.h"
22 
23 namespace amber {
24 namespace vulkan {
25 namespace {
26 
27 VkMemoryBarrier kMemoryBarrierForAll = {
28     VK_STRUCTURE_TYPE_MEMORY_BARRIER, nullptr,
29     VK_ACCESS_INDIRECT_COMMAND_READ_BIT | VK_ACCESS_INDEX_READ_BIT |
30         VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | VK_ACCESS_UNIFORM_READ_BIT |
31         VK_ACCESS_INPUT_ATTACHMENT_READ_BIT | VK_ACCESS_SHADER_READ_BIT |
32         VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
33         VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
34         VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
35         VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
36         VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT |
37         VK_ACCESS_HOST_READ_BIT | VK_ACCESS_HOST_WRITE_BIT,
38     VK_ACCESS_INDIRECT_COMMAND_READ_BIT | VK_ACCESS_INDEX_READ_BIT |
39         VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | VK_ACCESS_UNIFORM_READ_BIT |
40         VK_ACCESS_INPUT_ATTACHMENT_READ_BIT | VK_ACCESS_SHADER_READ_BIT |
41         VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
42         VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
43         VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
44         VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
45         VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT |
46         VK_ACCESS_HOST_READ_BIT | VK_ACCESS_HOST_WRITE_BIT};
47 
48 }  // namespace
49 
Resource(Device * device,uint32_t size_in_bytes)50 Resource::Resource(Device* device, uint32_t size_in_bytes)
51     : device_(device), size_in_bytes_(size_in_bytes) {}
52 
53 Resource::~Resource() = default;
54 
CreateVkBuffer(VkBuffer * buffer,VkBufferUsageFlags usage)55 Result Resource::CreateVkBuffer(VkBuffer* buffer, VkBufferUsageFlags usage) {
56   if (!buffer)
57     return Result("Vulkan::Given VkBuffer pointer is nullptr");
58 
59   VkBufferCreateInfo buffer_info = VkBufferCreateInfo();
60   buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
61   buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
62   buffer_info.size = size_in_bytes_;
63   buffer_info.usage = usage;
64 
65   if (device_->GetPtrs()->vkCreateBuffer(device_->GetVkDevice(), &buffer_info,
66                                          nullptr, buffer) != VK_SUCCESS) {
67     return Result("Vulkan::Calling vkCreateBuffer Fail");
68   }
69 
70   return {};
71 }
72 
ChooseMemory(uint32_t memory_type_bits,VkMemoryPropertyFlags flags,bool require_flags_found)73 uint32_t Resource::ChooseMemory(uint32_t memory_type_bits,
74                                 VkMemoryPropertyFlags flags,
75                                 bool require_flags_found) {
76   // Based on Vulkan spec about VkMemoryRequirements, N th bit of
77   // |memory_type_bits| is 1 where N can be the proper memory type index.
78   // This code is looking for the first non-zero bit whose memory type
79   // VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT property. If not exists,
80   // it returns the first non-zero bit.
81   uint32_t first_non_zero = std::numeric_limits<uint32_t>::max();
82   uint32_t memory_type_index = 0;
83   while (memory_type_bits) {
84     if (memory_type_bits % 2) {
85       if (first_non_zero == std::numeric_limits<uint32_t>::max())
86         first_non_zero = memory_type_index;
87 
88       if (device_->HasMemoryFlags(memory_type_index, flags))
89         return memory_type_index;
90     }
91 
92     ++memory_type_index;
93     memory_type_bits >>= 1;
94   }
95 
96   if (require_flags_found)
97     return std::numeric_limits<uint32_t>::max();
98 
99   return first_non_zero;
100 }
AllocateAndBindMemoryToVkBuffer(VkBuffer buffer,VkDeviceMemory * memory,VkMemoryPropertyFlags flags,bool require_flags_found,uint32_t * memory_type_index)101 Result Resource::AllocateAndBindMemoryToVkBuffer(VkBuffer buffer,
102                                                  VkDeviceMemory* memory,
103                                                  VkMemoryPropertyFlags flags,
104                                                  bool require_flags_found,
105                                                  uint32_t* memory_type_index) {
106   if (memory_type_index == nullptr) {
107     return Result(
108         "Vulkan: Resource::AllocateAndBindMemoryToVkBuffer memory_type_index "
109         "is nullptr");
110   }
111 
112   *memory_type_index = 0;
113 
114   if (buffer == VK_NULL_HANDLE)
115     return Result("Vulkan::Given VkBuffer is VK_NULL_HANDLE");
116   if (memory == nullptr)
117     return Result("Vulkan::Given VkDeviceMemory pointer is nullptr");
118 
119   VkMemoryRequirements requirement;
120   device_->GetPtrs()->vkGetBufferMemoryRequirements(device_->GetVkDevice(),
121                                                     buffer, &requirement);
122 
123   *memory_type_index =
124       ChooseMemory(requirement.memoryTypeBits, flags, require_flags_found);
125   if (*memory_type_index == std::numeric_limits<uint32_t>::max())
126     return Result("Vulkan::Find Proper Memory Fail");
127 
128   Result r = AllocateMemory(memory, requirement.size, *memory_type_index);
129   if (!r.IsSuccess())
130     return r;
131 
132   if (device_->GetPtrs()->vkBindBufferMemory(device_->GetVkDevice(), buffer,
133                                              *memory, 0) != VK_SUCCESS) {
134     return Result("Vulkan::Calling vkBindBufferMemory Fail");
135   }
136 
137   return {};
138 }
139 
AllocateMemory(VkDeviceMemory * memory,VkDeviceSize size,uint32_t memory_type_index)140 Result Resource::AllocateMemory(VkDeviceMemory* memory,
141                                 VkDeviceSize size,
142                                 uint32_t memory_type_index) {
143   VkMemoryAllocateInfo alloc_info = VkMemoryAllocateInfo();
144   alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
145   alloc_info.allocationSize = size;
146   alloc_info.memoryTypeIndex = memory_type_index;
147   if (device_->GetPtrs()->vkAllocateMemory(device_->GetVkDevice(), &alloc_info,
148                                            nullptr, memory) != VK_SUCCESS) {
149     return Result("Vulkan::Calling vkAllocateMemory Fail");
150   }
151 
152   return {};
153 }
154 
MapMemory(VkDeviceMemory memory)155 Result Resource::MapMemory(VkDeviceMemory memory) {
156   if (device_->GetPtrs()->vkMapMemory(device_->GetVkDevice(), memory, 0,
157                                       VK_WHOLE_SIZE, 0,
158                                       &memory_ptr_) != VK_SUCCESS) {
159     return Result("Vulkan::Calling vkMapMemory Fail");
160   }
161 
162   return {};
163 }
164 
UnMapMemory(VkDeviceMemory memory)165 void Resource::UnMapMemory(VkDeviceMemory memory) {
166   device_->GetPtrs()->vkUnmapMemory(device_->GetVkDevice(), memory);
167 }
168 
UpdateMemoryWithRawData(const std::vector<uint8_t> & raw_data)169 void Resource::UpdateMemoryWithRawData(const std::vector<uint8_t>& raw_data) {
170   size_t effective_size =
171       raw_data.size() > GetSizeInBytes() ? GetSizeInBytes() : raw_data.size();
172   std::memcpy(HostAccessibleMemoryPtr(), raw_data.data(), effective_size);
173 }
174 
MemoryBarrier(CommandBuffer * command_buffer)175 void Resource::MemoryBarrier(CommandBuffer* command_buffer) {
176   // TODO(jaebaek): Current memory barrier is naively implemented.
177   // Update it with the following access flags:
178   // (r = read, w = write)
179   //
180   //                                 Host           Device
181   // VertexBuffer                  host w         vertex r
182   //                           transfer w       transfer r
183   //
184   // IndexBuffer                   host w          index r
185   //                           transfer w       transfer r
186   //
187   // FrameBuffer                   host r          color w
188   //                                       depth/stencil w
189   //                           transfer r       transfer w
190   //
191   // ReadWrite Descriptors       host r/w       shader r/w
192   //                         transfer r/w     transfer r/w
193   //
194   // ReadOnly Descriptors          host w         shader r
195   //                           transfer w       transfer r
196   device_->GetPtrs()->vkCmdPipelineBarrier(
197       command_buffer->GetVkCommandBuffer(), VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
198       VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 1, &kMemoryBarrierForAll, 0,
199       nullptr, 0, nullptr);
200 }
201 
202 }  // namespace vulkan
203 }  // namespace amber
204