vOOlkan
An object oriented approach to Vulkan
DynamicSet.h
Go to the documentation of this file.
1#ifndef VULKAN_DYNAMICSET
2#define VULKAN_DYNAMICSET
3
4#include <glm/glm.hpp>
5#include <tuple>
6#include <concepts>
7#include <type_traits>
8
9#include "UniformBuffer.h"
10#include "LogicalDevice.h"
11#include "PhysicalDevice.h"
12#include "Set.h"
13
14
15namespace Vulkan {
16
23 class DynamicSet : public Set {
24 public:
25
29 struct DynamicSetBindingInfo : public Set::BindingInfo {
30 DynamicSetBindingInfo(int size, const Buffers::UniformBuffer& buffer, int offset, int dynamicDistance = 0) : size{ size }, buffer{ buffer }, offset{ offset }, dynamicDistance{ dynamicDistance }{}
31
39 DescriptorSetBindingCreationInfo generateDescriptorSetBindingInfo(const VkDescriptorSet& descriptorSet) const override {
40 return DescriptorSetBindingCreationInfo{ binding, descriptorSet, size, buffer, offset, dynamicDistance };
41 }
42
46 int size;
50 const Buffers::UniformBuffer& buffer;
54 int offset;
58 int dynamicDistance;
59 };
60
61
73 template<typename... Structs, template<typename, typename>class... Bindings> requires (std::same_as<Bindings<VkShaderStageFlagBits, Structs>, std::pair<VkShaderStageFlagBits, Structs>> && ...)
74 DynamicSet(const PhysicalDevice& realGpu, const LogicalDevice& virtualGpu, const Buffers::UniformBuffer& buffer, Bindings<VkShaderStageFlagBits, Structs>... bindings) : Set{ virtualGpu } {
75 //get minimum alignment for the GPU memory, used for padding
76 int alignment = realGpu.getProperties().limits.minUniformBufferOffsetAlignment;
77 int currentOffset = 0;
78
79 //for each binding
80 ([this, &currentOffset, &buffer, alignment](std::pair<VkShaderStageFlagBits, Structs> binding) {
81 //allocate the binding info on the heap (we need a pointer for polymorphism)
82 auto tmp = std::make_unique<DynamicSetBindingInfo>(sizeof(binding.second), buffer, currentOffset);
83 bindingsPerBuffer[&buffer].push_back(tmp.get()); //add a pointer to this info struct in the right array (see comment next to the definition of this variable)
84 this->bindingsInfo.push_back(std::move(tmp)); //put the binding info in the binding info vector
85
86 currentOffset += sizeof(binding.second); //increase the offset in the buffer by the size of the last binding
87 int paddingAmount = (alignment - (currentOffset % alignment)) % alignment; //number of padding bytes
88 currentOffset += paddingAmount; //add the padding bytes to the offset. e.g. offset = 253, padding bytes = 3 ( (253+3) % 16 = 0, 16 is often the required alignment)
89 }(bindings), ...);
90
91 //the dynamic distance for bindings allocated in this way is always the same and equal to the total size of the bindings
92 for (int i = 0; i < bindingsInfo.size(); ++i) {
93 static_cast<DynamicSetBindingInfo*>(bindingsInfo[i].get())->dynamicDistance = currentOffset;
94 bindingsInfo[i].get()->binding = i; //also set the binding index
95 }
96
97 //create the Vulkan layout struct used during pipeline creation
98 createDescriptorSetLayout(std::pair{ bindings.first, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC }...);
99 }
100
101
102
114 template<typename... Structs, typename... T> requires
115 (std::same_as<T, std::tuple<VkShaderStageFlagBits, Structs, Buffers::UniformBuffer*, int, int>> && ...)
116 DynamicSet(const LogicalDevice& virtualGpu, T... bindingsInfo) : Set{ virtualGpu } {
117 //for each binding...
118 ([this](T bindingInfo) {
119 //allocate the binding info on the heap (we need a pointer for polymorphism)
120 auto tmp = std::make_unique<DynamicSetBindingInfo>(sizeof(std::get<1>(bindingsInfo)), *std::get<2>(bindingsInfo), std::get<3>(bindingsInfo), std::get<4>(bindingsInfo));
121 bindingsPerBuffer[&(tmp->buffer)].push_back(tmp.get()); //add a pointer to this info struct in the right array (see comment next to the definition of this variable)
122 tmp->binding = bindingsInfo.size(); //set the index of this binding
123 this->bindingsInfo.push_back(std::move(tmp)); //add the pointer to the vector of binding info
124 }(bindingsInfo), ...);
125
126 //create the Vulkan layout struct used during pipeline creation
127 createDescriptorSetLayout(std::pair{ std::get<0>(bindingsInfo), VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC }...);
128 }
129
130
131
142 std::vector<uint32_t> getDynamicDistances(int i = 0) const {
143 std::vector<uint32_t> res;
144
145 for (const auto& binding : bindingsInfo) {
146 res.push_back(static_cast<DynamicSetBindingInfo*>(binding.get())->dynamicDistance * i);
147 }
148
149 return res;
150 }
151
152
166 template<typename... Bindings, template<typename...>class... T> requires (std::same_as<std::tuple<Bindings...>, T<Bindings...>> && ...)
167 void fillBuffer(Buffers::UniformBuffer& buffer, const T<Bindings...>&... tuplesOfData) const {
168 fillBufferHelper(buffer, std::make_integer_sequence<int, sizeof...(Bindings)>{}, tuplesOfData...);
169 }
170
171
172
173 private:
174
175 //This function is used to perform a sort of constexpr for each loop on the tuple
176 template<int... TI, typename... T>
177 void fillBufferHelper(Buffers::UniformBuffer& buffer, std::integer_sequence<int, TI...>, const T&... tuplesOfData) const {
178 std::vector<DynamicSetBindingInfo*> bindingsInfo;
179 try {
180 bindingsInfo = bindingsPerBuffer.at(&buffer); //get the info of the bindings of the buffer
181 }
182 catch (const std::out_of_range&) {
183 throw VulkanException{ "Failed to fill the uniform buffer", "The buffer to be filled isn't used in this set" };
184 }
185 int counter = 0; //how many tuple we've already traversed
186
187 //Basically the n - th element of the m - th tuple will be inserted in position : offset[n] + dynamicDistance[n] * m
188 ([&bindingsInfo, &counter, &buffer](const T& tuple) {
189 (buffer.fillBuffer(std::get<TI>(tuple), bindingsInfo[TI]->offset + bindingsInfo[TI]->dynamicDistance * counter), ...);
190 counter++;
191 }(tuplesOfData), ...);
192 }
193
194
195 std::map<const Buffers::UniformBuffer*, std::vector<DynamicSetBindingInfo*>> bindingsPerBuffer; //this map holds the bindings relative to each buffer used in the Set
196
197 };
198
199}
200
201
202
203#endif
Types of queue families.
Definition: Animations.h:17