source: opengl-game/graphics-pipeline_vulkan.hpp@ a3cefaa

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

Move SSBO resizing and pipeline recreation checks out of addObject() and into updateScene() so that those operations are only done at most once per pipeline per frame, using vkUpdateDescriptorSets() instead of recreating the whole graphics pipeline, and create a VulkanBuffer class for managing data related to uniform buffers and shader storage buffers, move objectCapacity and numObjects out of GraphicsPipeline_vulkan and use VulkanBuffer to manage them instead

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