source: opengl-game/graphics-pipeline_vulkan.hpp@ 1abebc1

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

Remove the storageBuffers parameter from addObject() since it is no longer used, rename StorageBufferSet, resizeStorageBufferSet(), and updateStorageuffer() to BufferSet, resizeBufferSet(), and updateBufferSet() respectively, and change updateObject() to just take a SceneObject reference.

  • Property mode set to 100644
File size: 26.7 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 // TODO: Instead, assert that (bufferData->size() == swapChainImages.size()
240 if (bufferData->size() != swapChainImages.size()) {
241 cout << "ALERT ALERT ALERT: SIZE MISMATCH!!!!!!!" << endl;
242 }
243
244 vkUpdateDescriptorSets(this->device, 1, &descriptorWrite, 0, nullptr);
245 }
246}
247
248template<class VertexType>
249void GraphicsPipeline_Vulkan<VertexType>::createPipeline(string vertShaderFile, string fragShaderFile) {
250 this->vertShaderFile = vertShaderFile;
251 this->fragShaderFile = fragShaderFile;
252
253 vector<char> vertShaderCode = readFile(vertShaderFile);
254 vector<char> fragShaderCode = readFile(fragShaderFile);
255
256 VkShaderModule vertShaderModule = createShaderModule(vertShaderCode);
257 VkShaderModule fragShaderModule = createShaderModule(fragShaderCode);
258
259 VkPipelineShaderStageCreateInfo vertShaderStageInfo = {};
260 vertShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
261 vertShaderStageInfo.stage = VK_SHADER_STAGE_VERTEX_BIT;
262 vertShaderStageInfo.module = vertShaderModule;
263 vertShaderStageInfo.pName = "main";
264
265 VkPipelineShaderStageCreateInfo fragShaderStageInfo = {};
266 fragShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
267 fragShaderStageInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
268 fragShaderStageInfo.module = fragShaderModule;
269 fragShaderStageInfo.pName = "main";
270
271 VkPipelineShaderStageCreateInfo shaderStages[] = { vertShaderStageInfo, fragShaderStageInfo };
272
273 VkPipelineVertexInputStateCreateInfo vertexInputInfo = {};
274 vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
275
276 vertexInputInfo.vertexBindingDescriptionCount = 1;
277 vertexInputInfo.vertexAttributeDescriptionCount = static_cast<uint32_t>(this->attributeDescriptions.size());
278 vertexInputInfo.pVertexBindingDescriptions = &this->bindingDescription;
279 vertexInputInfo.pVertexAttributeDescriptions = this->attributeDescriptions.data();
280
281 VkPipelineInputAssemblyStateCreateInfo inputAssembly = {};
282 inputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
283 inputAssembly.topology = this->topology;
284 inputAssembly.primitiveRestartEnable = VK_FALSE;
285
286 VkViewport viewport = {};
287 viewport.x = (float)this->viewport.x;
288 viewport.y = (float)this->viewport.y;
289 viewport.width = (float)this->viewport.width;
290 viewport.height = (float)this->viewport.height;
291 viewport.minDepth = 0.0f;
292 viewport.maxDepth = 1.0f;
293
294 VkRect2D scissor = {};
295 scissor.offset = { 0, 0 };
296 scissor.extent = { (uint32_t)this->viewport.width, (uint32_t)this->viewport.height };
297
298 VkPipelineViewportStateCreateInfo viewportState = {};
299 viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
300 viewportState.viewportCount = 1;
301 viewportState.pViewports = &viewport;
302 viewportState.scissorCount = 1;
303 viewportState.pScissors = &scissor;
304
305 VkPipelineRasterizationStateCreateInfo rasterizer = {};
306 rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
307 rasterizer.depthClampEnable = VK_FALSE;
308 rasterizer.rasterizerDiscardEnable = VK_FALSE;
309 rasterizer.polygonMode = VK_POLYGON_MODE_FILL;
310 rasterizer.lineWidth = 1.0f;
311 rasterizer.cullMode = VK_CULL_MODE_BACK_BIT;
312 rasterizer.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
313 rasterizer.depthBiasEnable = VK_FALSE;
314
315 VkPipelineMultisampleStateCreateInfo multisampling = {};
316 multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
317 multisampling.sampleShadingEnable = VK_FALSE;
318 multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
319
320 VkPipelineColorBlendAttachmentState colorBlendAttachment = {};
321 colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
322 colorBlendAttachment.blendEnable = VK_TRUE;
323 colorBlendAttachment.colorBlendOp = VK_BLEND_OP_ADD;
324 colorBlendAttachment.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
325 colorBlendAttachment.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
326 colorBlendAttachment.alphaBlendOp = VK_BLEND_OP_ADD;
327 colorBlendAttachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
328 colorBlendAttachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
329
330 VkPipelineColorBlendStateCreateInfo colorBlending = {};
331 colorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
332 colorBlending.logicOpEnable = VK_FALSE;
333 colorBlending.logicOp = VK_LOGIC_OP_COPY;
334 colorBlending.attachmentCount = 1;
335 colorBlending.pAttachments = &colorBlendAttachment;
336 colorBlending.blendConstants[0] = 0.0f;
337 colorBlending.blendConstants[1] = 0.0f;
338 colorBlending.blendConstants[2] = 0.0f;
339 colorBlending.blendConstants[3] = 0.0f;
340
341 VkPipelineDepthStencilStateCreateInfo depthStencil = {};
342 depthStencil.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
343 depthStencil.depthTestEnable = VK_TRUE;
344 depthStencil.depthWriteEnable = VK_TRUE;
345 depthStencil.depthCompareOp = VK_COMPARE_OP_LESS;
346 depthStencil.depthBoundsTestEnable = VK_FALSE;
347 depthStencil.minDepthBounds = 0.0f;
348 depthStencil.maxDepthBounds = 1.0f;
349 depthStencil.stencilTestEnable = VK_FALSE;
350 depthStencil.front = {};
351 depthStencil.back = {};
352
353 VkPipelineLayoutCreateInfo pipelineLayoutInfo = {};
354 pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
355 pipelineLayoutInfo.setLayoutCount = 1;
356 pipelineLayoutInfo.pSetLayouts = &this->descriptorSetLayout;
357 pipelineLayoutInfo.pushConstantRangeCount = 0;
358
359 if (vkCreatePipelineLayout(this->device, &pipelineLayoutInfo, nullptr, &this->pipelineLayout) != VK_SUCCESS) {
360 throw runtime_error("failed to create pipeline layout!");
361 }
362
363 VkGraphicsPipelineCreateInfo pipelineInfo = {};
364 pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
365 pipelineInfo.stageCount = 2;
366 pipelineInfo.pStages = shaderStages;
367 pipelineInfo.pVertexInputState = &vertexInputInfo;
368 pipelineInfo.pInputAssemblyState = &inputAssembly;
369 pipelineInfo.pViewportState = &viewportState;
370 pipelineInfo.pRasterizationState = &rasterizer;
371 pipelineInfo.pMultisampleState = &multisampling;
372 pipelineInfo.pDepthStencilState = &depthStencil;
373 pipelineInfo.pColorBlendState = &colorBlending;
374 pipelineInfo.pDynamicState = nullptr;
375 pipelineInfo.layout = this->pipelineLayout;
376 pipelineInfo.renderPass = this->renderPass;
377 pipelineInfo.subpass = 0;
378 pipelineInfo.basePipelineHandle = VK_NULL_HANDLE;
379 pipelineInfo.basePipelineIndex = -1;
380
381 if (vkCreateGraphicsPipelines(this->device, VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &this->pipeline) != VK_SUCCESS) {
382 throw runtime_error("failed to create graphics pipeline!");
383 }
384
385 vkDestroyShaderModule(this->device, vertShaderModule, nullptr);
386 vkDestroyShaderModule(this->device, fragShaderModule, nullptr);
387}
388
389template<class VertexType>
390void GraphicsPipeline_Vulkan<VertexType>::createDescriptorSetLayout() {
391 vector<VkDescriptorSetLayoutBinding> bindings(this->descriptorInfoList.size());
392
393 for (size_t i = 0; i < bindings.size(); i++) {
394 bindings[i].binding = i;
395 bindings[i].descriptorCount = 1;
396 bindings[i].descriptorType = this->descriptorInfoList[i].type;
397 bindings[i].stageFlags = this->descriptorInfoList[i].stageFlags;
398 bindings[i].pImmutableSamplers = nullptr;
399 }
400
401 VkDescriptorSetLayoutCreateInfo layoutInfo = {};
402 layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
403 layoutInfo.bindingCount = static_cast<uint32_t>(bindings.size());
404 layoutInfo.pBindings = bindings.data();
405
406 if (vkCreateDescriptorSetLayout(this->device, &layoutInfo, nullptr, &this->descriptorSetLayout) != VK_SUCCESS) {
407 throw runtime_error("failed to create descriptor set layout!");
408 }
409}
410
411template<class VertexType>
412void GraphicsPipeline_Vulkan<VertexType>::createDescriptorPool(vector<VkImage>& swapChainImages) {
413 vector<VkDescriptorPoolSize> poolSizes(this->descriptorInfoList.size());
414
415 for (size_t i = 0; i < poolSizes.size(); i++) {
416 poolSizes[i].type = this->descriptorInfoList[i].type;
417 poolSizes[i].descriptorCount = static_cast<uint32_t>(swapChainImages.size());
418 }
419
420 VkDescriptorPoolCreateInfo poolInfo = {};
421 poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
422 poolInfo.poolSizeCount = static_cast<uint32_t>(poolSizes.size());
423 poolInfo.pPoolSizes = poolSizes.data();
424 poolInfo.maxSets = static_cast<uint32_t>(swapChainImages.size());
425
426 if (vkCreateDescriptorPool(this->device, &poolInfo, nullptr, &this->descriptorPool) != VK_SUCCESS) {
427 throw runtime_error("failed to create descriptor pool!");
428 }
429}
430
431// TODO: Since I only need the size of the swapChainImages array, I should just pass that in instead of the whole array
432template<class VertexType>
433void GraphicsPipeline_Vulkan<VertexType>::createDescriptorSets(vector<VkImage>& swapChainImages) {
434 vector<VkDescriptorSetLayout> layouts(swapChainImages.size(), this->descriptorSetLayout);
435
436 VkDescriptorSetAllocateInfo allocInfo = {};
437 allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
438 allocInfo.descriptorPool = this->descriptorPool;
439 allocInfo.descriptorSetCount = static_cast<uint32_t>(swapChainImages.size());
440 allocInfo.pSetLayouts = layouts.data();
441
442 this->descriptorSets.resize(swapChainImages.size());
443 if (vkAllocateDescriptorSets(device, &allocInfo, this->descriptorSets.data()) != VK_SUCCESS) {
444 throw runtime_error("failed to allocate descriptor sets!");
445 }
446
447 for (size_t i = 0; i < swapChainImages.size(); i++) {
448 vector<VkWriteDescriptorSet> descriptorWrites(this->descriptorInfoList.size());
449
450 for (size_t j = 0; j < descriptorWrites.size(); j++) {
451 descriptorWrites[j].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
452 descriptorWrites[j].dstSet = this->descriptorSets[i];
453 descriptorWrites[j].dstBinding = j;
454 descriptorWrites[j].dstArrayElement = 0;
455 descriptorWrites[j].descriptorType = this->descriptorInfoList[j].type;
456 descriptorWrites[j].descriptorCount = 1;
457 descriptorWrites[j].pBufferInfo = nullptr;
458 descriptorWrites[j].pImageInfo = nullptr;
459 descriptorWrites[j].pTexelBufferView = nullptr;
460
461 switch (descriptorWrites[j].descriptorType) {
462 case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
463 case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
464 case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
465 descriptorWrites[j].pBufferInfo = &(*this->descriptorInfoList[j].bufferDataList)[i];
466 break;
467 case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
468 descriptorWrites[j].pImageInfo = this->descriptorInfoList[j].imageData;
469 break;
470 default:
471 throw runtime_error("Unknown descriptor type: " + to_string(descriptorWrites[j].descriptorType));
472 }
473 }
474
475 vkUpdateDescriptorSets(this->device, static_cast<uint32_t>(descriptorWrites.size()), descriptorWrites.data(), 0, nullptr);
476 }
477}
478
479template<class VertexType>
480void GraphicsPipeline_Vulkan<VertexType>::createRenderCommands(VkCommandBuffer& commandBuffer, uint32_t currentImage) {
481 vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
482
483 vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1,
484 &descriptorSets[currentImage], 0, nullptr);
485
486 VkBuffer vertexBuffers[] = { vertexBuffer };
487 VkDeviceSize offsets[] = { 0 };
488 vkCmdBindVertexBuffers(commandBuffer, 0, 1, vertexBuffers, offsets);
489
490 vkCmdBindIndexBuffer(commandBuffer, indexBuffer, 0, VK_INDEX_TYPE_UINT16);
491
492 vkCmdDrawIndexed(commandBuffer, static_cast<uint32_t>(numIndices), 1, 0, 0, 0);
493}
494
495template<class VertexType>
496void GraphicsPipeline_Vulkan<VertexType>::addObject(const vector<VertexType>& vertices, vector<uint16_t> indices,
497 VkCommandPool commandPool, VkQueue graphicsQueue) {
498 // TODO: When resizing the vertex or index buffer, take deleted objects into account.
499 // Remove their data from the buffer and determine the new size of the bufer based on # of remining objects
500
501 // If # non-deleted objects > currentCapacity / 2
502 // - resize and double capacity
503 // else If # non-deleted objects < currentCapacity / 4
504 // - resize amd halve capacity
505 // else
506 // - don't resize, but rewrite data in the buffer to only have non-deleted objects
507
508 if (this->numVertices + vertices.size() > this->vertexCapacity) {
509 resizeVertexBuffer(commandPool, graphicsQueue);
510 }
511 VulkanUtils::copyDataToBuffer(this->device, this->physicalDevice, commandPool, vertices,
512 this->vertexBuffer, this->numVertices, graphicsQueue);
513 this->numVertices += vertices.size();
514
515 if (this->numIndices + indices.size() > this->indexCapacity) {
516 resizeIndexBuffer(commandPool, graphicsQueue);
517 }
518 VulkanUtils::copyDataToBuffer(this->device, this->physicalDevice, commandPool, indices,
519 this->indexBuffer, this->numIndices, graphicsQueue);
520 this->numIndices += indices.size();
521}
522
523// Should only be used if the number of vertices has not changed
524template<class VertexType>
525void GraphicsPipeline_Vulkan<VertexType>::updateObjectVertices(size_t objIndex,
526 const vector<VertexType>& vertices, VkCommandPool commandPool, VkQueue graphicsQueue) {
527 VulkanUtils::copyDataToBuffer(this->device, this->physicalDevice, commandPool, vertices,
528 this->vertexBuffer, objIndex * vertices.size(), graphicsQueue);
529}
530
531template<class VertexType>
532void GraphicsPipeline_Vulkan<VertexType>::cleanup() {
533 vkDestroyPipeline(device, pipeline, nullptr);
534 vkDestroyDescriptorPool(device, descriptorPool, nullptr);
535
536 // TODO: I read that the pipeline layout does not have to be recreated every time
537 // Try only creating it once
538 vkDestroyPipelineLayout(device, pipelineLayout, nullptr);
539}
540
541template<class VertexType>
542void GraphicsPipeline_Vulkan<VertexType>::cleanupBuffers() {
543 vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr);
544
545 vkDestroyBuffer(device, vertexBuffer, nullptr);
546 vkFreeMemory(device, vertexBufferMemory, nullptr);
547 vkDestroyBuffer(device, indexBuffer, nullptr);
548 vkFreeMemory(device, indexBufferMemory, nullptr);
549}
550
551/*** PRIVATE METHODS ***/
552
553template<class VertexType>
554VkShaderModule GraphicsPipeline_Vulkan<VertexType>::createShaderModule(const vector<char>& code) {
555 VkShaderModuleCreateInfo createInfo = {};
556 createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
557 createInfo.codeSize = code.size();
558 createInfo.pCode = reinterpret_cast<const uint32_t*>(code.data());
559
560 VkShaderModule shaderModule;
561 if (vkCreateShaderModule(this->device, &createInfo, nullptr, &shaderModule) != VK_SUCCESS) {
562 throw runtime_error("failed to create shader module!");
563 }
564
565 return shaderModule;
566}
567
568template<class VertexType>
569vector<char> GraphicsPipeline_Vulkan<VertexType>::readFile(const string& filename) {
570 ifstream file(filename, ios::ate | ios::binary);
571
572 if (!file.is_open()) {
573 throw runtime_error("failed to open file!");
574 }
575
576 size_t fileSize = (size_t)file.tellg();
577 vector<char> buffer(fileSize);
578
579 file.seekg(0);
580 file.read(buffer.data(), fileSize);
581
582 file.close();
583
584 return buffer;
585}
586
587template<class VertexType>
588void GraphicsPipeline_Vulkan<VertexType>::resizeVertexBuffer(VkCommandPool commandPool, VkQueue graphicsQueue) {
589 VkBuffer newVertexBuffer;
590 VkDeviceMemory newVertexBufferMemory;
591 this->vertexCapacity *= 2;
592
593 VulkanUtils::createBuffer(this->device, this->physicalDevice, this->vertexCapacity * sizeof(VertexType),
594 VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
595 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, newVertexBuffer, newVertexBufferMemory);
596
597 VulkanUtils::copyBuffer(this->device, commandPool, vertexBuffer, newVertexBuffer, 0, 0, numVertices * sizeof(VertexType), graphicsQueue);
598
599 vkDestroyBuffer(this->device, vertexBuffer, nullptr);
600 vkFreeMemory(this->device, vertexBufferMemory, nullptr);
601
602 vertexBuffer = newVertexBuffer;
603 vertexBufferMemory = newVertexBufferMemory;
604}
605
606template<class VertexType>
607void GraphicsPipeline_Vulkan<VertexType>::resizeIndexBuffer(VkCommandPool commandPool, VkQueue graphicsQueue) {
608 VkBuffer newIndexBuffer;
609 VkDeviceMemory newIndexBufferMemory;
610 this->indexCapacity *= 2;
611
612 VulkanUtils::createBuffer(this->device, this->physicalDevice, this->indexCapacity * sizeof(uint16_t),
613 VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT,
614 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, newIndexBuffer, newIndexBufferMemory);
615
616 VulkanUtils::copyBuffer(this->device, commandPool, indexBuffer, newIndexBuffer, 0, 0, numIndices * sizeof(uint16_t), graphicsQueue);
617
618 vkDestroyBuffer(this->device, indexBuffer, nullptr);
619 vkFreeMemory(this->device, indexBufferMemory, nullptr);
620
621 indexBuffer = newIndexBuffer;
622 indexBufferMemory = newIndexBufferMemory;
623}
624
625#endif // _GRAPHICS_PIPELINE_VULKAN_H
Note: See TracBrowser for help on using the repository browser.