source: opengl-game/vulkan-buffer.hpp@ 6486ba8

feature/imgui-sdl
Last change on this file since 6486ba8 was 6486ba8, checked in by Dmitry Portnoy <dportnoy@…>, 5 years ago

Rewrite some parts of SDLGame and VulkanGame to store per-object buffer object
data contiguously and copied to the GPU in one call

  • Property mode set to 100644
File size: 5.2 KB
RevLine 
[a3cefaa]1#ifndef _VULKAN_BUFFER_H
2#define _VULKAN_BUFFER_H
3
4/*
5* This class is intended to be used with Storage Buffers and Uniform Buffers.
6*/
7
8template<class T>
9class VulkanBuffer {
10
11 public:
12
[8dcbf62]13 // TODO: Make these private (maybe make a getter for numObjects)
14 // Externally, they are only used in resizeBufferSet
[a3cefaa]15 size_t capacity;
[6bac215]16
17 // temp field to help with ubo+ssbo resizing until they are added to this class
18 // See if I need a separate field for this or if I can use other fields to check for this
19 // Maybe compare uniform or storage buffer size to the size of the memory allocated here
20 bool resized;
[a3cefaa]21
22 VulkanBuffer();
[b7fc3c2]23 VulkanBuffer(size_t capacity, size_t range, size_t minOffsetAlignment);
[6bac215]24
25 VulkanBuffer(const VulkanBuffer<T>&) = delete;
26 VulkanBuffer(VulkanBuffer<T>&& other);
27
[a3cefaa]28 ~VulkanBuffer();
29
[6bac215]30 VulkanBuffer<T>& operator=(const VulkanBuffer<T>&) = delete;
31 VulkanBuffer<T>& operator=(VulkanBuffer<T>&& other) noexcept;
32
33 void resize();
[a3cefaa]34
[6486ba8]35 T& get(uint32_t index);
[8dcbf62]36 void add(T obj);
[a3cefaa]37
[b7fc3c2]38 size_t memorySize();
[1abebc1]39
[a3cefaa]40 private:
41
[8dcbf62]42 size_t alignment;
[b7fc3c2]43 size_t range;
[6486ba8]44 //size_t capacity;
[6bac215]45 size_t numObjects;
[8dcbf62]46
[6486ba8]47 T* rawData;
48 vector<void*> mappedData;
[b7fc3c2]49
50 size_t memRequirement(size_t capacity);
[6486ba8]51 size_t memOffset(uint32_t index);
[a3cefaa]52};
53
54// Currently, for SSBOs, I store the per-object values (usually just the model matrix), on each object, so they
55// are not in their own array and therefore cannot be pushed to the GPU as one block. The updates must happen
56// separately per object.
57
58// Since Sascha WIllems' dynamic UBO example works the same way (iirc), I can implement dynamic UBOs like that as well
59// for now. Would be nice to plan for potentially storing the ubo data on the CPU in a contiguous block in the future,
60// assuming that would make updates easier. Keep in mind that this only makes sense if all or most of the objects
61// in the ubo get updated every frame.
62
63// ============================= TODO: Also, check when it makes sense to have a staging buffer for copying data to the GPU
64// and see if I actually need to use it everywhere I currently am. I think this is mentioned in Sascha WIllems dubo example
65// or some other Vulkan website I recently bookmarked
66
67template<class T>
68VulkanBuffer<T>::VulkanBuffer()
69 : alignment(0)
[b7fc3c2]70 , range(0)
[a3cefaa]71 , capacity(0)
72 , numObjects(0)
[6bac215]73 , resized(false)
[a3cefaa]74 , rawData(nullptr)
[6486ba8]75 , mappedData() {
[a3cefaa]76}
77
78template<class T>
[b7fc3c2]79VulkanBuffer<T>::VulkanBuffer(size_t capacity, size_t range, size_t minOffsetAlignment)
80 : alignment(range)
81 , range(range / sizeof(T))
[a3cefaa]82 , capacity(capacity)
83 , numObjects(0)
[6bac215]84 , resized(false)
[a3cefaa]85 , rawData(nullptr)
[6486ba8]86 , mappedData() {
[a3cefaa]87 if (minOffsetAlignment > 0) {
88 alignment = (alignment + minOffsetAlignment - 1) & ~(minOffsetAlignment - 1);
89 }
90
[6486ba8]91 rawData = (T*)malloc(memRequirement(capacity));
[a3cefaa]92}
93
[6bac215]94template<class T>
95VulkanBuffer<T>::VulkanBuffer(VulkanBuffer<T>&& other) {
96 // TODO: Implement
97}
98
[a3cefaa]99template<class T>
100VulkanBuffer<T>::~VulkanBuffer() {
[6486ba8]101 if (rawData != nullptr) {
102 free(rawData);
[a3cefaa]103 }
104}
105
106template<class T>
[6bac215]107VulkanBuffer<T>& VulkanBuffer<T>::operator=(VulkanBuffer<T>&& other) noexcept {
108 if (this != &other) {
109 capacity = other.capacity;
110 numObjects = other.numObjects;
111 resized = other.resized;
[a3cefaa]112
[6bac215]113 alignment = other.alignment;
[b7fc3c2]114 range = other.range;
[a3cefaa]115
[6486ba8]116 if (rawData != nullptr) {
117 free(rawData);
[6bac215]118 }
[a3cefaa]119
[6486ba8]120 rawData = other.rawData;
[a3cefaa]121
[6bac215]122 other.capacity = 0;
123 other.numObjects = 0;
[b7fc3c2]124 other.range = 0;
[a3cefaa]125
[6486ba8]126 other.rawData = nullptr;
[6bac215]127 }
[a3cefaa]128
129 return *this;
130}
131
[6bac215]132template<class T>
133void VulkanBuffer<T>::resize() {
134 resized = false;
135}
136
[6486ba8]137template<class T>
138T& VulkanBuffer<T>::get(uint32_t index) {
139 // TODO: Check that index < numObjects
140
141 T* obj = (T*)((size_t)rawData + memOffset(index));
142 return *obj;
143}
144
[a3cefaa]145template<class T>
[8dcbf62]146void VulkanBuffer<T>::add(T obj) {
[6bac215]147 if (numObjects == capacity) {
148 // Once I add Vulkan buffer objects in here, make sure this doesn't overlap with resizeBufferSet
149 resized = true;
150
[6486ba8]151 size_t oldMemReq = memRequirement(capacity);
152
[6bac215]153 capacity *= 2;
[6486ba8]154
155 size_t newMemReq = memRequirement(capacity);
156
157 T* newData = (T*)malloc(newMemReq);
158 // TODO: Check for failure
159
160 memcpy(newData, rawData, oldMemReq);
161
162 free(rawData);
163 rawData = newData;
[6bac215]164 }
165
[6486ba8]166 T* ptr = (T*)((size_t)rawData + memOffset(numObjects));
167 *ptr = obj;
168
[8dcbf62]169 numObjects++;
[a3cefaa]170}
171
[b7fc3c2]172template<class T>
173size_t VulkanBuffer<T>::memorySize() {
174 return memRequirement(capacity);
175}
176
177template<class T>
178size_t VulkanBuffer<T>::memRequirement(size_t capacity) {
179 return (capacity / range) * alignment + (capacity % range) * sizeof(T);
180}
181
[6486ba8]182template<class T>
183size_t VulkanBuffer<T>::memOffset(uint32_t index) {
184 return (index / range) * alignment + (index % range) * sizeof(T);
185}
186
[a3cefaa]187#endif // _VULKAN_BUFFER_H
Note: See TracBrowser for help on using the repository browser.