source: opengl-game/graphics-pipeline_vulkan.cpp@ 0ae182f

feature/imgui-sdl points-test
Last change on this file since 0ae182f was 0ae182f, checked in by Dmitry Portnoy <dmp1488@…>, 5 years ago

In vulkangame, finish implementing recreateSwapChain()

  • Property mode set to 100644
File size: 16.3 KB
Line 
1#include "graphics-pipeline_vulkan.hpp"
2
3#include <fstream>
4#include <stdexcept>
5#include <iostream>
6
7#include "vulkan-utils.hpp"
8
9using namespace std;
10
11// TODO: Remove any instances of cout and instead throw exceptions
12
13GraphicsPipeline_Vulkan::GraphicsPipeline_Vulkan(VkPhysicalDevice physicalDevice, VkDevice device,
14 VkRenderPass renderPass, Viewport viewport, int vertexSize) {
15 this->physicalDevice = physicalDevice;
16 this->device = device;
17 this->renderPass = renderPass;
18 this->viewport = viewport;
19
20 // Since there is only one array of vertex data, we use binding = 0
21 // I'll probably do that for the foreseeable future
22 // I can calculate the stride myself given info about all the varying attributes
23 this->bindingDescription.binding = 0;
24 this->bindingDescription.stride = vertexSize;
25 this->bindingDescription.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
26}
27
28GraphicsPipeline_Vulkan::~GraphicsPipeline_Vulkan() {
29}
30
31void GraphicsPipeline_Vulkan::updateRenderPass(VkRenderPass renderPass) {
32 this->renderPass = renderPass;
33}
34
35void GraphicsPipeline_Vulkan::createVertexBuffer(const void* bufferData, int vertexSize,
36 VkCommandPool commandPool, VkQueue graphicsQueue) {
37 VkDeviceSize bufferSize = numVertices * vertexSize;
38 VkDeviceSize bufferCapacity = vertexCapacity * vertexSize;
39
40 VkBuffer stagingBuffer;
41 VkDeviceMemory stagingBufferMemory;
42 VulkanUtils::createBuffer(device, physicalDevice, bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
43 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
44 stagingBuffer, stagingBufferMemory);
45
46 void* data;
47 vkMapMemory(device, stagingBufferMemory, 0, bufferSize, 0, &data);
48 memcpy(data, bufferData, (size_t) bufferSize);
49 vkUnmapMemory(device, stagingBufferMemory);
50
51 VulkanUtils::createBuffer(device, physicalDevice, bufferCapacity,
52 VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
53 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, vertexBuffer, vertexBufferMemory);
54
55 VulkanUtils::copyBuffer(device, commandPool, stagingBuffer, vertexBuffer, 0, 0, bufferSize, graphicsQueue);
56
57 vkDestroyBuffer(device, stagingBuffer, nullptr);
58 vkFreeMemory(device, stagingBufferMemory, nullptr);
59}
60
61void GraphicsPipeline_Vulkan::createIndexBuffer(const void* bufferData, int indexSize,
62 VkCommandPool commandPool, VkQueue graphicsQueue) {
63 VkDeviceSize bufferSize = numIndices * indexSize;
64 VkDeviceSize bufferCapacity = indexCapacity * indexSize;
65
66 VkBuffer stagingBuffer;
67 VkDeviceMemory stagingBufferMemory;
68 VulkanUtils::createBuffer(device, physicalDevice, bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
69 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
70 stagingBuffer, stagingBufferMemory);
71
72 void* data;
73 vkMapMemory(device, stagingBufferMemory, 0, bufferSize, 0, &data);
74 memcpy(data, bufferData, (size_t) bufferSize);
75 vkUnmapMemory(device, stagingBufferMemory);
76
77 VulkanUtils::createBuffer(device, physicalDevice, bufferCapacity,
78 VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT,
79 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, indexBuffer, indexBufferMemory);
80
81 VulkanUtils::copyBuffer(device, commandPool, stagingBuffer, indexBuffer, 0, 0, bufferSize, graphicsQueue);
82
83 vkDestroyBuffer(device, stagingBuffer, nullptr);
84 vkFreeMemory(device, stagingBufferMemory, nullptr);
85}
86
87void GraphicsPipeline_Vulkan::addAttribute(VkFormat format, size_t offset) {
88 VkVertexInputAttributeDescription attributeDesc = {};
89
90 attributeDesc.binding = 0;
91 attributeDesc.location = this->attributeDescriptions.size();
92 attributeDesc.format = format;
93 attributeDesc.offset = offset;
94
95 this->attributeDescriptions.push_back(attributeDesc);
96}
97
98void GraphicsPipeline_Vulkan::addDescriptorInfo(VkDescriptorType type, VkShaderStageFlags stageFlags, vector<VkDescriptorBufferInfo>* bufferData) {
99 this->descriptorInfoList.push_back({ type, stageFlags, bufferData, nullptr });
100}
101
102void GraphicsPipeline_Vulkan::addDescriptorInfo(VkDescriptorType type, VkShaderStageFlags stageFlags, VkDescriptorImageInfo* imageData) {
103 this->descriptorInfoList.push_back({ type, stageFlags, nullptr, imageData });
104}
105
106void GraphicsPipeline_Vulkan::createPipeline(string vertShaderFile, string fragShaderFile) {
107 vector<char> vertShaderCode = readFile(vertShaderFile);
108 vector<char> fragShaderCode = readFile(fragShaderFile);
109
110 VkShaderModule vertShaderModule = createShaderModule(vertShaderCode);
111 VkShaderModule fragShaderModule = createShaderModule(fragShaderCode);
112
113 VkPipelineShaderStageCreateInfo vertShaderStageInfo = {};
114 vertShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
115 vertShaderStageInfo.stage = VK_SHADER_STAGE_VERTEX_BIT;
116 vertShaderStageInfo.module = vertShaderModule;
117 vertShaderStageInfo.pName = "main";
118
119 VkPipelineShaderStageCreateInfo fragShaderStageInfo = {};
120 fragShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
121 fragShaderStageInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
122 fragShaderStageInfo.module = fragShaderModule;
123 fragShaderStageInfo.pName = "main";
124
125 VkPipelineShaderStageCreateInfo shaderStages[] = { vertShaderStageInfo, fragShaderStageInfo };
126
127 VkPipelineVertexInputStateCreateInfo vertexInputInfo = {};
128 vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
129
130 vertexInputInfo.vertexBindingDescriptionCount = 1;
131 vertexInputInfo.vertexAttributeDescriptionCount = static_cast<uint32_t>(this->attributeDescriptions.size());
132 vertexInputInfo.pVertexBindingDescriptions = &this->bindingDescription;
133 vertexInputInfo.pVertexAttributeDescriptions = this->attributeDescriptions.data();
134
135 VkPipelineInputAssemblyStateCreateInfo inputAssembly = {};
136 inputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
137 inputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
138 inputAssembly.primitiveRestartEnable = VK_FALSE;
139
140 VkViewport viewport = {};
141 viewport.x = (float)this->viewport.x;
142 viewport.y = (float)this->viewport.y;
143 viewport.width = (float)this->viewport.width;
144 viewport.height = (float)this->viewport.height;
145 viewport.minDepth = 0.0f;
146 viewport.maxDepth = 1.0f;
147
148 VkRect2D scissor = {};
149 scissor.offset = { 0, 0 };
150 scissor.extent = { (uint32_t)this->viewport.width, (uint32_t)this->viewport.height };
151
152 VkPipelineViewportStateCreateInfo viewportState = {};
153 viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
154 viewportState.viewportCount = 1;
155 viewportState.pViewports = &viewport;
156 viewportState.scissorCount = 1;
157 viewportState.pScissors = &scissor;
158
159 VkPipelineRasterizationStateCreateInfo rasterizer = {};
160 rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
161 rasterizer.depthClampEnable = VK_FALSE;
162 rasterizer.rasterizerDiscardEnable = VK_FALSE;
163 rasterizer.polygonMode = VK_POLYGON_MODE_FILL;
164 rasterizer.lineWidth = 1.0f;
165 rasterizer.cullMode = VK_CULL_MODE_BACK_BIT;
166 rasterizer.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
167 rasterizer.depthBiasEnable = VK_FALSE;
168
169 VkPipelineMultisampleStateCreateInfo multisampling = {};
170 multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
171 multisampling.sampleShadingEnable = VK_FALSE;
172 multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
173
174 VkPipelineColorBlendAttachmentState colorBlendAttachment = {};
175 colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
176 colorBlendAttachment.blendEnable = VK_TRUE;
177 colorBlendAttachment.colorBlendOp = VK_BLEND_OP_ADD;
178 colorBlendAttachment.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
179 colorBlendAttachment.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
180 colorBlendAttachment.alphaBlendOp = VK_BLEND_OP_ADD;
181 colorBlendAttachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
182 colorBlendAttachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
183
184 VkPipelineColorBlendStateCreateInfo colorBlending = {};
185 colorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
186 colorBlending.logicOpEnable = VK_FALSE;
187 colorBlending.logicOp = VK_LOGIC_OP_COPY;
188 colorBlending.attachmentCount = 1;
189 colorBlending.pAttachments = &colorBlendAttachment;
190 colorBlending.blendConstants[0] = 0.0f;
191 colorBlending.blendConstants[1] = 0.0f;
192 colorBlending.blendConstants[2] = 0.0f;
193 colorBlending.blendConstants[3] = 0.0f;
194
195 VkPipelineDepthStencilStateCreateInfo depthStencil = {};
196 depthStencil.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
197 depthStencil.depthTestEnable = VK_TRUE;
198 depthStencil.depthWriteEnable = VK_TRUE;
199 depthStencil.depthCompareOp = VK_COMPARE_OP_LESS;
200 depthStencil.depthBoundsTestEnable = VK_FALSE;
201 depthStencil.minDepthBounds = 0.0f;
202 depthStencil.maxDepthBounds = 1.0f;
203 depthStencil.stencilTestEnable = VK_FALSE;
204 depthStencil.front = {};
205 depthStencil.back = {};
206
207 VkPipelineLayoutCreateInfo pipelineLayoutInfo = {};
208 pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
209 pipelineLayoutInfo.setLayoutCount = 1;
210 pipelineLayoutInfo.pSetLayouts = &this->descriptorSetLayout;
211 pipelineLayoutInfo.pushConstantRangeCount = 0;
212
213 if (vkCreatePipelineLayout(this->device, &pipelineLayoutInfo, nullptr, &this->pipelineLayout) != VK_SUCCESS) {
214 throw runtime_error("failed to create pipeline layout!");
215 }
216
217 VkGraphicsPipelineCreateInfo pipelineInfo = {};
218 pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
219 pipelineInfo.stageCount = 2;
220 pipelineInfo.pStages = shaderStages;
221 pipelineInfo.pVertexInputState = &vertexInputInfo;
222 pipelineInfo.pInputAssemblyState = &inputAssembly;
223 pipelineInfo.pViewportState = &viewportState;
224 pipelineInfo.pRasterizationState = &rasterizer;
225 pipelineInfo.pMultisampleState = &multisampling;
226 pipelineInfo.pDepthStencilState = &depthStencil;
227 pipelineInfo.pColorBlendState = &colorBlending;
228 pipelineInfo.pDynamicState = nullptr;
229 pipelineInfo.layout = this->pipelineLayout;
230 pipelineInfo.renderPass = this->renderPass;
231 pipelineInfo.subpass = 0;
232 pipelineInfo.basePipelineHandle = VK_NULL_HANDLE;
233 pipelineInfo.basePipelineIndex = -1;
234
235 if (vkCreateGraphicsPipelines(this->device, VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &this->pipeline) != VK_SUCCESS) {
236 throw runtime_error("failed to create graphics pipeline!");
237 }
238
239 vkDestroyShaderModule(this->device, vertShaderModule, nullptr);
240 vkDestroyShaderModule(this->device, fragShaderModule, nullptr);
241}
242
243void GraphicsPipeline_Vulkan::createDescriptorSetLayout() {
244 vector<VkDescriptorSetLayoutBinding> bindings(this->descriptorInfoList.size());
245
246 for (size_t i = 0; i < bindings.size(); i++) {
247 bindings[i].binding = i;
248 bindings[i].descriptorCount = 1;
249 bindings[i].descriptorType = this->descriptorInfoList[i].type;
250 bindings[i].stageFlags = this->descriptorInfoList[i].stageFlags;
251 bindings[i].pImmutableSamplers = nullptr;
252 }
253
254 VkDescriptorSetLayoutCreateInfo layoutInfo = {};
255 layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
256 layoutInfo.bindingCount = static_cast<uint32_t>(bindings.size());
257 layoutInfo.pBindings = bindings.data();
258
259 if (vkCreateDescriptorSetLayout(this->device, &layoutInfo, nullptr, &this->descriptorSetLayout) != VK_SUCCESS) {
260 throw runtime_error("failed to create descriptor set layout!");
261 }
262}
263
264void GraphicsPipeline_Vulkan::createDescriptorPool(vector<VkImage>& swapChainImages) {
265 vector<VkDescriptorPoolSize> poolSizes(this->descriptorInfoList.size());
266
267 for (size_t i = 0; i < poolSizes.size(); i++) {
268 poolSizes[i].type = this->descriptorInfoList[i].type;
269 poolSizes[i].descriptorCount = static_cast<uint32_t>(swapChainImages.size());
270 }
271
272 VkDescriptorPoolCreateInfo poolInfo = {};
273 poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
274 poolInfo.poolSizeCount = static_cast<uint32_t>(poolSizes.size());
275 poolInfo.pPoolSizes = poolSizes.data();
276 poolInfo.maxSets = static_cast<uint32_t>(swapChainImages.size());
277
278 if (vkCreateDescriptorPool(this->device, &poolInfo, nullptr, &this->descriptorPool) != VK_SUCCESS) {
279 throw runtime_error("failed to create descriptor pool!");
280 }
281}
282
283void GraphicsPipeline_Vulkan::createDescriptorSets(vector<VkImage>& swapChainImages) {
284 vector<VkDescriptorSetLayout> layouts(swapChainImages.size(), this->descriptorSetLayout);
285
286 VkDescriptorSetAllocateInfo allocInfo = {};
287 allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
288 allocInfo.descriptorPool = this->descriptorPool;
289 allocInfo.descriptorSetCount = static_cast<uint32_t>(swapChainImages.size());
290 allocInfo.pSetLayouts = layouts.data();
291
292 this->descriptorSets.resize(swapChainImages.size());
293 if (vkAllocateDescriptorSets(device, &allocInfo, this->descriptorSets.data()) != VK_SUCCESS) {
294 throw runtime_error("failed to allocate descriptor sets!");
295 }
296
297 for (size_t i = 0; i < swapChainImages.size(); i++) {
298 vector<VkWriteDescriptorSet> descriptorWrites(this->descriptorInfoList.size());
299
300 for (size_t j = 0; j < descriptorWrites.size(); j++) {
301 descriptorWrites[j].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
302 descriptorWrites[j].dstSet = this->descriptorSets[i];
303 descriptorWrites[j].dstBinding = j;
304 descriptorWrites[j].dstArrayElement = 0;
305 descriptorWrites[j].descriptorType = this->descriptorInfoList[j].type;
306 descriptorWrites[j].descriptorCount = 1;
307 descriptorWrites[j].pBufferInfo = nullptr;
308 descriptorWrites[j].pImageInfo = nullptr;
309 descriptorWrites[j].pTexelBufferView = nullptr;
310
311 switch (descriptorWrites[j].descriptorType) {
312 case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
313 descriptorWrites[j].pBufferInfo = &(*this->descriptorInfoList[j].bufferDataList)[i];
314 break;
315 case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
316 descriptorWrites[j].pImageInfo = this->descriptorInfoList[j].imageData;
317 break;
318 default:
319 cout << "Unknown descriptor type: " << descriptorWrites[j].descriptorType << endl;
320 }
321 }
322
323 vkUpdateDescriptorSets(this->device, static_cast<uint32_t>(descriptorWrites.size()), descriptorWrites.data(), 0, nullptr);
324 }
325}
326
327void GraphicsPipeline_Vulkan::createRenderCommands(VkCommandBuffer& commandBuffer, uint32_t currentImage) {
328 vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
329 vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1,
330 &descriptorSets[currentImage], 0, nullptr);
331
332 VkBuffer vertexBuffers[] = { vertexBuffer };
333 VkDeviceSize offsets[] = { 0 };
334 vkCmdBindVertexBuffers(commandBuffer, 0, 1, vertexBuffers, offsets);
335
336 vkCmdBindIndexBuffer(commandBuffer, indexBuffer, 0, VK_INDEX_TYPE_UINT16);
337
338 vkCmdDrawIndexed(commandBuffer, static_cast<uint32_t>(numIndices), 1, 0, 0, 0);
339}
340
341VkShaderModule GraphicsPipeline_Vulkan::createShaderModule(const vector<char>& code) {
342 VkShaderModuleCreateInfo createInfo = {};
343 createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
344 createInfo.codeSize = code.size();
345 createInfo.pCode = reinterpret_cast<const uint32_t*>(code.data());
346
347 VkShaderModule shaderModule;
348 if (vkCreateShaderModule(this->device, &createInfo, nullptr, &shaderModule) != VK_SUCCESS) {
349 throw runtime_error("failed to create shader module!");
350 }
351
352 return shaderModule;
353}
354
355vector<char> GraphicsPipeline_Vulkan::readFile(const string& filename) {
356 ifstream file(filename, ios::ate | ios::binary);
357
358 if (!file.is_open()) {
359 throw runtime_error("failed to open file!");
360 }
361
362 size_t fileSize = (size_t)file.tellg();
363 vector<char> buffer(fileSize);
364
365 file.seekg(0);
366 file.read(buffer.data(), fileSize);
367
368 file.close();
369
370 return buffer;
371}
372
373void GraphicsPipeline_Vulkan::cleanup() {
374 vkDestroyPipeline(device, pipeline, nullptr);
375 vkDestroyDescriptorPool(device, descriptorPool, nullptr);
376 vkDestroyPipelineLayout(device, pipelineLayout, nullptr);
377}
378
379void GraphicsPipeline_Vulkan::cleanupBuffers() {
380 vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr);
381
382 vkDestroyBuffer(device, vertexBuffer, nullptr);
383 vkFreeMemory(device, vertexBufferMemory, nullptr);
384 vkDestroyBuffer(device, indexBuffer, nullptr);
385 vkFreeMemory(device, indexBufferMemory, nullptr);
386}
Note: See TracBrowser for help on using the repository browser.