source: opengl-game/graphics-pipeline_vulkan.hpp@ 6385d0f

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

In GraphicsPipeline_Vulkan, change addStorageDescriptor() to take a parameter indicating the shader stage, and add an updateObjectVertices() method

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