source: opengl-game/graphics-pipeline_vulkan.hpp@ 3b84bb6

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

In VulkanGame, call centerObject() on all objects when they are created and move that call inside VulkanGame::addObject(), rename GraphicsPipeline_Vulkan::addVertices() to addObject, add start adding generic support for objects to be added after pipeline creation is complete

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