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/buffer_descriptor.h"
16 
17 #include <algorithm>
18 #include <utility>
19 #include <vector>
20 
21 #include "src/make_unique.h"
22 #include "src/vulkan/command_buffer.h"
23 #include "src/vulkan/device.h"
24 
25 namespace amber {
26 namespace vulkan {
27 
BufferDescriptor(Buffer * buffer,DescriptorType type,Device * device,uint32_t desc_set,uint32_t binding,Pipeline * pipeline)28 BufferDescriptor::BufferDescriptor(Buffer* buffer,
29                                    DescriptorType type,
30                                    Device* device,
31                                    uint32_t desc_set,
32                                    uint32_t binding,
33                                    Pipeline* pipeline)
34     : BufferBackedDescriptor(buffer,
35                              type,
36                              device,
37                              desc_set,
38                              binding,
39                              pipeline) {}
40 
41 BufferDescriptor::~BufferDescriptor() = default;
42 
CreateResourceIfNeeded()43 Result BufferDescriptor::CreateResourceIfNeeded() {
44   auto& transfer_resources = pipeline_->GetDescriptorTransferResources();
45 
46   VkBufferUsageFlags flags =
47       VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
48   if (IsUniformBuffer() || IsUniformBufferDynamic()) {
49     flags |= VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
50   } else if (IsStorageBuffer() || IsStorageBufferDynamic()) {
51     flags |= VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
52   } else if (IsUniformTexelBuffer()) {
53     flags |= VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT;
54   } else if (IsStorageTexelBuffer()) {
55     flags |= VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT;
56   } else {
57     return Result("Unexpected buffer type when deciding usage flags");
58   }
59 
60   for (const auto& amber_buffer : GetAmberBuffers()) {
61     // Create (but don't initialize) the transfer buffer if not already created.
62     if (transfer_resources.count(amber_buffer) == 0) {
63       auto size_in_bytes =
64           static_cast<uint32_t>(amber_buffer->ValuePtr()->size());
65       auto transfer_buffer = MakeUnique<TransferBuffer>(
66           device_, size_in_bytes, amber_buffer->GetFormat());
67       transfer_buffer->SetReadOnly(IsReadOnly());
68       transfer_resources[amber_buffer] = std::move(transfer_buffer);
69     } else {
70       // Unset transfer buffer's read only property if needed.
71       if (!IsReadOnly()) {
72         transfer_resources[amber_buffer]->SetReadOnly(false);
73       }
74     }
75 
76     // Update the buffer create flags.
77     Result r =
78         transfer_resources[amber_buffer]->AsTransferBuffer()->AddUsageFlags(
79             flags);
80     if (!r.IsSuccess())
81       return r;
82   }
83   is_descriptor_set_update_needed_ = true;
84 
85   descriptor_offsets_.reserve(GetAmberBuffers().size());
86   descriptor_ranges_.reserve(GetAmberBuffers().size());
87 
88   return {};
89 }
90 
UpdateDescriptorSetIfNeeded(VkDescriptorSet descriptor_set)91 void BufferDescriptor::UpdateDescriptorSetIfNeeded(
92     VkDescriptorSet descriptor_set) {
93   if (!is_descriptor_set_update_needed_)
94     return;
95 
96   std::vector<VkDescriptorBufferInfo> buffer_infos;
97   std::vector<VkBufferView> buffer_views;
98 
99   // Create VkDescriptorBufferInfo for every descriptor buffer.
100   for (uint32_t i = 0; i < GetAmberBuffers().size(); i++) {
101     const auto& buffer =
102         pipeline_->GetDescriptorTransferResources()[GetAmberBuffers()[i]]
103             ->AsTransferBuffer();
104     assert(buffer->GetVkBuffer() && "Unexpected descriptor type");
105     // Add buffer infos for uniform and storage buffers.
106     if (IsUniformBuffer() || IsUniformBufferDynamic() || IsStorageBuffer() ||
107         IsStorageBufferDynamic()) {
108       uint64_t range = descriptor_ranges_[i];
109       // If dynamic offset is used, we must change range with VK_WHOLE_SIZE to
110       // an actual range.
111       // From vulkan spec: For each dynamic uniform or storage buffer binding in
112       // pDescriptorSets, the sum of the effective offset, as defined above, and
113       // the range of the binding must be less than or equal to the size of the
114       // buffer.
115       if ((IsUniformBufferDynamic() || IsStorageBufferDynamic()) &&
116           descriptor_ranges_[i] == VK_WHOLE_SIZE) {
117         range = buffer->GetSizeInBytes() - dynamic_offsets_[i] -
118                 descriptor_offsets_[i];
119       }
120 
121       VkDescriptorBufferInfo buffer_info;
122       buffer_info.buffer = buffer->GetVkBuffer();
123       buffer_info.offset = descriptor_offsets_[i];
124       buffer_info.range = range;
125 
126       buffer_infos.push_back(buffer_info);
127     }
128 
129     if (IsUniformTexelBuffer() || IsStorageTexelBuffer()) {
130       buffer_views.push_back(*buffer->GetVkBufferView());
131     }
132   }
133 
134   VkWriteDescriptorSet write = VkWriteDescriptorSet();
135   write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
136   write.dstSet = descriptor_set;
137   write.dstBinding = binding_;
138   write.dstArrayElement = 0;
139   write.descriptorCount = static_cast<uint32_t>(GetAmberBuffers().size());
140   write.descriptorType = GetVkDescriptorType();
141   write.pBufferInfo = buffer_infos.data();
142   write.pTexelBufferView = buffer_views.data();
143 
144   device_->GetPtrs()->vkUpdateDescriptorSets(device_->GetVkDevice(), 1, &write,
145                                              0, nullptr);
146   is_descriptor_set_update_needed_ = false;
147 }
148 
149 }  // namespace vulkan
150 }  // namespace amber
151