source: opengl-game/graphics-pipeline_vulkan.hpp@ 58453c3

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

Remove the swapChainImages parameter from the GraphicsPipeline_Vulkan constructor and modify createDescriptorPool(), createDescriptorSets(), and updateDescriptorInfo() to accept a size paramter instead of accepting a vector of swap chain images and getting the size from that

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