Cogs.Core
BuffersVK.cpp
1#include "BuffersVK.h"
2
3#include "GraphicsDeviceVK.h"
4
5#include "EffectsVK.h"
6#include "FormatsVK.h"
7
8namespace
9{
10 Cogs::Logging::Log logger = Cogs::Logging::getLogger("BuffersVK");
11}
12
13Cogs::BufferPageVK::BufferPageVK(BufferContextVK & context, size_t pageSize)
14{
15 VkBufferCreateInfo bufferInfo = {};
16 bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
17 bufferInfo.pNext = nullptr;
18 bufferInfo.size = context.elementSize * pageSize;
19 bufferInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
20 bufferInfo.flags = 0;
21
22 VkMemoryAllocateInfo allocateInfo = {};
23 allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
24 allocateInfo.pNext = nullptr;
25 allocateInfo.allocationSize = 0;
26 allocateInfo.memoryTypeIndex = 0;
27
28 auto result = vkCreateBuffer(context.device, &bufferInfo, nullptr, &buffer);
29
30 if (VK_FAILED(result)) {
31 VK_LOG_ERROR(result, "Could not create buffer.");
32 return;
33 }
34
35 VkMemoryRequirements memoryRequirements;
36 vkGetBufferMemoryRequirements(context.device, buffer, &memoryRequirements);
37 assert(!result);
38
39 allocateInfo.allocationSize = memoryRequirements.size;
40 auto pass = context.graphicsDevice->getMemoryType(memoryRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, &allocateInfo.memoryTypeIndex);
41 assert(pass);
42
43 result = vkAllocateMemory(context.device, &allocateInfo, nullptr, &deviceMemory);
44 assert(!result);
45
46 result = vkBindBufferMemory(context.device, buffer, deviceMemory, 0);
47
48 // Resize the backing store of the page to hold pageSize number of elements.
49 storage.resize(sizeof(PoolBufferVK) * pageSize);
50
51 auto head = reinterpret_cast<PoolBufferVK *>(storage.data());
52
53 vkMapMemory(context.device, deviceMemory, 0, memoryRequirements.size, 0, ((void **)&mappedRegion));
54
55 // Initialize the linked list of elements chaining all elements in the page together.
56 for (size_t i = 0; i < pageSize; ++i) {
57 PoolBufferVK * block = head + i;
58
59 auto offset = i * context.elementSize;
60 block->mappedRegion = mappedRegion + offset;
61 block->pool = context.pool;
62 block->offset = offset;
63 block->size = context.elementSize;
64 block->buffer = buffer;
65
66 block->next = block + 1;
67 }
68
69 (head + pageSize - 1)->next = nullptr;
70}
71
72#define VERTEX_BUFFER_BIND_ID 0
73
74void Cogs::BuffersVK::initialize(GraphicsDeviceVK * graphicsDevice)
75{
76 pool256.initialize(graphicsDevice, graphicsDevice->device, 1, 256, 1024);
77 pool1024.initialize(graphicsDevice, graphicsDevice->device, 1, 1024, 256);
78}
79
80Cogs::VertexBufferHandle Cogs::BuffersVK::loadVertexBuffer(const void * vertexData, const size_t count, const VertexFormat & vertexFormat)
81{
82 const uint32_t vertexSize = getSize(vertexFormat);
83 const size_t size = vertexSize * count;
84
85 auto handle = loadBuffer(vertexData, size, Usage::Dynamic, AccessMode::Write, BindFlags::VertexBuffer);
86
87 auto & buffer = buffers[handle];
88
89 auto hashCode = getHash(vertexFormat);
90 assert(hashCode);
91
92 auto vIt = vertexFormats.find(hashCode);
93
94 if (vIt != vertexFormats.end()) {
95 buffer.vertexFormat = &vIt->second;
96 } else {
97 buffer.vertexFormat = &(vertexFormats[hashCode] = vertexFormat);
98 }
99
100 return handle;
101}
102
103Cogs::VertexBufferHandle Cogs::BuffersVK::loadVertexBuffer(const void * vertexData, const size_t count, VertexFormatHandle vertexFormatHandle)
104{
105 assert(false);
107}
108
110{
111 assert(false);
112}
113
114Cogs::IndexBufferHandle Cogs::BuffersVK::loadIndexBuffer(const void * indexData, const size_t count, const size_t indexSize)
115{
116 auto handle = loadBuffer(indexData, count * indexSize, Usage::Dynamic, AccessMode::Write, BindFlags::IndexBuffer);
117
118 auto & buffer = buffers[handle];
119
120 buffer.size = count;
121 buffer.indexSize = indexSize;
122
123 return handle;
124}
125
127{
128}
129
130namespace
131{
132 const char * Semantics[] = {
133 "POSITION",
134 "NORMAL",
135 "COLOR",
136 "TEXCOORD",
137 "TANGENT",
138 "INSTANCEVECTOR",
139 "INSTANCEMATRIX",
140 };
141
142 const uint32_t NoRegister = ~0ul;
143}
144
145Cogs::InputLayoutHandle Cogs::BuffersVK::loadInputLayout(const VertexFormatHandle * vertexFormats, const size_t count, EffectHandle effectHandle)
146{
147 if (!HandleIsValid(effectHandle)) {
148 LOG_ERROR(logger, "Cannot create input layout for invalid effect.");
150 }
151
152 auto handle = inputLayouts.addResource(InputLayoutVK{});
153 auto & inputLayout = inputLayouts[handle];
154
155 auto findSemantic = [&](const char * semantic, size_t index = 0) -> uint32_t
156 {
157 auto & effect = graphicsDevice->effects.effects[effectHandle];
158
159 for (auto & ia : effect.vertexShader.reflection.inputAttributes) {
160 if (ia.semantic == semantic && ia.index == index) return ia.reg;
161 }
162
163 return NoRegister;
164 };
165
166 size_t attribCount = 0;
167 for (size_t i = 0; i < count; ++i) {
168 const VertexFormat *format = getVertexFormat(vertexFormats[i]);
169 for (size_t j = 0; j < format->elements.size(); ++j) {
170 auto & element = format->elements[j];
171
172 if (findSemantic(Semantics[(size_t)element.semantic], element.semanticIndex) == NoRegister) continue;
173
174 if (format->elements[j].semantic == ElementSemantic::InstanceVector) {
175 attribCount += 4;
176 } else {
177 ++attribCount;
178 }
179 }
180 }
181
182 inputLayout.vertexInputBinding.resize(count);
183 inputLayout.vertexInputAttribs.resize(attribCount);
184
185 inputLayout.vertexInputState.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
186 inputLayout.vertexInputState.pNext = nullptr;
187 inputLayout.vertexInputState.vertexBindingDescriptionCount = static_cast<uint32_t>(count);
188 inputLayout.vertexInputState.pVertexBindingDescriptions = inputLayout.vertexInputBinding.data();
189 inputLayout.vertexInputState.vertexAttributeDescriptionCount = static_cast<uint32_t>(attribCount);
190 inputLayout.vertexInputState.pVertexAttributeDescriptions = inputLayout.vertexInputAttribs.data();
191
192 for (uint32_t i = 0; i < count; ++i) {
193 const VertexFormat *format = getVertexFormat(vertexFormats[i]);
194 inputLayout.vertexInputBinding[i].binding = i;
195 inputLayout.vertexInputBinding[i].stride = getSize(*format);
196 inputLayout.vertexInputBinding[i].inputRate = format->elements.front().inputType == InputType::VertexData ? VK_VERTEX_INPUT_RATE_VERTEX : VK_VERTEX_INPUT_RATE_INSTANCE;
197 }
198
199 uint32_t location = 0;
200
201 for (uint32_t i = 0; i < count; ++i) {
202 const VertexFormat &format = *getVertexFormat(vertexFormats[i]);
203 for (auto & element : format.elements) {
204 auto reg = findSemantic(Semantics[(size_t)element.semantic], element.semanticIndex);
205
206 if (reg == NoRegister) continue;
207
208 if (element.semantic == ElementSemantic::InstanceMatrix) {
209 for (uint32_t j = 0; j < 4; ++j) {
210 inputLayout.vertexInputAttribs[location].binding = i;
211 inputLayout.vertexInputAttribs[location].location = reg + j;
212 inputLayout.vertexInputAttribs[location].format = Vulkan::TextureFormats[(size_t)element.format];
213 inputLayout.vertexInputAttribs[location].offset = element.offset + 16 * j;
214
215 ++location;
216 }
217 } else {
218 inputLayout.vertexInputAttribs[location].binding = i;
219 inputLayout.vertexInputAttribs[location].location = reg;
220 inputLayout.vertexInputAttribs[location].format = Vulkan::TextureFormats[(size_t)element.format];
221 inputLayout.vertexInputAttribs[location].offset = element.offset;
222
223 ++location;
224 }
225 }
226 }
227
228 return handle;
229}
230
232{
233 inputLayouts.removeResource(inputLayoutHandle);
234}
235
236Cogs::BufferHandle Cogs::BuffersVK::loadBuffer(const void * data, const size_t size, Usage::EUsage usage, uint32_t accessMode, uint32_t bindFlags, uint32_t stride)
237{
238 BufferVK buffer = {};
239 buffer.bindFlags = (BindFlags::EBindFlags)bindFlags;
240
241 VkBufferUsageFlags usageFlags = 0;
242
243 if (bindFlags == BindFlags::VertexBuffer) {
244 usageFlags |= VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
245 } else if (bindFlags == BindFlags::IndexBuffer) {
246 usageFlags |= VK_BUFFER_USAGE_INDEX_BUFFER_BIT;
247 } else if (bindFlags == BindFlags::ConstantBuffer) {
248 usageFlags |= VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
249 }
250
251 if (usage == Usage::Staging && (accessMode & AccessMode::Read) != 0) {
252 usageFlags |= VK_BUFFER_USAGE_TRANSFER_DST_BIT;
253 } else if (usage == Usage::Staging && (accessMode & AccessMode::Write) != 0) {
254 usageFlags |= VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
255 }
256
257 if (bindFlags == BindFlags::ConstantBuffer && size < 256) {
258 buffer.poolBuffer = pool256.allocate();
259 buffer.bufferInfo.buffer = buffer.poolBuffer->buffer;
260 buffer.bufferInfo.offset = buffer.poolBuffer->offset;
261 buffer.bufferInfo.range = buffer.poolBuffer->size;
262
263 return buffers.addResource(buffer);
264 } else if (bindFlags == BindFlags::ConstantBuffer && size < 1024) {
265 buffer.poolBuffer = pool1024.allocate();
266 buffer.bufferInfo.buffer = buffer.poolBuffer->buffer;
267 buffer.bufferInfo.offset = buffer.poolBuffer->offset;
268 buffer.bufferInfo.range = buffer.poolBuffer->size;
269
270 return buffers.addResource(buffer);
271 }
272
273 VkBufferCreateInfo bufferInfo = {};
274 bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
275 bufferInfo.pNext = nullptr;
276 bufferInfo.size = size;
277 bufferInfo.usage = usageFlags;
278 bufferInfo.flags = 0;
279
280 VkMemoryAllocateInfo allocateInfo = {};
281 allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
282 allocateInfo.pNext = nullptr;
283 allocateInfo.allocationSize = 0;
284 allocateInfo.memoryTypeIndex = 0;
285
286 auto result = vkCreateBuffer(graphicsDevice->device, &bufferInfo, nullptr, &buffer.buffer);
287
288 if (VK_FAILED(result)) {
289 VK_LOG_ERROR(result, "Could not create buffer.");
291 }
292
293 VkMemoryRequirements memoryRequirements;
294 vkGetBufferMemoryRequirements(graphicsDevice->device, buffer.buffer, &memoryRequirements);
295 assert(!result);
296
297 buffer.size = memoryRequirements.size;
298
299 allocateInfo.allocationSize = memoryRequirements.size;
300 auto pass = graphicsDevice->getMemoryType(memoryRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, &allocateInfo.memoryTypeIndex);
301 assert(pass);
302
303 result = vkAllocateMemory(graphicsDevice->device, &allocateInfo, nullptr, &buffer.deviceMemory);
304 assert(!result);
305
306 if (data) {
307 void * mappedMemory;
308 result = vkMapMemory(graphicsDevice->device, buffer.deviceMemory, 0, allocateInfo.allocationSize, 0, &mappedMemory);
309
310 assert(!result);
311
312 std::memcpy(mappedMemory, data, size);
313
314 vkUnmapMemory(graphicsDevice->device, buffer.deviceMemory);
315 }
316
317 buffer.bufferInfo.buffer = buffer.buffer;
318 buffer.bufferInfo.offset = 0;
319 buffer.bufferInfo.range = size;
320
321 result = vkBindBufferMemory(graphicsDevice->device, buffer.buffer, buffer.deviceMemory, 0);
322
323 return buffers.addResource(buffer);
324}
325
326void Cogs::BuffersVK::retrieveSubBuffer(void * data, BufferHandle source, const size_t offset, const size_t size)
327{
328 assert(false);
329}
330
332{
333 assert(false);
334}
335
337{
338 return (void*)(buffers[bufferHandle].buffer);
339}
340
342{
343 assert(false);
344}
void releaseVertexBuffer(VertexBufferHandle vertexBufferHandle) override
Release the vertex buffer with the given handle.
Definition: BuffersVK.cpp:109
BufferHandle loadBuffer(const void *data, const size_t size, Usage::EUsage usage, uint32_t accessMode, uint32_t bindFlags, uint32_t stride=0) override
Loads a new buffer using the given data to populate the buffer.
Definition: BuffersVK.cpp:236
void releaseBuffer(BufferHandle bufferHandle) override
Releases the buffer with the given bufferHandle.
Definition: BuffersVK.cpp:331
VertexBufferHandle loadVertexBuffer(const void *vertexData, const size_t count, const VertexFormat &vertexFormat) override
Loads a new vertex buffer and populates it with the given data.
Definition: BuffersVK.cpp:80
void releaseInputLayout(InputLayoutHandle inputLayoutHandle) override
Releases the input layout with the given inputLayoutHandle.
Definition: BuffersVK.cpp:231
IndexBufferHandle loadIndexBuffer(const void *indexData, const size_t count, const size_t indexSize) override
Loads a new index buffer and populates it with the given indexData.
Definition: BuffersVK.cpp:114
void releaseIndexBuffer(IndexBufferHandle indexBufferHandle) override
Releases the index buffer with the given handle.
Definition: BuffersVK.cpp:126
void retrieveSubBuffer(void *data, BufferHandle source, const size_t offset, const size_t size) override
Retrieves the contents of a buffer.
Definition: BuffersVK.cpp:326
void * getNativeHandle(BufferHandle bufferHandle) override
Get the device-specific handle (D3D buffer pointer, OpenGL buffer ID etc) associated with the given b...
Definition: BuffersVK.cpp:336
void releaseResources() override
Releases all allocated buffer resources.
Definition: BuffersVK.cpp:341
InputLayoutHandle loadInputLayout(const VertexFormatHandle *vertexFormats, const size_t count, EffectHandle effectHandle) override
Loads a new input layout to map vertex flow between vertex buffers with the given vertexFormats to ef...
Definition: BuffersVK.cpp:145
Log implementation class.
Definition: LogManager.h:139
constexpr Log getLogger(const char(&name)[LEN]) noexcept
Definition: LogManager.h:180
@ VertexData
Per vertex data.
@ InstanceMatrix
Instance matrix semantic.
@ InstanceVector
Instance vector semantic.
@ Read
The buffer can be mapped and read from by the CPU after creation.
Definition: Flags.h:48
@ Write
The buffer can be mapped and written to by the CPU after creation.
Definition: Flags.h:50
EBindFlags
Bind flags enumeration.
Definition: Flags.h:64
@ ConstantBuffer
The buffer can be bound as input to effects as a constant buffer.
Definition: Flags.h:72
@ VertexBuffer
The buffer can be bound as input to the vertex shader stage as a vertex buffer.
Definition: Flags.h:68
@ IndexBuffer
The buffer can be bound as input to the vertex shader stage as an index buffer.
Definition: Flags.h:70
static const Handle_t NoHandle
Represents a handle to nothing.
Definition: Common.h:77
static const Handle_t InvalidHandle
Represents an invalid handle.
Definition: Common.h:80
EUsage
Usage enumeration.
Definition: Flags.h:24
@ Dynamic
Buffer will be loaded and modified with some frequency.
Definition: Flags.h:30
@ Staging
Definition: Flags.h:33
Vertex format structure used to describe a single vertex for the input assembler.
Definition: VertexFormat.h:60
std::vector< VertexElement > elements
Vector containing all vertex elements of this format.
Definition: VertexFormat.h:62