source: opengl-game/graphics-pipeline_vulkan.hpp

feature/imgui-sdl
Last change on this file 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
Line 
1#ifndef _GRAPHICS_PIPELINE_VULKAN_H
2#define _GRAPHICS_PIPELINE_VULKAN_H
3
4#include "graphics-pipeline.hpp"
5
6#include <fstream>
7#include <iostream>
8#include <stdexcept>
9#include <vector>
10
11#include <vulkan/vulkan.h>
12
13#define GLM_FORCE_RADIANS
14#define GLM_FORCE_DEPTH_ZERO_TO_ONE // Since, in Vulkan, the depth range is 0 to 1 instead of -1 to 1
15#define GLM_FORCE_RIGHT_HANDED
16
17#include <glm/glm.hpp>
18#include <glm/gtc/matrix_transform.hpp>
19
20#include "vulkan-utils.hpp"
21
22using namespace glm;
23
24// TODO: Maybe change the name of this struct so I can call the list something other than descriptorInfoList
25struct DescriptorInfo {
26 VkDescriptorType type;
27 VkShaderStageFlags stageFlags;
28
29 // Only one of the below properties should be set
30 vector<VkDescriptorBufferInfo>* bufferDataList;
31 VkDescriptorImageInfo* imageData;
32};
33
34template<class VertexType>
35class GraphicsPipeline_Vulkan : public GraphicsPipeline {
36 public:
37 string vertShaderFile, fragShaderFile;
38
39 GraphicsPipeline_Vulkan();
40
41 GraphicsPipeline_Vulkan(VkPrimitiveTopology topology, VkPhysicalDevice physicalDevice, VkDevice device,
42 VkRenderPass renderPass, Viewport viewport, size_t vertexCapacity, size_t indexCapacity);
43 ~GraphicsPipeline_Vulkan();
44
45 size_t getNumVertices();
46
47 void updateRenderPass(VkRenderPass renderPass);
48
49 // Maybe I should rename these to addVertexAttribute (addVaryingAttribute) and addUniformAttribute
50
51 void addAttribute(VkFormat format, size_t offset);
52
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);
56 void addDescriptorInfo(VkDescriptorType type, VkShaderStageFlags stageFlags, VkDescriptorImageInfo* imageData);
57
58 void updateDescriptorInfo(uint32_t index, vector<VkDescriptorBufferInfo>* bufferData, uint32_t size);
59
60 void createPipeline(string vertShaderFile, string fragShaderFile);
61 void createDescriptorSetLayout();
62 void createDescriptorPool(uint32_t size);
63 void createDescriptorSets(uint32_t size);
64
65 void createRenderCommands(VkCommandBuffer& commandBuffer, uint32_t currentImage,
66 const vector<uint32_t>& dynamicOffsets);
67
68 void addObject(const vector<VertexType>& vertices, vector<uint16_t> indices, VkCommandPool commandPool,
69 VkQueue graphicsQueue);
70
71 void updateObjectVertices(size_t objIndex, const vector<VertexType>& vertices, VkCommandPool commandPool,
72 VkQueue graphicsQueue);
73
74 void cleanup();
75 void cleanupBuffers();
76
77 private:
78 VkPrimitiveTopology topology;
79 VkPhysicalDevice physicalDevice;
80 VkDevice device;
81 VkRenderPass renderPass;
82
83 VkPipeline pipeline;
84 VkPipelineLayout pipelineLayout;
85
86 VkVertexInputBindingDescription bindingDescription;
87
88 vector<VkVertexInputAttributeDescription> attributeDescriptions;
89 vector<DescriptorInfo> descriptorInfoList;
90
91 VkDescriptorSetLayout descriptorSetLayout;
92 VkDescriptorPool descriptorPool;
93 vector<VkDescriptorSet> descriptorSets;
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;
104
105 VkShaderModule createShaderModule(const vector<char>& code);
106 vector<char> readFile(const string& filename);
107
108 void resizeVertexBuffer(VkCommandPool commandPool, VkQueue graphicsQueue);
109 void resizeIndexBuffer(VkCommandPool commandPool, VkQueue graphicsQueue);
110};
111
112/*** PUBLIC METHODS ***/
113
114template<class VertexType>
115GraphicsPipeline_Vulkan<VertexType>::GraphicsPipeline_Vulkan() {
116}
117
118// TODO: Verify that vertex capacity and index capacity are both > 0
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
121template<class VertexType>
122GraphicsPipeline_Vulkan<VertexType>::GraphicsPipeline_Vulkan(VkPrimitiveTopology topology,
123 VkPhysicalDevice physicalDevice, VkDevice device,
124 VkRenderPass renderPass, Viewport viewport,
125 size_t vertexCapacity, size_t indexCapacity)
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
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;
140 this->bindingDescription.stride = sizeof(VertexType);
141 this->bindingDescription.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
142
143 this->numVertices = 0;
144 this->vertexCapacity = vertexCapacity;
145
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);
149
150 this->numIndices = 0;
151 this->indexCapacity = indexCapacity;
152
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);
156}
157
158// TODO: Move as much cleanup as I can into the destructor
159template<class VertexType>
160GraphicsPipeline_Vulkan<VertexType>::~GraphicsPipeline_Vulkan() {
161}
162
163template<class VertexType>
164size_t GraphicsPipeline_Vulkan<VertexType>::getNumVertices() {
165 return numVertices;
166}
167
168template<class VertexType>
169void GraphicsPipeline_Vulkan<VertexType>::updateRenderPass(VkRenderPass renderPass) {
170 this->renderPass = renderPass;
171}
172
173template<class VertexType>
174void GraphicsPipeline_Vulkan<VertexType>::addAttribute(VkFormat format, size_t offset) {
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
185template<class VertexType>
186void GraphicsPipeline_Vulkan<VertexType>::addDescriptorInfo(VkDescriptorType type, VkShaderStageFlags stageFlags,
187 vector<VkDescriptorBufferInfo>* bufferData) {
188 this->descriptorInfoList.push_back({ type, stageFlags, bufferData, nullptr });
189}
190
191template<class VertexType>
192void GraphicsPipeline_Vulkan<VertexType>::addDescriptorInfo(VkDescriptorType type, VkShaderStageFlags stageFlags,
193 VkDescriptorImageInfo* imageData) {
194 this->descriptorInfoList.push_back({ type, stageFlags, nullptr, imageData });
195}
196
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
200template<class VertexType>
201void GraphicsPipeline_Vulkan<VertexType>::updateDescriptorInfo(uint32_t index,
202 vector<VkDescriptorBufferInfo>* bufferData,
203 uint32_t size) {
204 this->descriptorInfoList[index].bufferDataList = bufferData;
205
206 // TODO: This code was mostly copied from createDescriptorSets. I should make some common function they both use
207 // for updating descriptor sets
208 for (size_t i = 0; i < size; i++) {
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
236 // TODO: Instead, assert that (bufferData->size() == swapChainImages.size() (now just changed to size)
237 if (bufferData->size() != size) {
238 cout << "ALERT ALERT ALERT: SIZE MISMATCH!!!!!!!" << endl;
239 }
240
241 vkUpdateDescriptorSets(this->device, 1, &descriptorWrite, 0, nullptr);
242 }
243}
244
245template<class VertexType>
246void GraphicsPipeline_Vulkan<VertexType>::createPipeline(string vertShaderFile, string fragShaderFile) {
247 this->vertShaderFile = vertShaderFile;
248 this->fragShaderFile = fragShaderFile;
249
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;
280 inputAssembly.topology = this->topology;
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
386template<class VertexType>
387void GraphicsPipeline_Vulkan<VertexType>::createDescriptorSetLayout() {
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
408template<class VertexType>
409void GraphicsPipeline_Vulkan<VertexType>::createDescriptorPool(uint32_t size) {
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;
414 poolSizes[i].descriptorCount = size;
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();
421 poolInfo.maxSets = size;
422
423 if (vkCreateDescriptorPool(this->device, &poolInfo, nullptr, &this->descriptorPool) != VK_SUCCESS) {
424 throw runtime_error("failed to create descriptor pool!");
425 }
426}
427
428template<class VertexType>
429void GraphicsPipeline_Vulkan<VertexType>::createDescriptorSets(uint32_t size) {
430 vector<VkDescriptorSetLayout> layouts(size, this->descriptorSetLayout);
431
432 VkDescriptorSetAllocateInfo allocInfo = {};
433 allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
434 allocInfo.descriptorPool = this->descriptorPool;
435 allocInfo.descriptorSetCount = size;
436 allocInfo.pSetLayouts = layouts.data();
437
438 this->descriptorSets.resize(size);
439 if (vkAllocateDescriptorSets(device, &allocInfo, this->descriptorSets.data()) != VK_SUCCESS) {
440 throw runtime_error("failed to allocate descriptor sets!");
441 }
442
443 for (size_t i = 0; i < size; i++) {
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:
459 case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
460 case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
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 }
469 }
470
471 vkUpdateDescriptorSets(this->device, static_cast<uint32_t>(descriptorWrites.size()), descriptorWrites.data(), 0, nullptr);
472 }
473}
474
475template<class VertexType>
476void GraphicsPipeline_Vulkan<VertexType>::createRenderCommands(VkCommandBuffer& commandBuffer, uint32_t currentImage,
477 const vector<uint32_t>& dynamicOffsets) {
478 vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
479
480 // If more dynamic UBOs are added, this needs to become an array of offsets
481 vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1,
482 &descriptorSets[currentImage], dynamicOffsets.size(), dynamicOffsets.data());
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
493template<class VertexType>
494void GraphicsPipeline_Vulkan<VertexType>::addObject(const vector<VertexType>& vertices, vector<uint16_t> indices,
495 VkCommandPool commandPool, VkQueue graphicsQueue) {
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
505
506 if (this->numVertices + vertices.size() > this->vertexCapacity) {
507 resizeVertexBuffer(commandPool, graphicsQueue);
508 }
509 VulkanUtils::copyDataToBuffer(this->device, this->physicalDevice, commandPool, vertices,
510 this->vertexBuffer, this->numVertices, graphicsQueue);
511 this->numVertices += vertices.size();
512
513 if (this->numIndices + indices.size() > this->indexCapacity) {
514 resizeIndexBuffer(commandPool, graphicsQueue);
515 }
516 VulkanUtils::copyDataToBuffer(this->device, this->physicalDevice, commandPool, indices,
517 this->indexBuffer, this->numIndices, graphicsQueue);
518 this->numIndices += indices.size();
519}
520
521// Should only be used if the number of vertices has not changed
522template<class VertexType>
523void GraphicsPipeline_Vulkan<VertexType>::updateObjectVertices(size_t objIndex,
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
529template<class VertexType>
530void GraphicsPipeline_Vulkan<VertexType>::cleanup() {
531 vkDestroyPipeline(device, pipeline, nullptr);
532 vkDestroyDescriptorPool(device, descriptorPool, nullptr);
533
534 // TODO: I read that the pipeline layout does not have to be recreated every time
535 // Try only creating it once
536 vkDestroyPipelineLayout(device, pipelineLayout, nullptr);
537}
538
539template<class VertexType>
540void GraphicsPipeline_Vulkan<VertexType>::cleanupBuffers() {
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
551template<class VertexType>
552VkShaderModule GraphicsPipeline_Vulkan<VertexType>::createShaderModule(const vector<char>& code) {
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}
565
566template<class VertexType>
567vector<char> GraphicsPipeline_Vulkan<VertexType>::readFile(const string& filename) {
568 ifstream file(filename, ios::ate | ios::binary);
569
570 if (!file.is_open()) {
571 throw runtime_error("failed to open file!");
572 }
573
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
585template<class VertexType>
586void GraphicsPipeline_Vulkan<VertexType>::resizeVertexBuffer(VkCommandPool commandPool, VkQueue graphicsQueue) {
587 VkBuffer newVertexBuffer;
588 VkDeviceMemory newVertexBufferMemory;
589 this->vertexCapacity *= 2;
590
591 VulkanUtils::createBuffer(this->device, this->physicalDevice, this->vertexCapacity * sizeof(VertexType),
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
595 VulkanUtils::copyBuffer(this->device, commandPool, vertexBuffer, newVertexBuffer, 0, 0, numVertices * sizeof(VertexType), graphicsQueue);
596
597 vkDestroyBuffer(this->device, vertexBuffer, nullptr);
598 vkFreeMemory(this->device, vertexBufferMemory, nullptr);
599
600 vertexBuffer = newVertexBuffer;
601 vertexBufferMemory = newVertexBufferMemory;
602}
603
604template<class VertexType>
605void GraphicsPipeline_Vulkan<VertexType>::resizeIndexBuffer(VkCommandPool commandPool, 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.