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
RevLine 
[7d2b0b9]1#ifndef _GRAPHICS_PIPELINE_VULKAN_H
2#define _GRAPHICS_PIPELINE_VULKAN_H
3
4#include "graphics-pipeline.hpp"
5
[b8777b7]6#include <fstream>
[860a0da]7#include <iostream>
[cd487fb]8#include <stdexcept>
[7d2b0b9]9#include <vector>
10
[771b33a]11#include <vulkan/vulkan.h>
12
[cd1cb0f]13#define GLM_FORCE_RADIANS
14#define GLM_FORCE_DEPTH_ZERO_TO_ONE // Since, in Vulkan, the depth range is 0 to 1 instead of -1 to 1
15#define GLM_FORCE_RIGHT_HANDED
16
17#include <glm/glm.hpp>
18#include <glm/gtc/matrix_transform.hpp>
19
[e3bef3a]20#include "vulkan-utils.hpp"
21
[cd1cb0f]22using namespace glm;
23
[b794178]24// TODO: Maybe change the name of this struct so I can call the list something other than descriptorInfoList
25struct DescriptorInfo {
26 VkDescriptorType type;
27 VkShaderStageFlags stageFlags;
28
29 // Only one of the below properties should be set
30 vector<VkDescriptorBufferInfo>* bufferDataList;
31 VkDescriptorImageInfo* imageData;
32};
33
[860a0da]34struct StorageBufferSet {
35 vector<VkBuffer> buffers;
36 vector<VkDeviceMemory> memory;
37 vector<VkDescriptorBufferInfo> infoSet;
38};
39
[2d87297]40template<class VertexType, class SSBOType>
[7d2b0b9]41class GraphicsPipeline_Vulkan : public GraphicsPipeline {
42 public:
[b8777b7]43 GraphicsPipeline_Vulkan();
[860a0da]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
[87c8f1a]48 GraphicsPipeline_Vulkan(VkPhysicalDevice physicalDevice, VkDevice device, VkRenderPass renderPass,
[860a0da]49 Viewport viewport, vector<VkImage>& swapChainImages,
50 size_t vertexCapacity, size_t indexCapacity, size_t objectCapacity);
[7d2b0b9]51 ~GraphicsPipeline_Vulkan();
52
[0fe8433]53 size_t getNumVertices();
54
[0ae182f]55 void updateRenderPass(VkRenderPass renderPass);
56
[b794178]57 // Maybe I should rename these to addVertexAttribute (addVaryingAttribute) and addUniformAttribute
58
[771b33a]59 void addAttribute(VkFormat format, size_t offset);
[b794178]60
[860a0da]61 void addStorageDescriptor();
62
[b794178]63 void addDescriptorInfo(VkDescriptorType type, VkShaderStageFlags stageFlags, vector<VkDescriptorBufferInfo>* bufferData);
64 void addDescriptorInfo(VkDescriptorType type, VkShaderStageFlags stageFlags, VkDescriptorImageInfo* imageData);
65
[7d2b0b9]66 void createPipeline(string vertShaderFile, string fragShaderFile);
[b794178]67 void createDescriptorSetLayout();
68 void createDescriptorPool(vector<VkImage>& swapChainImages);
69 void createDescriptorSets(vector<VkImage>& swapChainImages);
70
[603b5bc]71 void createRenderCommands(VkCommandBuffer& commandBuffer, uint32_t currentImage);
72
[0fe8433]73 void addVertices(const vector<VertexType>& vertices, vector<uint16_t> indices, VkCommandPool commandPool,
[e3bef3a]74 VkQueue graphicsQueue);
75
[2da64ef]76 void updateObject(size_t objIndex, SSBOType& ssbo);
77
[b794178]78 void cleanup();
79 void cleanupBuffers();
[7d2b0b9]80
81 private:
[87c8f1a]82 VkPhysicalDevice physicalDevice;
[7d2b0b9]83 VkDevice device;
[b794178]84 VkRenderPass renderPass;
85
86 VkPipeline pipeline;
87 VkPipelineLayout pipelineLayout;
88
[771b33a]89 VkVertexInputBindingDescription bindingDescription;
[b794178]90
[771b33a]91 vector<VkVertexInputAttributeDescription> attributeDescriptions;
[b794178]92 vector<DescriptorInfo> descriptorInfoList;
[7d2b0b9]93
[b794178]94 VkDescriptorSetLayout descriptorSetLayout;
95 VkDescriptorPool descriptorPool;
96 vector<VkDescriptorSet> descriptorSets;
[87c8f1a]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;
[b8777b7]107
[860a0da]108 size_t numObjects;
109 size_t objectCapacity;
110
[2da64ef]111 StorageBufferSet storageBufferSet;
112
[b8777b7]113 VkShaderModule createShaderModule(const vector<char>& code);
114 vector<char> readFile(const string& filename);
115
[5a0242e]116 void resizeVertexBuffer(VkCommandPool commandPool, VkQueue graphicsQueue);
117 void resizeIndexBuffer(VkCommandPool commandPool, VkQueue graphicsQueue);
[7d2b0b9]118};
119
[b8777b7]120/*** PUBLIC METHODS ***/
121
[2d87297]122template<class VertexType, class SSBOType>
123GraphicsPipeline_Vulkan<VertexType, SSBOType>::GraphicsPipeline_Vulkan() {
[b8777b7]124}
125
[683dd55]126// TODO: Verify that vertex capacity and index capacity are both > 0
[2d87297]127template<class VertexType, class SSBOType>
128GraphicsPipeline_Vulkan<VertexType, SSBOType>::GraphicsPipeline_Vulkan(
129 VkPhysicalDevice physicalDevice, VkDevice device,
[860a0da]130 VkRenderPass renderPass, Viewport viewport, vector<VkImage>& swapChainImages,
131 size_t vertexCapacity, size_t indexCapacity, size_t objectCapacity) {
[b8777b7]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;
[5a0242e]141 this->bindingDescription.stride = sizeof(VertexType);
[b8777b7]142 this->bindingDescription.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
143
[5a0242e]144 this->numVertices = 0;
145 this->vertexCapacity = vertexCapacity;
[b8777b7]146
[5a0242e]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);
[e3bef3a]150
[5a0242e]151 this->numIndices = 0;
152 this->indexCapacity = indexCapacity;
[87c8f1a]153
[5a0242e]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);
[860a0da]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 }
[e3bef3a]182}
183
[860a0da]184// TODO: Move as much cleanup as I can into the destructor
[2d87297]185template<class VertexType, class SSBOType>
186GraphicsPipeline_Vulkan<VertexType, SSBOType>::~GraphicsPipeline_Vulkan() {
[b8777b7]187}
188
[2d87297]189template<class VertexType, class SSBOType>
190size_t GraphicsPipeline_Vulkan<VertexType, SSBOType>::getNumVertices() {
[0fe8433]191 return numVertices;
192}
193
[2d87297]194template<class VertexType, class SSBOType>
195void GraphicsPipeline_Vulkan<VertexType, SSBOType>::updateRenderPass(VkRenderPass renderPass) {
[5a0242e]196 this->renderPass = renderPass;
[b8777b7]197}
198
[2d87297]199template<class VertexType, class SSBOType>
200void GraphicsPipeline_Vulkan<VertexType, SSBOType>::addAttribute(VkFormat format, size_t offset) {
[b8777b7]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
[2d87297]211template<class VertexType, class SSBOType>
[860a0da]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) {
[b8777b7]222 this->descriptorInfoList.push_back({ type, stageFlags, bufferData, nullptr });
223}
224
[2d87297]225template<class VertexType, class SSBOType>
[860a0da]226void GraphicsPipeline_Vulkan<VertexType, SSBOType>::addDescriptorInfo(VkDescriptorType type,
227 VkShaderStageFlags stageFlags, VkDescriptorImageInfo* imageData) {
[b8777b7]228 this->descriptorInfoList.push_back({ type, stageFlags, nullptr, imageData });
229}
230
[2d87297]231template<class VertexType, class SSBOType>
232void GraphicsPipeline_Vulkan<VertexType, SSBOType>::createPipeline(string vertShaderFile, string fragShaderFile) {
[b8777b7]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
[2d87297]369template<class VertexType, class SSBOType>
370void GraphicsPipeline_Vulkan<VertexType, SSBOType>::createDescriptorSetLayout() {
[b8777b7]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
[2d87297]391template<class VertexType, class SSBOType>
392void GraphicsPipeline_Vulkan<VertexType, SSBOType>::createDescriptorPool(vector<VkImage>& swapChainImages) {
[b8777b7]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
[860a0da]411// TODO: Since I only need the size of the swapChainImages array, I should just pass that in instead of the whole array
[2d87297]412template<class VertexType, class SSBOType>
413void GraphicsPipeline_Vulkan<VertexType, SSBOType>::createDescriptorSets(vector<VkImage>& swapChainImages) {
[b8777b7]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 }
[e3bef3a]426
[b8777b7]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:
[055750a]443 case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
[b8777b7]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 }
[e3bef3a]452 }
453
[b8777b7]454 vkUpdateDescriptorSets(this->device, static_cast<uint32_t>(descriptorWrites.size()), descriptorWrites.data(), 0, nullptr);
455 }
456}
457
[2d87297]458template<class VertexType, class SSBOType>
[860a0da]459void GraphicsPipeline_Vulkan<VertexType, SSBOType>::createRenderCommands(VkCommandBuffer& commandBuffer,
460 uint32_t currentImage) {
[b8777b7]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
[2d87297]474template<class VertexType, class SSBOType>
475void GraphicsPipeline_Vulkan<VertexType, SSBOType>::addVertices(const vector<VertexType>& vertices, vector<uint16_t> indices,
[b8777b7]476 VkCommandPool commandPool, VkQueue graphicsQueue) {
477
[5a0242e]478 if (numVertices + vertices.size() > vertexCapacity) {
479 resizeVertexBuffer(commandPool, graphicsQueue);
480 }
481 if (numIndices + indices.size() > indexCapacity) {
482 resizeIndexBuffer(commandPool, graphicsQueue);
[b8777b7]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
[2da64ef]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
[2d87297]503template<class VertexType, class SSBOType>
504void GraphicsPipeline_Vulkan<VertexType, SSBOType>::cleanup() {
[b8777b7]505 vkDestroyPipeline(device, pipeline, nullptr);
506 vkDestroyDescriptorPool(device, descriptorPool, nullptr);
[860a0da]507
508 // TODO: I read that the pipeline layout does not have to be recreated every time
509 // Try only creating it once
[b8777b7]510 vkDestroyPipelineLayout(device, pipelineLayout, nullptr);
511}
512
[2d87297]513template<class VertexType, class SSBOType>
514void GraphicsPipeline_Vulkan<VertexType, SSBOType>::cleanupBuffers() {
[b8777b7]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);
[860a0da]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 }
[b8777b7]528}
529
530/*** PRIVATE METHODS ***/
531
[2d87297]532template<class VertexType, class SSBOType>
533VkShaderModule GraphicsPipeline_Vulkan<VertexType, SSBOType>::createShaderModule(const vector<char>& code) {
[b8777b7]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}
[e3bef3a]546
[2d87297]547template<class VertexType, class SSBOType>
548vector<char> GraphicsPipeline_Vulkan<VertexType, SSBOType>::readFile(const string& filename) {
[b8777b7]549 ifstream file(filename, ios::ate | ios::binary);
[e3bef3a]550
[b8777b7]551 if (!file.is_open()) {
552 throw runtime_error("failed to open file!");
[e3bef3a]553 }
554
[b8777b7]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
[2d87297]566template<class VertexType, class SSBOType>
[860a0da]567void GraphicsPipeline_Vulkan<VertexType, SSBOType>::resizeVertexBuffer(VkCommandPool commandPool,
568 VkQueue graphicsQueue) {
[5a0242e]569 VkBuffer newVertexBuffer;
570 VkDeviceMemory newVertexBufferMemory;
[860a0da]571 this->vertexCapacity *= 2;
[5a0242e]572
[860a0da]573 VulkanUtils::createBuffer(this->device, this->physicalDevice, this->vertexCapacity * sizeof(VertexType),
[5a0242e]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
[860a0da]577 VulkanUtils::copyBuffer(this->device, commandPool, vertexBuffer, newVertexBuffer, 0, 0, numVertices * sizeof(VertexType), graphicsQueue);
[5a0242e]578
[860a0da]579 vkDestroyBuffer(this->device, vertexBuffer, nullptr);
580 vkFreeMemory(this->device, vertexBufferMemory, nullptr);
[b8777b7]581
[5a0242e]582 vertexBuffer = newVertexBuffer;
583 vertexBufferMemory = newVertexBufferMemory;
584}
[b8777b7]585
[2d87297]586template<class VertexType, class SSBOType>
[860a0da]587void GraphicsPipeline_Vulkan<VertexType, SSBOType>::resizeIndexBuffer(VkCommandPool commandPool,
588 VkQueue graphicsQueue) {
[5a0242e]589 VkBuffer newIndexBuffer;
590 VkDeviceMemory newIndexBufferMemory;
[860a0da]591 this->indexCapacity *= 2;
[b8777b7]592
[860a0da]593 VulkanUtils::createBuffer(this->device, this->physicalDevice, this->indexCapacity * sizeof(uint16_t),
[5a0242e]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
[860a0da]597 VulkanUtils::copyBuffer(this->device, commandPool, indexBuffer, newIndexBuffer, 0, 0, numIndices * sizeof(uint16_t), graphicsQueue);
[5a0242e]598
[860a0da]599 vkDestroyBuffer(this->device, indexBuffer, nullptr);
600 vkFreeMemory(this->device, indexBufferMemory, nullptr);
[5a0242e]601
602 indexBuffer = newIndexBuffer;
603 indexBufferMemory = newIndexBufferMemory;
[87c8f1a]604}
605
[7d2b0b9]606#endif // _GRAPHICS_PIPELINE_VULKAN_H
Note: See TracBrowser for help on using the repository browser.