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/vertex_buffer.h"
16
17 #include <cassert>
18 #include <cstring>
19
20 #include "src/make_unique.h"
21 #include "src/vulkan/command_buffer.h"
22 #include "src/vulkan/device.h"
23
24 namespace amber {
25 namespace vulkan {
26 namespace {
27
GetVkInputRate(InputRate rate)28 VkVertexInputRate GetVkInputRate(InputRate rate) {
29 return rate == InputRate::kVertex ? VK_VERTEX_INPUT_RATE_VERTEX
30 : VK_VERTEX_INPUT_RATE_INSTANCE;
31 }
32
33 } // namespace
34
VertexBuffer(Device * device)35 VertexBuffer::VertexBuffer(Device* device) : device_(device) {}
36
37 VertexBuffer::~VertexBuffer() = default;
38
SetData(uint8_t location,Buffer * buffer,InputRate rate,Format * format,uint32_t offset,uint32_t stride)39 void VertexBuffer::SetData(uint8_t location,
40 Buffer* buffer,
41 InputRate rate,
42 Format* format,
43 uint32_t offset,
44 uint32_t stride) {
45 const uint32_t binding = static_cast<uint32_t>(vertex_attr_desc_.size());
46 vertex_attr_desc_.emplace_back();
47 vertex_attr_desc_.back().binding = binding;
48 vertex_attr_desc_.back().location = location;
49 vertex_attr_desc_.back().offset = offset;
50 vertex_attr_desc_.back().format = device_->GetVkFormat(*format);
51
52 vertex_binding_desc_.emplace_back();
53 vertex_binding_desc_.back().binding = binding;
54 vertex_binding_desc_.back().stride = stride;
55 vertex_binding_desc_.back().inputRate = GetVkInputRate(rate);
56
57 data_.push_back(buffer);
58 }
59
BindToCommandBuffer(CommandBuffer * command)60 void VertexBuffer::BindToCommandBuffer(CommandBuffer* command) {
61 std::vector<VkBuffer> buffers;
62 std::vector<VkDeviceSize> offsets;
63
64 for (const auto& buf : data_) {
65 buffers.push_back(buffer_to_vk_buffer_[buf]);
66 offsets.push_back(0);
67 }
68 device_->GetPtrs()->vkCmdBindVertexBuffers(
69 command->GetVkCommandBuffer(), 0, static_cast<uint32_t>(buffers.size()),
70 buffers.data(), offsets.data());
71 }
72
SendVertexData(CommandBuffer * command)73 Result VertexBuffer::SendVertexData(CommandBuffer* command) {
74 if (!is_vertex_data_pending_)
75 return Result("Vulkan::Vertices data was already sent");
76
77 buffer_to_vk_buffer_.clear();
78
79 for (const auto& buf : data_) {
80 if (buffer_to_vk_buffer_.count(buf) != 0) {
81 continue;
82 }
83
84 // Create a new transfer buffer to hold vertex data.
85 uint32_t bytes = buf->GetSizeInBytes();
86 transfer_buffers_.push_back(
87 MakeUnique<TransferBuffer>(device_, bytes, nullptr));
88 Result r = transfer_buffers_.back()->Initialize(
89 VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT);
90
91 std::memcpy(transfer_buffers_.back()->HostAccessibleMemoryPtr(),
92 buf->GetValues<void>(), bytes);
93 transfer_buffers_.back()->CopyToDevice(command);
94
95 if (!r.IsSuccess())
96 return r;
97
98 buffer_to_vk_buffer_[buf] = transfer_buffers_.back()->GetVkBuffer();
99 }
100
101 is_vertex_data_pending_ = false;
102 return {};
103 }
104
105 } // namespace vulkan
106 } // namespace amber
107