source: opengl-game/graphics-pipeline_vulkan.cpp@ 1f25a71

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

In vulkangame, implement the renderScene function to draw a frame in Vulkan and implement a test UI overlay

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