source: opengl-game/graphics-pipeline_vulkan.hpp@ 9d21aac

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

Remove the SSBOType template parameter from GraphicsPipeline_Vulkan

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