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