source: opengl-game/graphics-pipeline_vulkan.hpp@ 996dd3e

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

Completely remove storage buffers from the GraphicsPipeline_Vulkan class and start moving storage buffer operations out of the addObject() and updateObject() functions

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