vengine  0.1.0
3D graphics engine made with Vulkan
Loading...
Searching...
No Matches
swapChain.cpp
Go to the documentation of this file.
1#include <iostream>
2#include <limits>
3#include <stdexcept>
4
6
8{
9 for (VkImageView_T *imageView : swapChainImageViews) {
10 vkDestroyImageView(device.device(), imageView, nullptr);
11 }
12 swapChainImageViews.clear();
13
14 if (swapChain != nullptr) {
15 vkDestroySwapchainKHR(device.device(), swapChain, nullptr);
16 swapChain = nullptr;
17 }
18
19 for (size_t i = 0; i < depthImages.size(); i++) {
20 vkDestroyImageView(device.device(), depthImageViews[i], nullptr);
21 vkDestroyImage(device.device(), depthImages[i], nullptr);
22 vkFreeMemory(device.device(), depthImageMemorys[i], nullptr);
23 }
24
25 for (VkFramebuffer_T *framebuffer : swapChainFramebuffers) {
26 vkDestroyFramebuffer(device.device(), framebuffer, nullptr);
27 }
28
29 vkDestroyRenderPass(device.device(), renderPass, nullptr);
30
31 // cleanup synchronization objects
32 for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
33 vkDestroySemaphore(device.device(), renderFinishedSemaphores[i], nullptr);
34 vkDestroySemaphore(device.device(), imageAvailableSemaphores[i], nullptr);
35 vkDestroyFence(device.device(), inFlightFences[i], nullptr);
36 }
37}
38
40{
41 createSwapChain();
42 createImageViews();
43 createRenderPass();
44 createDepthResources();
45 createFramebuffers();
46 createSyncObjects();
47}
48
49VkResult ven::SwapChain::acquireNextImage(uint32_t *imageIndex) const
50{
51 vkWaitForFences(device.device(), 1, &inFlightFences[currentFrame], VK_TRUE, std::numeric_limits<uint64_t>::max());
52
53 return vkAcquireNextImageKHR(device.device(), swapChain, std::numeric_limits<uint64_t>::max(), imageAvailableSemaphores[currentFrame], VK_NULL_HANDLE, imageIndex);;
54}
55
56VkResult ven::SwapChain::submitCommandBuffers(const VkCommandBuffer *buffers, const uint32_t *imageIndex)
57{
58 if (imagesInFlight[*imageIndex] != VK_NULL_HANDLE) {
59 vkWaitForFences(device.device(), 1, &imagesInFlight[*imageIndex], VK_TRUE, UINT64_MAX);
60 }
61 imagesInFlight[*imageIndex] = inFlightFences[currentFrame];
62
63 VkSubmitInfo submitInfo = {};
64 submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
65
66 const VkSemaphore waitSemaphores[] = {imageAvailableSemaphores[currentFrame]};
67 constexpr VkPipelineStageFlags waitStages[] = {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT};
68 submitInfo.waitSemaphoreCount = 1;
69 submitInfo.pWaitSemaphores = waitSemaphores;
70 submitInfo.pWaitDstStageMask = waitStages;
71
72 submitInfo.commandBufferCount = 1;
73 submitInfo.pCommandBuffers = buffers;
74
75 const VkSemaphore signalSemaphores[] = {renderFinishedSemaphores[currentFrame]};
76 submitInfo.signalSemaphoreCount = 1;
77 submitInfo.pSignalSemaphores = signalSemaphores;
78
79 vkResetFences(device.device(), 1, &inFlightFences[currentFrame]);
80 if (vkQueueSubmit(device.graphicsQueue(), 1, &submitInfo, inFlightFences[currentFrame]) != VK_SUCCESS) {
81 throw std::runtime_error("failed to submit draw command m_buffer!");
82 }
83
84 VkPresentInfoKHR presentInfo = {};
85 presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
86
87 presentInfo.waitSemaphoreCount = 1;
88 presentInfo.pWaitSemaphores = signalSemaphores;
89
90 const VkSwapchainKHR swapChains[] = {swapChain};
91 presentInfo.swapchainCount = 1;
92 presentInfo.pSwapchains = swapChains;
93
94 presentInfo.pImageIndices = imageIndex;
95
96 const VkResult result = vkQueuePresentKHR(device.presentQueue(), &presentInfo);
97
98 currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT;
99
100 return result;
101}
102
104{
105 const SwapChainSupportDetails swapChainSupport = device.getSwapChainSupport();
106
107 const VkSurfaceFormatKHR surfaceFormat = chooseSwapSurfaceFormat(swapChainSupport.formats);
108 const VkPresentModeKHR presentMode = chooseSwapPresentMode(swapChainSupport.presentModes);
109 const VkExtent2D extent = chooseSwapExtent(swapChainSupport.capabilities);
110
111 uint32_t imageCount = swapChainSupport.capabilities.minImageCount + 1;
112 if (swapChainSupport.capabilities.maxImageCount > 0 && imageCount > swapChainSupport.capabilities.maxImageCount) {
113 imageCount = swapChainSupport.capabilities.maxImageCount;
114 }
115
116 VkSwapchainCreateInfoKHR createInfo = {};
117 createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
118 createInfo.surface = device.surface();
119
120 createInfo.minImageCount = imageCount;
121 createInfo.imageFormat = surfaceFormat.format;
122 createInfo.imageColorSpace = surfaceFormat.colorSpace;
123 createInfo.imageExtent = extent;
124 createInfo.imageArrayLayers = 1;
125 createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
126
127 const QueueFamilyIndices indices = device.findPhysicalQueueFamilies();
128 const uint32_t queueFamilyIndices[] = {indices.graphicsFamily, indices.presentFamily};
129
130 if (indices.graphicsFamily != indices.presentFamily) {
131 createInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
132 createInfo.queueFamilyIndexCount = 2;
133 createInfo.pQueueFamilyIndices = queueFamilyIndices;
134 } else {
135 createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
136 createInfo.queueFamilyIndexCount = 0; // Optional
137 createInfo.pQueueFamilyIndices = nullptr; // Optional
138 }
139
140 createInfo.preTransform = swapChainSupport.capabilities.currentTransform;
141 createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
142
143 createInfo.presentMode = presentMode;
144 createInfo.clipped = VK_TRUE;
145
146 createInfo.oldSwapchain = oldSwapChain == nullptr ? VK_NULL_HANDLE : oldSwapChain->swapChain;
147
148 if (vkCreateSwapchainKHR(device.device(), &createInfo, nullptr, &swapChain) != VK_SUCCESS) {
149 throw std::runtime_error("failed to create swap chain!");
150 }
151
152 // we only specified a minimum number of images in the swap chain, so the implementation is
153 // allowed to create a swap chain with more. That's why we'll first query the final number of
154 // images with vkGetSwapchainImagesKHR, then resize the container and finally call it again to
155 // retrieve the handles.
156 vkGetSwapchainImagesKHR(device.device(), swapChain, &imageCount, nullptr);
157 swapChainImages.resize(imageCount);
158 vkGetSwapchainImagesKHR(device.device(), swapChain, &imageCount, swapChainImages.data());
159
160 swapChainImageFormat = surfaceFormat.format;
161 m_swapChainExtent = extent;
162}
163
165{
166 swapChainImageViews.resize(swapChainImages.size());
167 for (size_t i = 0; i < swapChainImages.size(); i++) {
168 VkImageViewCreateInfo viewInfo{};
169 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
170 viewInfo.image = swapChainImages[i];
171 viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
172 viewInfo.format = swapChainImageFormat;
173 viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
174 viewInfo.subresourceRange.baseMipLevel = 0;
175 viewInfo.subresourceRange.levelCount = 1;
176 viewInfo.subresourceRange.baseArrayLayer = 0;
177 viewInfo.subresourceRange.layerCount = 1;
178
179 if (vkCreateImageView(device.device(), &viewInfo, nullptr, &swapChainImageViews[i]) != VK_SUCCESS) {
180 throw std::runtime_error("failed to create texture image view!");
181 }
182 }
183}
184
186{
187 VkAttachmentDescription depthAttachment{};
188 depthAttachment.format = findDepthFormat();
189 depthAttachment.samples = VK_SAMPLE_COUNT_1_BIT;
190 depthAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
191 depthAttachment.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
192 depthAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
193 depthAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
194 depthAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
195 depthAttachment.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
196
197 VkAttachmentReference depthAttachmentRef{};
198 depthAttachmentRef.attachment = 1;
199 depthAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
200
201 VkAttachmentDescription colorAttachment = {};
202 colorAttachment.format = getSwapChainImageFormat();
203 colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT;
204 colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
205 colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
206 colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
207 colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
208 colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
209 colorAttachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
210
211 VkAttachmentReference colorAttachmentRef = {};
212 colorAttachmentRef.attachment = 0;
213 colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
214
215 VkSubpassDescription subpass = {};
216 subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
217 subpass.colorAttachmentCount = 1;
218 subpass.pColorAttachments = &colorAttachmentRef;
219 subpass.pDepthStencilAttachment = &depthAttachmentRef;
220
221 VkSubpassDependency dependency = {};
222 dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
223 dependency.srcAccessMask = 0;
224 dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
225 dependency.dstSubpass = 0;
226 dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
227 dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
228
229 const std::array<VkAttachmentDescription, 2> attachments = {colorAttachment, depthAttachment};
230 VkRenderPassCreateInfo renderPassInfo = {};
231 renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
232 renderPassInfo.attachmentCount = static_cast<uint32_t>(attachments.size());
233 renderPassInfo.pAttachments = attachments.data();
234 renderPassInfo.subpassCount = 1;
235 renderPassInfo.pSubpasses = &subpass;
236 renderPassInfo.dependencyCount = 1;
237 renderPassInfo.pDependencies = &dependency;
238
239 if (vkCreateRenderPass(device.device(), &renderPassInfo, nullptr, &renderPass) != VK_SUCCESS) {
240 throw std::runtime_error("failed to create render pass!");
241 }
242}
243
245{
246 swapChainFramebuffers.resize(imageCount());
247 for (size_t i = 0; i < imageCount(); i++) {
248 std::array<VkImageView, 2> attachments = {swapChainImageViews[i], depthImageViews[i]};
249
250 const VkExtent2D swapChainExtent = getSwapChainExtent();
251 VkFramebufferCreateInfo framebufferInfo = {};
252 framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
253 framebufferInfo.renderPass = renderPass;
254 framebufferInfo.attachmentCount = static_cast<uint32_t>(attachments.size());
255 framebufferInfo.pAttachments = attachments.data();
256 framebufferInfo.width = swapChainExtent.width;
257 framebufferInfo.height = swapChainExtent.height;
258 framebufferInfo.layers = 1;
259
260 if (vkCreateFramebuffer(device.device(), &framebufferInfo, nullptr, &swapChainFramebuffers[i]) != VK_SUCCESS) {
261 throw std::runtime_error("failed to create framebuffer!");
262 }
263 }
264}
265
267{
268 const VkFormat depthFormat = findDepthFormat();
269 const VkExtent2D swapChainExtent = getSwapChainExtent();
270
271 swapChainDepthFormat = depthFormat;
272 depthImages.resize(imageCount());
273 depthImageMemorys.resize(imageCount());
274 depthImageViews.resize(imageCount());
275
276 for (size_t i = 0; i < depthImages.size(); i++) {
277 VkImageCreateInfo imageInfo{};
278 imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
279 imageInfo.imageType = VK_IMAGE_TYPE_2D;
280 imageInfo.extent.width = swapChainExtent.width;
281 imageInfo.extent.height = swapChainExtent.height;
282 imageInfo.extent.depth = 1;
283 imageInfo.mipLevels = 1;
284 imageInfo.arrayLayers = 1;
285 imageInfo.format = depthFormat;
286 imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
287 imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
288 imageInfo.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
289 imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
290 imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
291 imageInfo.flags = 0;
292
293 device.createImageWithInfo(imageInfo, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, depthImages[i], depthImageMemorys[i]);
294
295 VkImageViewCreateInfo viewInfo{};
296 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
297 viewInfo.image = depthImages[i];
298 viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
299 viewInfo.format = depthFormat;
300 viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
301 viewInfo.subresourceRange.baseMipLevel = 0;
302 viewInfo.subresourceRange.levelCount = 1;
303 viewInfo.subresourceRange.baseArrayLayer = 0;
304 viewInfo.subresourceRange.layerCount = 1;
305
306 if (vkCreateImageView(device.device(), &viewInfo, nullptr, &depthImageViews[i]) != VK_SUCCESS) {
307 throw std::runtime_error("failed to create texture image view!");
308 }
309 }
310}
311
313{
314 imageAvailableSemaphores.resize(MAX_FRAMES_IN_FLIGHT);
315 renderFinishedSemaphores.resize(MAX_FRAMES_IN_FLIGHT);
316 inFlightFences.resize(MAX_FRAMES_IN_FLIGHT);
317 imagesInFlight.resize(imageCount(), VK_NULL_HANDLE);
318
319 VkSemaphoreCreateInfo semaphoreInfo = {};
320 semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
321
322 VkFenceCreateInfo fenceInfo = {};
323 fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
324 fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
325
326 for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
327 if (vkCreateSemaphore(device.device(), &semaphoreInfo, nullptr, &imageAvailableSemaphores[i]) != VK_SUCCESS ||
328 vkCreateSemaphore(device.device(), &semaphoreInfo, nullptr, &renderFinishedSemaphores[i]) != VK_SUCCESS ||
329 vkCreateFence(device.device(), &fenceInfo, nullptr, &inFlightFences[i]) != VK_SUCCESS) {
330 throw std::runtime_error("failed to create synchronization objects for a frame!");
331 }
332 }
333}
334
335VkSurfaceFormatKHR ven::SwapChain::chooseSwapSurfaceFormat(const std::vector<VkSurfaceFormatKHR> &availableFormats)
336{
337 for (const auto &availableFormat : availableFormats) {
338 if (availableFormat.format == VK_FORMAT_B8G8R8A8_UNORM && availableFormat.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
339 return availableFormat;
340 }
341 }
342
343 return availableFormats[0];
344}
345
346VkPresentModeKHR ven::SwapChain::chooseSwapPresentMode(const std::vector<VkPresentModeKHR> &availablePresentModes)
347{
348 for (const auto &availablePresentMode : availablePresentModes) {
349 if (availablePresentMode == VK_PRESENT_MODE_MAILBOX_KHR) {
350 std::cout << "Present mode: Mailbox\n";
351 return availablePresentMode;
352 }
353 }
354
355 for (const auto &availablePresentMode : availablePresentModes) {
356 if (availablePresentMode == VK_PRESENT_MODE_IMMEDIATE_KHR) {
357 std::cout << "Present mode: Immediate" << '\n';
358 return availablePresentMode;
359 }
360 }
361
362 std::cout << "Present mode: V-Sync\n";
363 return VK_PRESENT_MODE_FIFO_KHR;
364}
365
366VkExtent2D ven::SwapChain::chooseSwapExtent(const VkSurfaceCapabilitiesKHR &capabilities) const
367{
368 if (capabilities.currentExtent.width != std::numeric_limits<uint32_t>::max()) {
369 return capabilities.currentExtent;
370 }
371 VkExtent2D actualExtent = windowExtent;
372 actualExtent.width = std::max(capabilities.minImageExtent.width, std::min(capabilities.maxImageExtent.width, actualExtent.width));
373 actualExtent.height = std::max(capabilities.minImageExtent.height, std::min(capabilities.maxImageExtent.height, actualExtent.height));
374
375 return actualExtent;
376}
377
379{
380 return device.findSupportedFormat(
381 {VK_FORMAT_D32_SFLOAT, VK_FORMAT_D32_SFLOAT_S8_UINT, VK_FORMAT_D24_UNORM_S8_UINT},
382 VK_IMAGE_TILING_OPTIMAL,
383 VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT);
384}
This file contains the Shader class.
VkDevice device() const
Definition Device.hpp:48
Device & device
Definition SwapChain.hpp:75
std::vector< VkImageView > depthImageViews
Definition SwapChain.hpp:71
VkExtent2D chooseSwapExtent(const VkSurfaceCapabilitiesKHR &capabilities) const
static VkPresentModeKHR chooseSwapPresentMode(const std::vector< VkPresentModeKHR > &availablePresentModes)
std::vector< VkImageView > swapChainImageViews
Definition SwapChain.hpp:73
std::vector< VkFramebuffer > swapChainFramebuffers
Definition SwapChain.hpp:66
VkResult acquireNextImage(uint32_t *imageIndex) const
Definition swapChain.cpp:49
std::vector< VkFence > inFlightFences
Definition SwapChain.hpp:83
void createFramebuffers()
void createSwapChain()
void createDepthResources()
std::vector< VkSemaphore > renderFinishedSemaphores
Definition SwapChain.hpp:82
void createSyncObjects()
void createImageViews()
VkFormat findDepthFormat() const
VkResult submitCommandBuffers(const VkCommandBuffer *buffers, const uint32_t *imageIndex)
Definition swapChain.cpp:56
static constexpr int MAX_FRAMES_IN_FLIGHT
Definition SwapChain.hpp:20
std::vector< VkDeviceMemory > depthImageMemorys
Definition SwapChain.hpp:70
VkRenderPass renderPass
Definition SwapChain.hpp:67
void createRenderPass()
VkSwapchainKHR swapChain
Definition SwapChain.hpp:78
std::vector< VkImage > depthImages
Definition SwapChain.hpp:69
std::vector< VkSemaphore > imageAvailableSemaphores
Definition SwapChain.hpp:81
static VkSurfaceFormatKHR chooseSwapSurfaceFormat(const std::vector< VkSurfaceFormatKHR > &availableFormats)
std::vector< VkPresentModeKHR > presentModes
Definition Device.hpp:18
VkSurfaceCapabilitiesKHR capabilities
Definition Device.hpp:16
std::vector< VkSurfaceFormatKHR > formats
Definition Device.hpp:17