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

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

In VulkanGame, move the logic of updating per-object data in the SSBO into GraphicsPipeline_Vulkan and remove the SSBO properties from VulkanGame

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