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 <cassert>
19 #include <cstring>
20 #include <utility>
21 #include <vector>
22
23 #include "src/engine.h"
24 #include "src/make_unique.h"
25 #include "src/vulkan/command_buffer.h"
26 #include "src/vulkan/device.h"
27
28 namespace amber {
29 namespace vulkan {
30
BufferDescriptor(Buffer * buffer,DescriptorType type,Device * device,uint32_t desc_set,uint32_t binding)31 BufferDescriptor::BufferDescriptor(Buffer* buffer,
32 DescriptorType type,
33 Device* device,
34 uint32_t desc_set,
35 uint32_t binding)
36 : device_(device),
37 amber_buffer_(buffer),
38 type_(type),
39 descriptor_set_(desc_set),
40 binding_(binding) {}
41
42 BufferDescriptor::~BufferDescriptor() = default;
43
CreateResourceIfNeeded()44 Result BufferDescriptor::CreateResourceIfNeeded() {
45 if (transfer_buffer_) {
46 return Result(
47 "Vulkan: BufferDescriptor::CreateResourceIfNeeded() must be called "
48 "only when |transfer_buffer| is empty");
49 }
50
51 if (amber_buffer_ && amber_buffer_->ValuePtr()->empty())
52 return {};
53
54 uint32_t size_in_bytes =
55 amber_buffer_ ? static_cast<uint32_t>(amber_buffer_->ValuePtr()->size())
56 : 0;
57 transfer_buffer_ = MakeUnique<TransferBuffer>(device_, size_in_bytes);
58
59 Result r = transfer_buffer_->Initialize(
60 (IsStorageBuffer() ? VK_BUFFER_USAGE_STORAGE_BUFFER_BIT
61 : VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT) |
62 VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT);
63 if (!r.IsSuccess())
64 return r;
65
66 is_descriptor_set_update_needed_ = true;
67 return {};
68 }
69
RecordCopyDataToResourceIfNeeded(CommandBuffer * command)70 void BufferDescriptor::RecordCopyDataToResourceIfNeeded(
71 CommandBuffer* command) {
72 if (!transfer_buffer_)
73 return;
74
75 if (amber_buffer_ && !amber_buffer_->ValuePtr()->empty()) {
76 transfer_buffer_->UpdateMemoryWithRawData(*amber_buffer_->ValuePtr());
77 amber_buffer_->ValuePtr()->clear();
78 }
79
80 transfer_buffer_->CopyToDevice(command);
81 }
82
RecordCopyDataToHost(CommandBuffer * command)83 Result BufferDescriptor::RecordCopyDataToHost(CommandBuffer* command) {
84 if (!transfer_buffer_) {
85 return Result(
86 "Vulkan: BufferDescriptor::RecordCopyDataToHost() no transfer buffer");
87 }
88
89 transfer_buffer_->CopyToHost(command);
90 return {};
91 }
92
MoveResourceToBufferOutput()93 Result BufferDescriptor::MoveResourceToBufferOutput() {
94 if (!transfer_buffer_) {
95 return Result(
96 "Vulkan: BufferDescriptor::MoveResourceToBufferOutput() no transfer"
97 " buffer");
98 }
99
100 // Only need to copy the buffer back if we have an attached amber buffer to
101 // write too.
102 if (amber_buffer_) {
103 void* resource_memory_ptr = transfer_buffer_->HostAccessibleMemoryPtr();
104 if (!resource_memory_ptr) {
105 return Result(
106 "Vulkan: BufferDescriptor::MoveResourceToBufferOutput() "
107 "no host accessible memory pointer");
108 }
109
110 if (!amber_buffer_->ValuePtr()->empty()) {
111 return Result(
112 "Vulkan: BufferDescriptor::MoveResourceToBufferOutput() "
113 "output buffer is not empty");
114 }
115
116 auto size_in_bytes = transfer_buffer_->GetSizeInBytes();
117 amber_buffer_->SetElementCount(size_in_bytes /
118 amber_buffer_->GetFormat()->SizeInBytes());
119 amber_buffer_->ValuePtr()->resize(size_in_bytes);
120 std::memcpy(amber_buffer_->ValuePtr()->data(), resource_memory_ptr,
121 size_in_bytes);
122 }
123
124 transfer_buffer_ = nullptr;
125 return {};
126 }
127
UpdateDescriptorSetIfNeeded(VkDescriptorSet descriptor_set)128 void BufferDescriptor::UpdateDescriptorSetIfNeeded(
129 VkDescriptorSet descriptor_set) {
130 if (!is_descriptor_set_update_needed_)
131 return;
132
133 VkDescriptorBufferInfo buffer_info = VkDescriptorBufferInfo();
134 buffer_info.buffer = transfer_buffer_->GetVkBuffer();
135 buffer_info.offset = 0;
136 buffer_info.range = VK_WHOLE_SIZE;
137
138 VkWriteDescriptorSet write = VkWriteDescriptorSet();
139 write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
140 write.dstSet = descriptor_set;
141 write.dstBinding = binding_;
142 write.dstArrayElement = 0;
143 write.descriptorCount = 1;
144 write.descriptorType = IsStorageBuffer() ? VK_DESCRIPTOR_TYPE_STORAGE_BUFFER
145 : VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
146 write.pBufferInfo = &buffer_info;
147
148 device_->GetPtrs()->vkUpdateDescriptorSets(device_->GetVkDevice(), 1, &write,
149 0, nullptr);
150 is_descriptor_set_update_needed_ = false;
151 }
152
SetSizeInElements(uint32_t element_count)153 Result BufferDescriptor::SetSizeInElements(uint32_t element_count) {
154 if (!amber_buffer_)
155 return Result("missing amber_buffer for SetSizeInElements call");
156
157 amber_buffer_->SetSizeInElements(element_count);
158 return {};
159 }
160
AddToBuffer(const std::vector<Value> & values,uint32_t offset)161 Result BufferDescriptor::AddToBuffer(const std::vector<Value>& values,
162 uint32_t offset) {
163 if (!amber_buffer_)
164 return Result("missing amber_buffer for AddToBuffer call");
165
166 return amber_buffer_->SetDataWithOffset(values, offset);
167 }
168
GetVkDescriptorType() const169 VkDescriptorType BufferDescriptor::GetVkDescriptorType() const {
170 return IsStorageBuffer() ? VK_DESCRIPTOR_TYPE_STORAGE_BUFFER
171 : VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
172 }
173
174 } // namespace vulkan
175 } // namespace amber
176