source: opengl-game/graphics-pipeline_vulkan.hpp@ 2ba5617

feature/imgui-sdl points-test
Last change on this file since 2ba5617 was 44f23af, checked in by Dmitry Portnoy <dmitry.portnoy@…>, 5 years ago

In VulkanGame, add code to resize the storage buffer and update the right descriptor info when the storage buffer becomes full

  • Property mode set to 100644
File size: 28.1 KB
Line 
1#ifndef _GRAPHICS_PIPELINE_VULKAN_H
2#define _GRAPHICS_PIPELINE_VULKAN_H
3
4#include "graphics-pipeline.hpp"
5
6#include <fstream>
7#include <iostream>
8#include <stdexcept>
9#include <vector>
10
11#include <vulkan/vulkan.h>
12
13#define GLM_FORCE_RADIANS
14#define GLM_FORCE_DEPTH_ZERO_TO_ONE // Since, in Vulkan, the depth range is 0 to 1 instead of -1 to 1
15#define GLM_FORCE_RIGHT_HANDED
16
17#include <glm/glm.hpp>
18#include <glm/gtc/matrix_transform.hpp>
19
20#include "vulkan-utils.hpp"
21
22using namespace glm;
23
24// TODO: Maybe change the name of this struct so I can call the list something other than descriptorInfoList
25struct DescriptorInfo {
26 VkDescriptorType type;
27 VkShaderStageFlags stageFlags;
28
29 // Only one of the below properties should be set
30 vector<VkDescriptorBufferInfo>* bufferDataList;
31 VkDescriptorImageInfo* imageData;
32};
33
34struct StorageBufferSet {
35 vector<VkBuffer> buffers;
36 vector<VkDeviceMemory> memory;
37 vector<VkDescriptorBufferInfo> infoSet;
38};
39
40template<class VertexType, class SSBOType>
41class GraphicsPipeline_Vulkan : public GraphicsPipeline {
42 public:
43 string vertShaderFile, fragShaderFile;
44
45 GraphicsPipeline_Vulkan();
46
47 // TODO: swapChainImages is only ever used to get its size. Check how that is determined and,
48 // if it will never change, just pass it in the constructor and save it
49 // If it does change, I could add an updateSwapchainImageCount() function
50 GraphicsPipeline_Vulkan(VkPhysicalDevice physicalDevice, VkDevice device, VkRenderPass renderPass,
51 Viewport viewport, vector<VkImage>& swapChainImages,
52 size_t vertexCapacity, size_t indexCapacity, size_t objectCapacity);
53 ~GraphicsPipeline_Vulkan();
54
55 size_t getNumVertices();
56
57 void updateRenderPass(VkRenderPass renderPass);
58
59 // Maybe I should rename these to addVertexAttribute (addVaryingAttribute) and addUniformAttribute
60
61 void addAttribute(VkFormat format, size_t offset);
62
63 void addStorageDescriptor();
64
65 void addDescriptorInfo(VkDescriptorType type, VkShaderStageFlags stageFlags, vector<VkDescriptorBufferInfo>* bufferData);
66 void addDescriptorInfo(VkDescriptorType type, VkShaderStageFlags stageFlags, VkDescriptorImageInfo* imageData);
67
68 void createPipeline(string vertShaderFile, string fragShaderFile);
69 void createDescriptorSetLayout();
70 void createDescriptorPool(vector<VkImage>& swapChainImages);
71 void createDescriptorSets(vector<VkImage>& swapChainImages);
72
73 void createRenderCommands(VkCommandBuffer& commandBuffer, uint32_t currentImage);
74
75 bool addObject(const vector<VertexType>& vertices, vector<uint16_t> indices, SSBOType& ssbo,
76 VkCommandPool commandPool, VkQueue graphicsQueue);
77
78 void updateObject(size_t objIndex, SSBOType& ssbo);
79
80 void cleanup();
81 void cleanupBuffers();
82
83 private:
84 VkPhysicalDevice physicalDevice;
85 VkDevice device;
86 VkRenderPass renderPass;
87
88 VkPipeline pipeline;
89 VkPipelineLayout pipelineLayout;
90
91 VkVertexInputBindingDescription bindingDescription;
92
93 vector<VkVertexInputAttributeDescription> attributeDescriptions;
94 vector<DescriptorInfo> descriptorInfoList;
95
96 VkDescriptorSetLayout descriptorSetLayout;
97 VkDescriptorPool descriptorPool;
98 vector<VkDescriptorSet> descriptorSets;
99
100 size_t numVertices;
101 size_t vertexCapacity;
102 VkBuffer vertexBuffer;
103 VkDeviceMemory vertexBufferMemory;
104
105 size_t numIndices;
106 size_t indexCapacity;
107 VkBuffer indexBuffer;
108 VkDeviceMemory indexBufferMemory;
109
110 size_t numObjects;
111 size_t objectCapacity;
112
113 StorageBufferSet storageBufferSet;
114
115 VkShaderModule createShaderModule(const vector<char>& code);
116 vector<char> readFile(const string& filename);
117
118 void resizeVertexBuffer(VkCommandPool commandPool, VkQueue graphicsQueue);
119 void resizeIndexBuffer(VkCommandPool commandPool, VkQueue graphicsQueue);
120 void resizeStorageBufferSet(StorageBufferSet& set, VkCommandPool commandPool, VkQueue graphicsQueue);
121};
122
123/*** PUBLIC METHODS ***/
124
125template<class VertexType, class SSBOType>
126GraphicsPipeline_Vulkan<VertexType, SSBOType>::GraphicsPipeline_Vulkan() {
127}
128
129// TODO: Verify that vertex capacity and index capacity are both > 0
130// TODO: See if it would be feasible to move code in the createPipeline method
131// into the constructor. That way, I can also put relevant cleanup code into the destructor
132template<class VertexType, class SSBOType>
133GraphicsPipeline_Vulkan<VertexType, SSBOType>::GraphicsPipeline_Vulkan(
134 VkPhysicalDevice physicalDevice, VkDevice device,
135 VkRenderPass renderPass, Viewport viewport, vector<VkImage>& swapChainImages,
136 size_t vertexCapacity, size_t indexCapacity, size_t objectCapacity) {
137 this->physicalDevice = physicalDevice;
138 this->device = device;
139 this->renderPass = renderPass;
140 this->viewport = viewport;
141
142 // Since there is only one array of vertex data, we use binding = 0
143 // I'll probably do that for the foreseeable future
144 // I can calculate the stride myself given info about all the varying attributes
145 this->bindingDescription.binding = 0;
146 this->bindingDescription.stride = sizeof(VertexType);
147 this->bindingDescription.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
148
149 this->numVertices = 0;
150 this->vertexCapacity = vertexCapacity;
151
152 VulkanUtils::createBuffer(device, physicalDevice, vertexCapacity * sizeof(VertexType),
153 VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
154 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, vertexBuffer, vertexBufferMemory);
155
156 this->numIndices = 0;
157 this->indexCapacity = indexCapacity;
158
159 VulkanUtils::createBuffer(device, physicalDevice, indexCapacity * sizeof(uint16_t),
160 VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT,
161 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, indexBuffer, indexBufferMemory);
162
163 this->numObjects = 0;
164 this->objectCapacity = objectCapacity;
165
166 // Hacky way to allow an SSBO to be optional
167 // Specifying void* as the SSBOType will skip allocating the related buffers
168 if (!is_same_v<SSBOType, void*>) {
169 VkDeviceSize bufferSize = objectCapacity * sizeof(SSBOType);
170 cout << "NUM SWAP CHAIN IMAGES: " << swapChainImages.size() << endl;
171
172 storageBufferSet.buffers.resize(swapChainImages.size());
173 storageBufferSet.memory.resize(swapChainImages.size());
174 storageBufferSet.infoSet.resize(swapChainImages.size());
175
176 for (size_t i = 0; i < swapChainImages.size(); i++) {
177 VulkanUtils::createBuffer(this->device, this->physicalDevice, bufferSize,
178 VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
179 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
180 storageBufferSet.buffers[i], storageBufferSet.memory[i]);
181
182 storageBufferSet.infoSet[i].buffer = storageBufferSet.buffers[i];
183 storageBufferSet.infoSet[i].offset = 0; // This is the offset from the start of the buffer, so always 0 for now
184 storageBufferSet.infoSet[i].range = bufferSize; // Size of the update starting from offset, or VK_WHOLE_SIZE
185 }
186 }
187}
188
189// TODO: Move as much cleanup as I can into the destructor
190template<class VertexType, class SSBOType>
191GraphicsPipeline_Vulkan<VertexType, SSBOType>::~GraphicsPipeline_Vulkan() {
192}
193
194template<class VertexType, class SSBOType>
195size_t GraphicsPipeline_Vulkan<VertexType, SSBOType>::getNumVertices() {
196 return numVertices;
197}
198
199template<class VertexType, class SSBOType>
200void GraphicsPipeline_Vulkan<VertexType, SSBOType>::updateRenderPass(VkRenderPass renderPass) {
201 this->renderPass = renderPass;
202}
203
204template<class VertexType, class SSBOType>
205void GraphicsPipeline_Vulkan<VertexType, SSBOType>::addAttribute(VkFormat format, size_t offset) {
206 VkVertexInputAttributeDescription attributeDesc = {};
207
208 attributeDesc.binding = 0;
209 attributeDesc.location = this->attributeDescriptions.size();
210 attributeDesc.format = format;
211 attributeDesc.offset = offset;
212
213 this->attributeDescriptions.push_back(attributeDesc);
214}
215
216template<class VertexType, class SSBOType>
217void GraphicsPipeline_Vulkan<VertexType, SSBOType>::addStorageDescriptor() {
218 if (!is_same_v<SSBOType, void*>) {
219 addDescriptorInfo(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
220 VK_SHADER_STAGE_VERTEX_BIT, &storageBufferSet.infoSet);
221 }
222}
223
224template<class VertexType, class SSBOType>
225void GraphicsPipeline_Vulkan<VertexType, SSBOType>::addDescriptorInfo(VkDescriptorType type,
226 VkShaderStageFlags stageFlags, vector<VkDescriptorBufferInfo>* bufferData) {
227 this->descriptorInfoList.push_back({ type, stageFlags, bufferData, nullptr });
228}
229
230template<class VertexType, class SSBOType>
231void GraphicsPipeline_Vulkan<VertexType, SSBOType>::addDescriptorInfo(VkDescriptorType type,
232 VkShaderStageFlags stageFlags, VkDescriptorImageInfo* imageData) {
233 this->descriptorInfoList.push_back({ type, stageFlags, nullptr, imageData });
234}
235
236template<class VertexType, class SSBOType>
237void GraphicsPipeline_Vulkan<VertexType, SSBOType>::createPipeline(string vertShaderFile, string fragShaderFile) {
238 this->vertShaderFile = vertShaderFile;
239 this->fragShaderFile = fragShaderFile;
240
241 vector<char> vertShaderCode = readFile(vertShaderFile);
242 vector<char> fragShaderCode = readFile(fragShaderFile);
243
244 VkShaderModule vertShaderModule = createShaderModule(vertShaderCode);
245 VkShaderModule fragShaderModule = createShaderModule(fragShaderCode);
246
247 VkPipelineShaderStageCreateInfo vertShaderStageInfo = {};
248 vertShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
249 vertShaderStageInfo.stage = VK_SHADER_STAGE_VERTEX_BIT;
250 vertShaderStageInfo.module = vertShaderModule;
251 vertShaderStageInfo.pName = "main";
252
253 VkPipelineShaderStageCreateInfo fragShaderStageInfo = {};
254 fragShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
255 fragShaderStageInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
256 fragShaderStageInfo.module = fragShaderModule;
257 fragShaderStageInfo.pName = "main";
258
259 VkPipelineShaderStageCreateInfo shaderStages[] = { vertShaderStageInfo, fragShaderStageInfo };
260
261 VkPipelineVertexInputStateCreateInfo vertexInputInfo = {};
262 vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
263
264 vertexInputInfo.vertexBindingDescriptionCount = 1;
265 vertexInputInfo.vertexAttributeDescriptionCount = static_cast<uint32_t>(this->attributeDescriptions.size());
266 vertexInputInfo.pVertexBindingDescriptions = &this->bindingDescription;
267 vertexInputInfo.pVertexAttributeDescriptions = this->attributeDescriptions.data();
268
269 VkPipelineInputAssemblyStateCreateInfo inputAssembly = {};
270 inputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
271 inputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
272 inputAssembly.primitiveRestartEnable = VK_FALSE;
273
274 VkViewport viewport = {};
275 viewport.x = (float)this->viewport.x;
276 viewport.y = (float)this->viewport.y;
277 viewport.width = (float)this->viewport.width;
278 viewport.height = (float)this->viewport.height;
279 viewport.minDepth = 0.0f;
280 viewport.maxDepth = 1.0f;
281
282 VkRect2D scissor = {};
283 scissor.offset = { 0, 0 };
284 scissor.extent = { (uint32_t)this->viewport.width, (uint32_t)this->viewport.height };
285
286 VkPipelineViewportStateCreateInfo viewportState = {};
287 viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
288 viewportState.viewportCount = 1;
289 viewportState.pViewports = &viewport;
290 viewportState.scissorCount = 1;
291 viewportState.pScissors = &scissor;
292
293 VkPipelineRasterizationStateCreateInfo rasterizer = {};
294 rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
295 rasterizer.depthClampEnable = VK_FALSE;
296 rasterizer.rasterizerDiscardEnable = VK_FALSE;
297 rasterizer.polygonMode = VK_POLYGON_MODE_FILL;
298 rasterizer.lineWidth = 1.0f;
299 rasterizer.cullMode = VK_CULL_MODE_BACK_BIT;
300 rasterizer.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
301 rasterizer.depthBiasEnable = VK_FALSE;
302
303 VkPipelineMultisampleStateCreateInfo multisampling = {};
304 multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
305 multisampling.sampleShadingEnable = VK_FALSE;
306 multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
307
308 VkPipelineColorBlendAttachmentState colorBlendAttachment = {};
309 colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
310 colorBlendAttachment.blendEnable = VK_TRUE;
311 colorBlendAttachment.colorBlendOp = VK_BLEND_OP_ADD;
312 colorBlendAttachment.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
313 colorBlendAttachment.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
314 colorBlendAttachment.alphaBlendOp = VK_BLEND_OP_ADD;
315 colorBlendAttachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
316 colorBlendAttachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
317
318 VkPipelineColorBlendStateCreateInfo colorBlending = {};
319 colorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
320 colorBlending.logicOpEnable = VK_FALSE;
321 colorBlending.logicOp = VK_LOGIC_OP_COPY;
322 colorBlending.attachmentCount = 1;
323 colorBlending.pAttachments = &colorBlendAttachment;
324 colorBlending.blendConstants[0] = 0.0f;
325 colorBlending.blendConstants[1] = 0.0f;
326 colorBlending.blendConstants[2] = 0.0f;
327 colorBlending.blendConstants[3] = 0.0f;
328
329 VkPipelineDepthStencilStateCreateInfo depthStencil = {};
330 depthStencil.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
331 depthStencil.depthTestEnable = VK_TRUE;
332 depthStencil.depthWriteEnable = VK_TRUE;
333 depthStencil.depthCompareOp = VK_COMPARE_OP_LESS;
334 depthStencil.depthBoundsTestEnable = VK_FALSE;
335 depthStencil.minDepthBounds = 0.0f;
336 depthStencil.maxDepthBounds = 1.0f;
337 depthStencil.stencilTestEnable = VK_FALSE;
338 depthStencil.front = {};
339 depthStencil.back = {};
340
341 VkPipelineLayoutCreateInfo pipelineLayoutInfo = {};
342 pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
343 pipelineLayoutInfo.setLayoutCount = 1;
344 pipelineLayoutInfo.pSetLayouts = &this->descriptorSetLayout;
345 pipelineLayoutInfo.pushConstantRangeCount = 0;
346
347 if (vkCreatePipelineLayout(this->device, &pipelineLayoutInfo, nullptr, &this->pipelineLayout) != VK_SUCCESS) {
348 throw runtime_error("failed to create pipeline layout!");
349 }
350
351 VkGraphicsPipelineCreateInfo pipelineInfo = {};
352 pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
353 pipelineInfo.stageCount = 2;
354 pipelineInfo.pStages = shaderStages;
355 pipelineInfo.pVertexInputState = &vertexInputInfo;
356 pipelineInfo.pInputAssemblyState = &inputAssembly;
357 pipelineInfo.pViewportState = &viewportState;
358 pipelineInfo.pRasterizationState = &rasterizer;
359 pipelineInfo.pMultisampleState = &multisampling;
360 pipelineInfo.pDepthStencilState = &depthStencil;
361 pipelineInfo.pColorBlendState = &colorBlending;
362 pipelineInfo.pDynamicState = nullptr;
363 pipelineInfo.layout = this->pipelineLayout;
364 pipelineInfo.renderPass = this->renderPass;
365 pipelineInfo.subpass = 0;
366 pipelineInfo.basePipelineHandle = VK_NULL_HANDLE;
367 pipelineInfo.basePipelineIndex = -1;
368
369 if (vkCreateGraphicsPipelines(this->device, VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &this->pipeline) != VK_SUCCESS) {
370 throw runtime_error("failed to create graphics pipeline!");
371 }
372
373 vkDestroyShaderModule(this->device, vertShaderModule, nullptr);
374 vkDestroyShaderModule(this->device, fragShaderModule, nullptr);
375}
376
377template<class VertexType, class SSBOType>
378void GraphicsPipeline_Vulkan<VertexType, SSBOType>::createDescriptorSetLayout() {
379 vector<VkDescriptorSetLayoutBinding> bindings(this->descriptorInfoList.size());
380
381 for (size_t i = 0; i < bindings.size(); i++) {
382 bindings[i].binding = i;
383 bindings[i].descriptorCount = 1;
384 bindings[i].descriptorType = this->descriptorInfoList[i].type;
385 bindings[i].stageFlags = this->descriptorInfoList[i].stageFlags;
386 bindings[i].pImmutableSamplers = nullptr;
387 }
388
389 VkDescriptorSetLayoutCreateInfo layoutInfo = {};
390 layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
391 layoutInfo.bindingCount = static_cast<uint32_t>(bindings.size());
392 layoutInfo.pBindings = bindings.data();
393
394 if (vkCreateDescriptorSetLayout(this->device, &layoutInfo, nullptr, &this->descriptorSetLayout) != VK_SUCCESS) {
395 throw runtime_error("failed to create descriptor set layout!");
396 }
397}
398
399template<class VertexType, class SSBOType>
400void GraphicsPipeline_Vulkan<VertexType, SSBOType>::createDescriptorPool(vector<VkImage>& swapChainImages) {
401 vector<VkDescriptorPoolSize> poolSizes(this->descriptorInfoList.size());
402
403 for (size_t i = 0; i < poolSizes.size(); i++) {
404 poolSizes[i].type = this->descriptorInfoList[i].type;
405 poolSizes[i].descriptorCount = static_cast<uint32_t>(swapChainImages.size());
406 }
407
408 VkDescriptorPoolCreateInfo poolInfo = {};
409 poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
410 poolInfo.poolSizeCount = static_cast<uint32_t>(poolSizes.size());
411 poolInfo.pPoolSizes = poolSizes.data();
412 poolInfo.maxSets = static_cast<uint32_t>(swapChainImages.size());
413
414 if (vkCreateDescriptorPool(this->device, &poolInfo, nullptr, &this->descriptorPool) != VK_SUCCESS) {
415 throw runtime_error("failed to create descriptor pool!");
416 }
417}
418
419// TODO: Since I only need the size of the swapChainImages array, I should just pass that in instead of the whole array
420template<class VertexType, class SSBOType>
421void GraphicsPipeline_Vulkan<VertexType, SSBOType>::createDescriptorSets(vector<VkImage>& swapChainImages) {
422 vector<VkDescriptorSetLayout> layouts(swapChainImages.size(), this->descriptorSetLayout);
423
424 VkDescriptorSetAllocateInfo allocInfo = {};
425 allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
426 allocInfo.descriptorPool = this->descriptorPool;
427 allocInfo.descriptorSetCount = static_cast<uint32_t>(swapChainImages.size());
428 allocInfo.pSetLayouts = layouts.data();
429
430 this->descriptorSets.resize(swapChainImages.size());
431 if (vkAllocateDescriptorSets(device, &allocInfo, this->descriptorSets.data()) != VK_SUCCESS) {
432 throw runtime_error("failed to allocate descriptor sets!");
433 }
434
435 for (size_t i = 0; i < swapChainImages.size(); i++) {
436 vector<VkWriteDescriptorSet> descriptorWrites(this->descriptorInfoList.size());
437
438 for (size_t j = 0; j < descriptorWrites.size(); j++) {
439 descriptorWrites[j].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
440 descriptorWrites[j].dstSet = this->descriptorSets[i];
441 descriptorWrites[j].dstBinding = j;
442 descriptorWrites[j].dstArrayElement = 0;
443 descriptorWrites[j].descriptorType = this->descriptorInfoList[j].type;
444 descriptorWrites[j].descriptorCount = 1;
445 descriptorWrites[j].pBufferInfo = nullptr;
446 descriptorWrites[j].pImageInfo = nullptr;
447 descriptorWrites[j].pTexelBufferView = nullptr;
448
449 switch (descriptorWrites[j].descriptorType) {
450 case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
451 case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
452 descriptorWrites[j].pBufferInfo = &(*this->descriptorInfoList[j].bufferDataList)[i];
453 break;
454 case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
455 descriptorWrites[j].pImageInfo = this->descriptorInfoList[j].imageData;
456 break;
457 default:
458 throw runtime_error("Unknown descriptor type: " + to_string(descriptorWrites[j].descriptorType));
459 }
460 }
461
462 vkUpdateDescriptorSets(this->device, static_cast<uint32_t>(descriptorWrites.size()), descriptorWrites.data(), 0, nullptr);
463 }
464}
465
466template<class VertexType, class SSBOType>
467void GraphicsPipeline_Vulkan<VertexType, SSBOType>::createRenderCommands(VkCommandBuffer& commandBuffer,
468 uint32_t currentImage) {
469 vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
470 vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1,
471 &descriptorSets[currentImage], 0, nullptr);
472
473 VkBuffer vertexBuffers[] = { vertexBuffer };
474 VkDeviceSize offsets[] = { 0 };
475 vkCmdBindVertexBuffers(commandBuffer, 0, 1, vertexBuffers, offsets);
476
477 vkCmdBindIndexBuffer(commandBuffer, indexBuffer, 0, VK_INDEX_TYPE_UINT16);
478
479 vkCmdDrawIndexed(commandBuffer, static_cast<uint32_t>(numIndices), 1, 0, 0, 0);
480}
481
482template<class VertexType, class SSBOType>
483bool GraphicsPipeline_Vulkan<VertexType, SSBOType>::addObject(
484 const vector<VertexType>& vertices, vector<uint16_t> indices,
485 SSBOType& ssbo, VkCommandPool commandPool, VkQueue graphicsQueue) {
486
487 // TODO: When resizing the vertex or index buffer, take deleted objects into account.
488 // Remove their data from the buffer and determine the new size of the bufer based on # of remining objects
489
490 // If # non-deleted objects > currentCapacity / 2
491 // - resize and double capacity
492 // else If # non-deleted objects < currentCapacity / 4
493 // - resize amd halve capacity
494 // else
495 // - don't resize, but rewrite data in the buffer to only have non-deleted objects
496
497 if (numVertices + vertices.size() > vertexCapacity) {
498 resizeVertexBuffer(commandPool, graphicsQueue);
499 }
500 VulkanUtils::copyDataToBuffer(device, physicalDevice, commandPool, vertices, vertexBuffer, numVertices,
501 graphicsQueue);
502 numVertices += vertices.size();
503
504 if (numIndices + indices.size() > indexCapacity) {
505 resizeIndexBuffer(commandPool, graphicsQueue);
506 }
507 VulkanUtils::copyDataToBuffer(device, physicalDevice, commandPool, indices, indexBuffer, numIndices,
508 graphicsQueue);
509 numIndices += indices.size();
510
511 bool resizedStorageBuffer = false;
512
513 if (!is_same_v<SSBOType, void*>) {
514 if (this->numObjects == this->objectCapacity) {
515 resizeStorageBufferSet(storageBufferSet, commandPool, graphicsQueue);
516 cleanup();
517
518 // Assume the SSBO is always the 2nd binding
519 this->descriptorInfoList[1].bufferDataList = &storageBufferSet.infoSet;
520 resizedStorageBuffer = true;
521
522 cout << "SSBO resized, New object capacity: " << this->objectCapacity << endl;
523
524 // TODO: I'll need to correctly update the descriptor set array instead of appending to it
525 // Then, I'll have to call createDescriptorSets() and finally createCommandBuffers() (from vulkan-game)
526 // This isn't too bad actually, since I have to call createCommandBuffers() every time I add a newobject
527 // anyway. So, in this function, I'll just have to call createDescriptorSets()
528 }
529
530 updateObject(this->numObjects, ssbo);
531 }
532
533 this->numObjects++;
534
535 return resizedStorageBuffer;
536}
537
538template<class VertexType, class SSBOType>
539void GraphicsPipeline_Vulkan<VertexType, SSBOType>::updateObject(size_t objIndex, SSBOType& ssbo) {
540 if (!is_same_v<SSBOType, void*>) {
541 for (size_t i = 0; i < storageBufferSet.memory.size(); i++) {
542 VulkanUtils::copyDataToMemory(device, storageBufferSet.memory[i], objIndex, ssbo);
543 }
544 }
545}
546
547template<class VertexType, class SSBOType>
548void GraphicsPipeline_Vulkan<VertexType, SSBOType>::cleanup() {
549 vkDestroyPipeline(device, pipeline, nullptr);
550 vkDestroyDescriptorPool(device, descriptorPool, nullptr);
551
552 // TODO: I read that the pipeline layout does not have to be recreated every time
553 // Try only creating it once
554 vkDestroyPipelineLayout(device, pipelineLayout, nullptr);
555}
556
557template<class VertexType, class SSBOType>
558void GraphicsPipeline_Vulkan<VertexType, SSBOType>::cleanupBuffers() {
559 vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr);
560
561 vkDestroyBuffer(device, vertexBuffer, nullptr);
562 vkFreeMemory(device, vertexBufferMemory, nullptr);
563 vkDestroyBuffer(device, indexBuffer, nullptr);
564 vkFreeMemory(device, indexBufferMemory, nullptr);
565
566 if (!is_same_v<SSBOType, void*>) {
567 for (size_t i = 0; i < storageBufferSet.buffers.size(); i++) {
568 vkDestroyBuffer(device, storageBufferSet.buffers[i], nullptr);
569 vkFreeMemory(device, storageBufferSet.memory[i], nullptr);
570 }
571 }
572}
573
574/*** PRIVATE METHODS ***/
575
576template<class VertexType, class SSBOType>
577VkShaderModule GraphicsPipeline_Vulkan<VertexType, SSBOType>::createShaderModule(const vector<char>& code) {
578 VkShaderModuleCreateInfo createInfo = {};
579 createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
580 createInfo.codeSize = code.size();
581 createInfo.pCode = reinterpret_cast<const uint32_t*>(code.data());
582
583 VkShaderModule shaderModule;
584 if (vkCreateShaderModule(this->device, &createInfo, nullptr, &shaderModule) != VK_SUCCESS) {
585 throw runtime_error("failed to create shader module!");
586 }
587
588 return shaderModule;
589}
590
591template<class VertexType, class SSBOType>
592vector<char> GraphicsPipeline_Vulkan<VertexType, SSBOType>::readFile(const string& filename) {
593 ifstream file(filename, ios::ate | ios::binary);
594
595 if (!file.is_open()) {
596 throw runtime_error("failed to open file!");
597 }
598
599 size_t fileSize = (size_t)file.tellg();
600 vector<char> buffer(fileSize);
601
602 file.seekg(0);
603 file.read(buffer.data(), fileSize);
604
605 file.close();
606
607 return buffer;
608}
609
610template<class VertexType, class SSBOType>
611void GraphicsPipeline_Vulkan<VertexType, SSBOType>::resizeVertexBuffer(VkCommandPool commandPool,
612 VkQueue graphicsQueue) {
613 VkBuffer newVertexBuffer;
614 VkDeviceMemory newVertexBufferMemory;
615 this->vertexCapacity *= 2;
616
617 VulkanUtils::createBuffer(this->device, this->physicalDevice, this->vertexCapacity * sizeof(VertexType),
618 VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
619 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, newVertexBuffer, newVertexBufferMemory);
620
621 VulkanUtils::copyBuffer(this->device, commandPool, vertexBuffer, newVertexBuffer, 0, 0, numVertices * sizeof(VertexType), graphicsQueue);
622
623 vkDestroyBuffer(this->device, vertexBuffer, nullptr);
624 vkFreeMemory(this->device, vertexBufferMemory, nullptr);
625
626 vertexBuffer = newVertexBuffer;
627 vertexBufferMemory = newVertexBufferMemory;
628}
629
630template<class VertexType, class SSBOType>
631void GraphicsPipeline_Vulkan<VertexType, SSBOType>::resizeIndexBuffer(VkCommandPool commandPool,
632 VkQueue graphicsQueue) {
633 VkBuffer newIndexBuffer;
634 VkDeviceMemory newIndexBufferMemory;
635 this->indexCapacity *= 2;
636
637 VulkanUtils::createBuffer(this->device, this->physicalDevice, this->indexCapacity * sizeof(uint16_t),
638 VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT,
639 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, newIndexBuffer, newIndexBufferMemory);
640
641 VulkanUtils::copyBuffer(this->device, commandPool, indexBuffer, newIndexBuffer, 0, 0, numIndices * sizeof(uint16_t), graphicsQueue);
642
643 vkDestroyBuffer(this->device, indexBuffer, nullptr);
644 vkFreeMemory(this->device, indexBufferMemory, nullptr);
645
646 indexBuffer = newIndexBuffer;
647 indexBufferMemory = newIndexBufferMemory;
648}
649
650template<class VertexType, class SSBOType>
651void GraphicsPipeline_Vulkan<VertexType, SSBOType>::resizeStorageBufferSet(StorageBufferSet& set,
652 VkCommandPool commandPool, VkQueue graphicsQueue) {
653 this->objectCapacity *= 2;
654 VkDeviceSize bufferSize = objectCapacity * sizeof(SSBOType);
655
656 for (size_t i = 0; i < set.buffers.size(); i++) {
657 VkBuffer newStorageBuffer;
658 VkDeviceMemory newStorageBufferMemory;
659
660 VulkanUtils::createBuffer(this->device, this->physicalDevice, bufferSize,
661 VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
662 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
663 newStorageBuffer, newStorageBufferMemory);
664
665 VulkanUtils::copyBuffer(this->device, commandPool, set.buffers[i], newStorageBuffer,
666 0, 0, this->numObjects * sizeof(SSBOType), graphicsQueue);
667
668 vkDestroyBuffer(this->device, set.buffers[i], nullptr);
669 vkFreeMemory(this->device, set.memory[i], nullptr);
670
671 set.buffers[i] = newStorageBuffer;
672 set.memory[i] = newStorageBufferMemory;
673
674 set.infoSet[i].buffer = set.buffers[i];
675 set.infoSet[i].offset = 0; // This is the offset from the start of the buffer, so always 0 for now
676 set.infoSet[i].range = bufferSize; // Size of the update starting from offset, or VK_WHOLE_SIZE
677 }
678}
679
680#endif // _GRAPHICS_PIPELINE_VULKAN_H
Note: See TracBrowser for help on using the repository browser.