source: opengl-game/graphics-pipeline_vulkan.hpp@ 90880fb

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

Change createRenderCommands() to support dynamic offsets

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