• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2018 The Amber Authors.
2 // Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //     http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 
16 #include "src/vulkan/resource.h"
17 
18 #include <cstring>
19 #include <limits>
20 
21 #include "src/vulkan/command_buffer.h"
22 #include "src/vulkan/device.h"
23 
24 namespace amber {
25 namespace vulkan {
26 namespace {
27 
28 VkMemoryBarrier kMemoryBarrierForAll = {
29     VK_STRUCTURE_TYPE_MEMORY_BARRIER, nullptr,
30     VK_ACCESS_INDIRECT_COMMAND_READ_BIT | VK_ACCESS_INDEX_READ_BIT |
31         VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | VK_ACCESS_UNIFORM_READ_BIT |
32         VK_ACCESS_INPUT_ATTACHMENT_READ_BIT | VK_ACCESS_SHADER_READ_BIT |
33         VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
34         VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
35         VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
36         VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
37         VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT |
38         VK_ACCESS_HOST_READ_BIT | VK_ACCESS_HOST_WRITE_BIT,
39     VK_ACCESS_INDIRECT_COMMAND_READ_BIT | VK_ACCESS_INDEX_READ_BIT |
40         VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | VK_ACCESS_UNIFORM_READ_BIT |
41         VK_ACCESS_INPUT_ATTACHMENT_READ_BIT | VK_ACCESS_SHADER_READ_BIT |
42         VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
43         VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
44         VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
45         VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
46         VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT |
47         VK_ACCESS_HOST_READ_BIT | VK_ACCESS_HOST_WRITE_BIT};
48 
49 }  // namespace
50 
Resource(Device * device,uint32_t size_in_bytes)51 Resource::Resource(Device* device, uint32_t size_in_bytes)
52     : device_(device), size_in_bytes_(size_in_bytes) {}
53 
54 Resource::~Resource() = default;
55 
CreateVkBuffer(VkBuffer * buffer,VkBufferUsageFlags usage)56 Result Resource::CreateVkBuffer(VkBuffer* buffer, VkBufferUsageFlags usage) {
57   if (!buffer)
58     return Result("Vulkan::Given VkBuffer pointer is nullptr");
59 
60   VkBufferCreateInfo buffer_info = VkBufferCreateInfo();
61   buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
62   buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
63   buffer_info.size = size_in_bytes_;
64   buffer_info.usage = usage;
65 
66   if (device_->GetPtrs()->vkCreateBuffer(device_->GetVkDevice(), &buffer_info,
67                                          nullptr, buffer) != VK_SUCCESS) {
68     return Result("Vulkan::Calling vkCreateBuffer Fail");
69   }
70 
71   return {};
72 }
73 
ChooseMemory(uint32_t memory_type_bits,VkMemoryPropertyFlags flags,bool require_flags_found)74 uint32_t Resource::ChooseMemory(uint32_t memory_type_bits,
75                                 VkMemoryPropertyFlags flags,
76                                 bool require_flags_found) {
77   // Based on Vulkan spec about VkMemoryRequirements, N th bit of
78   // |memory_type_bits| is 1 where N can be the proper memory type index.
79   // This code is looking for the first non-zero bit whose memory type
80   // VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT property. If not exists,
81   // it returns the first non-zero bit.
82   uint32_t first_non_zero = std::numeric_limits<uint32_t>::max();
83   uint32_t memory_type_index = 0;
84   while (memory_type_bits) {
85     if (memory_type_bits % 2) {
86       if (first_non_zero == std::numeric_limits<uint32_t>::max())
87         first_non_zero = memory_type_index;
88 
89       if (device_->HasMemoryFlags(memory_type_index, flags))
90         return memory_type_index;
91     }
92 
93     ++memory_type_index;
94     memory_type_bits >>= 1;
95   }
96 
97   if (require_flags_found)
98     return std::numeric_limits<uint32_t>::max();
99 
100   return first_non_zero;
101 }
AllocateAndBindMemoryToVkBuffer(VkBuffer buffer,VkDeviceMemory * memory,VkMemoryPropertyFlags flags,bool require_flags_found,uint32_t * memory_type_index)102 Result Resource::AllocateAndBindMemoryToVkBuffer(VkBuffer buffer,
103                                                  VkDeviceMemory* memory,
104                                                  VkMemoryPropertyFlags flags,
105                                                  bool require_flags_found,
106                                                  uint32_t* memory_type_index) {
107   if (memory_type_index == nullptr) {
108     return Result(
109         "Vulkan: Resource::AllocateAndBindMemoryToVkBuffer memory_type_index "
110         "is nullptr");
111   }
112 
113   *memory_type_index = 0;
114 
115   if (buffer == VK_NULL_HANDLE)
116     return Result("Vulkan::Given VkBuffer is VK_NULL_HANDLE");
117   if (memory == nullptr)
118     return Result("Vulkan::Given VkDeviceMemory pointer is nullptr");
119 
120   VkMemoryRequirements requirement;
121   device_->GetPtrs()->vkGetBufferMemoryRequirements(device_->GetVkDevice(),
122                                                     buffer, &requirement);
123 
124   *memory_type_index =
125       ChooseMemory(requirement.memoryTypeBits, flags, require_flags_found);
126   if (*memory_type_index == std::numeric_limits<uint32_t>::max())
127     return Result("Vulkan::Find Proper Memory Fail");
128 
129   Result r = AllocateMemory(memory, requirement.size, *memory_type_index);
130   if (!r.IsSuccess())
131     return r;
132 
133   if (device_->GetPtrs()->vkBindBufferMemory(device_->GetVkDevice(), buffer,
134                                              *memory, 0) != VK_SUCCESS) {
135     return Result("Vulkan::Calling vkBindBufferMemory Fail");
136   }
137 
138   return {};
139 }
140 
AllocateMemory(VkDeviceMemory * memory,VkDeviceSize size,uint32_t memory_type_index)141 Result Resource::AllocateMemory(VkDeviceMemory* memory,
142                                 VkDeviceSize size,
143                                 uint32_t memory_type_index) {
144   VkMemoryAllocateInfo alloc_info = VkMemoryAllocateInfo();
145   VkMemoryAllocateFlagsInfo allocFlagsInfo = VkMemoryAllocateFlagsInfo();
146 
147   alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
148   alloc_info.allocationSize = size;
149   alloc_info.memoryTypeIndex = memory_type_index;
150 
151   if (memory_allocate_flags_ != 0) {
152     allocFlagsInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO;
153     allocFlagsInfo.pNext = nullptr;
154     allocFlagsInfo.flags = memory_allocate_flags_;
155     allocFlagsInfo.deviceMask = 0u;
156 
157     alloc_info.pNext = &allocFlagsInfo;
158   }
159 
160   if (device_->GetPtrs()->vkAllocateMemory(device_->GetVkDevice(), &alloc_info,
161                                            nullptr, memory) != VK_SUCCESS) {
162     return Result("Vulkan::Calling vkAllocateMemory Fail");
163   }
164 
165   return {};
166 }
167 
MapMemory(VkDeviceMemory memory)168 Result Resource::MapMemory(VkDeviceMemory memory) {
169   if (device_->GetPtrs()->vkMapMemory(device_->GetVkDevice(), memory, 0,
170                                       VK_WHOLE_SIZE, 0,
171                                       &memory_ptr_) != VK_SUCCESS) {
172     return Result("Vulkan::Calling vkMapMemory Fail");
173   }
174 
175   return {};
176 }
177 
UnMapMemory(VkDeviceMemory memory)178 void Resource::UnMapMemory(VkDeviceMemory memory) {
179   device_->GetPtrs()->vkUnmapMemory(device_->GetVkDevice(), memory);
180 }
181 
UpdateMemoryWithRawData(const std::vector<uint8_t> & raw_data)182 void Resource::UpdateMemoryWithRawData(const std::vector<uint8_t>& raw_data) {
183   size_t effective_size =
184       raw_data.size() > GetSizeInBytes() ? GetSizeInBytes() : raw_data.size();
185   std::memcpy(HostAccessibleMemoryPtr(), raw_data.data(), effective_size);
186 }
187 
MemoryBarrier(CommandBuffer * command_buffer)188 void Resource::MemoryBarrier(CommandBuffer* command_buffer) {
189   // TODO(jaebaek): Current memory barrier is naively implemented.
190   // Update it with the following access flags:
191   // (r = read, w = write)
192   //
193   //                                 Host           Device
194   // VertexBuffer                  host w         vertex r
195   //                           transfer w       transfer r
196   //
197   // IndexBuffer                   host w          index r
198   //                           transfer w       transfer r
199   //
200   // FrameBuffer                   host r          color w
201   //                                       depth/stencil w
202   //                           transfer r       transfer w
203   //
204   // ReadWrite Descriptors       host r/w       shader r/w
205   //                         transfer r/w     transfer r/w
206   //
207   // ReadOnly Descriptors          host w         shader r
208   //                           transfer w       transfer r
209   device_->GetPtrs()->vkCmdPipelineBarrier(
210       command_buffer->GetVkCommandBuffer(), VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
211       VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 1, &kMemoryBarrierForAll, 0,
212       nullptr, 0, nullptr);
213 }
214 
215 }  // namespace vulkan
216 }  // namespace amber
217