Chronos 0.0
A advanced 2D rendering and animation system
Loading...
Searching...
No Matches
swapchain.cpp
Go to the documentation of this file.
1/*
2Copyright (c) 2024 Rahul Satish Vadhyar
3
4Permission is hereby granted, free of charge, to any person obtaining a copy
5of this software and associated documentation files (the "Software"), to deal
6in the Software without restriction, including without limitation the rights
7to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8copies of the Software, and to permit persons to whom the Software is
9furnished to do so, subject to the following conditions:
10
11The above copyright notice and this permission notice shall be included in all
12copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20SOFTWARE.
21*/
22#include <algorithm>
23#include "swapchain.hpp"
24#include "helper.hpp"
25#include "texture.hpp"
27 const std::vector<VkSurfaceFormatKHR>& availableFormats)
28{
29 // try to choose SRBG format, else return the first available format
30 for (const auto& availableFormat : availableFormats) {
31 if (availableFormat.format == VK_FORMAT_B8G8R8A8_SRGB
32 && availableFormat.colorSpace
33 == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
34 return availableFormat;
35 }
36 }
37
38 return availableFormats[0];
39}
40
42 const VkSurfaceCapabilitiesKHR& capabilities, GLFWwindow* window)
43{
44 if (capabilities.currentExtent.width
45 != std::numeric_limits<uint32_t>::max()) {
46 return capabilities.currentExtent;
47 } else {
48 int width, height;
49 glfwGetFramebufferSize(window, &width, &height);
50
51 VkExtent2D actualExtent
52 = { static_cast<uint32_t>(width), static_cast<uint32_t>(height) };
53
54 actualExtent.width
55 = std::clamp(actualExtent.width, capabilities.minImageExtent.width,
56 capabilities.maxImageExtent.width);
57 actualExtent.height = std::clamp(actualExtent.height,
58 capabilities.minImageExtent.height,
59 capabilities.maxImageExtent.height);
60
61 return actualExtent;
62 }
63}
64
66 VkPhysicalDevice device, VkSurfaceKHR surface)
67{
69 vkGetPhysicalDeviceSurfaceCapabilitiesKHR(
70 device, surface, &details.capabilities);
71
72 uint32_t formatCount;
73 vkGetPhysicalDeviceSurfaceFormatsKHR(
74 device, surface, &formatCount, nullptr);
75
76 if (formatCount != 0) {
77 details.formats.resize(formatCount);
78 vkGetPhysicalDeviceSurfaceFormatsKHR(
79 device, surface, &formatCount, details.formats.data());
80 }
81
82 uint32_t presentModeCount;
83 vkGetPhysicalDeviceSurfacePresentModesKHR(
84 device, surface, &presentModeCount, nullptr);
85
86 if (presentModeCount != 0) {
87 details.presentModes.resize(presentModeCount);
88 vkGetPhysicalDeviceSurfacePresentModesKHR(
89 device, surface, &presentModeCount, details.presentModes.data());
90 }
91
92 return details;
93}
95 Chronos::Engine::Device* device, VkSurfaceKHR surface, GLFWwindow* window)
96{
97 this->device = device;
98 this->surface = surface;
99 this->window = window;
100 create();
103}
104
106{
107 // create the swapchain
108 SwapChainSupportDetails swapChainSupport
110 (*device).physicalDevice, surface);
111 VkSurfaceFormatKHR surfaceFormat
113 VkPresentModeKHR presentMode
114 = this->chooseSwapPresentMode(swapChainSupport.presentModes);
115 VkExtent2D extent = Chronos::Engine::chooseSwapExtent(
116 swapChainSupport.capabilities, window);
117
118 // set the number of images in the swap chain
119 uint32_t imageCount = swapChainSupport.capabilities.minImageCount + 1;
120
121 // check if the number of images exceeds the maximum possible images
122 // supprted
123 if (swapChainSupport.capabilities.maxImageCount > 0
124 && imageCount > swapChainSupport.capabilities.maxImageCount) {
125 imageCount = swapChainSupport.capabilities.maxImageCount;
126 }
127
128 VkSwapchainCreateInfoKHR createInfo {};
129 createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
130 createInfo.surface = surface;
131 createInfo.minImageCount = imageCount;
132 createInfo.imageFormat = surfaceFormat.format;
133 createInfo.imageColorSpace = surfaceFormat.colorSpace;
134 createInfo.imageExtent = extent;
135 createInfo.imageArrayLayers = 1;
136 createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
137
139 = Chronos::Engine::findQueueFamilies(device->physicalDevice, surface);
140 uint32_t queueFamilyIndices[]
141 = { indices.graphicsFamily.value(), indices.presentFamily.value() };
142
143 if (indices.graphicsFamily != indices.presentFamily) {
144 createInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
145 createInfo.queueFamilyIndexCount = 2;
146 createInfo.pQueueFamilyIndices = queueFamilyIndices;
147 } else {
148 createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
149 createInfo.queueFamilyIndexCount = 0; // Optional
150 createInfo.pQueueFamilyIndices = nullptr; // Optional
151 }
152 createInfo.preTransform = swapChainSupport.capabilities.currentTransform;
153 createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
154 createInfo.presentMode = presentMode;
155 createInfo.clipped = VK_TRUE;
156 createInfo.oldSwapchain = NULL;
157
158 if (vkCreateSwapchainKHR(device->device, &createInfo, nullptr, &swapChain)
159 != VK_SUCCESS) {
160 throw std::runtime_error("Failed to create swap chain");
161 }
162 vkGetSwapchainImagesKHR(device->device, swapChain, &imageCount, nullptr);
163 swapChainImages.resize(imageCount);
164 vkGetSwapchainImagesKHR(
165 device->device, swapChain, &imageCount, swapChainImages.data());
166 swapChainImageFormat = surfaceFormat.format;
167 swapChainExtent = extent;
168}
169
171{
172 swapChainImageViews.resize(swapChainImages.size());
173 for (size_t i = 0; i < swapChainImages.size(); i++) {
174 swapChainImageViews[i] = Chronos::Engine::createImageView(
175 *device, swapChainImageFormat, swapChainImages[i]);
176 }
177}
178
180{
181 VkFormat colorFormat = swapChainImageFormat;
182 createImage(*device, swapChainExtent.width, swapChainExtent.height,
183 colorFormat, VK_IMAGE_TILING_OPTIMAL,
184 VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT
185 | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
186 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &colorImage, &colorImageMemory,
187 device->msaaSamples);
188
189 colorImageView
190 = Chronos::Engine::createImageView(*device, colorFormat, colorImage);
191}
192
194{
195 vkDestroyImageView(device->device, colorImageView, nullptr);
196 vkDestroyImage(device->device, colorImage, nullptr);
197 vkFreeMemory(device->device, colorImageMemory, nullptr);
198 // destroy the image views
199 for (auto imageView : swapChainImageViews) {
200 vkDestroyImageView(device->device, imageView, nullptr);
201 }
202 // destroy the swap chain
203 vkDestroySwapchainKHR(device->device, swapChain, nullptr);
204}
205
207{
208 int width = 0, height = 0;
209 glfwGetFramebufferSize(window, &width, &height);
210 while (width == 0 || height == 0) {
211 glfwGetFramebufferSize(window, &width, &height);
212 glfwWaitEvents();
213 }
214
215 vkDeviceWaitIdle(device->device);
216
217 cleanup();
218 create();
219 createImageViews();
220 createColorResources();
221}
222
224{
225 // if we want to change msaa, we need to recreate the swapchain
226 vkDeviceWaitIdle(device->device);
227 cleanup();
228 create();
229 createImageViews();
230 createColorResources();
231}
232
234 const std::vector<VkPresentModeKHR>& availablePresentModes)
235{
236 // The presentation modes available
237 // VK_PRESENT_MODE_IMMEDIATE_KHR: Images submitted by your application are
238 // transferred to the screen right away, which may result in tearing.
239 // VK_PRESENT_MODE_FIFO_KHR : The swap chain is a queue where the display
240 // takes an image from the front of the queue when the display is refreshed
241 // and the program inserts
242 // rendered images at the
243 // back of the queue.If the queue is full then the program has to wait.
244 // This is most similar to vertical sync as found in modern games.The moment
245 // that the display is refreshed is known as
246 // "vertical blank". VK_PRESENT_MODE_FIFO_RELAXED_KHR : This mode only
247 // differs from the previous one if the application is late and the queue
248 // was empty at the last
249 // vertical blank.Instead of waiting for the next vertical blank, the image
250 // is transferred right away when it
251 // finally arrives.This may result in visible tearing.
252 // VK_PRESENT_MODE_MAILBOX_KHR : This is another variation of the second
253 // mode.Instead of blocking the application when the queue is full, the
254 // images that are already
255 // queued are simply replaced with the newer ones.This mode can be used to
256 // render frames as fast as
257 // possible while still avoiding tearing, resulting in fewer latency issues
258 // than standard vertical sync.This is commonly
259 // known as "triple buffering", although the existence of three buffers
260 // alone does not necessarily mean that the framerate
261 // is unlocked.
262
263 // try to select mailbox mode, else select the default FIFO mode
264 for (const auto& availablePresentMode : availablePresentModes) {
265 if (availablePresentMode == this->preferredPresentMode) {
266 return availablePresentMode;
267 }
268 }
269
270 return VK_PRESENT_MODE_FIFO_KHR;
271}
This initializes, manages and destroys the logical and physical devices(GPU).
Definition device.hpp:47
void createImageViews()
Creates the image views of the swapchain images.
Chronos::Engine::Device * device
Device to which swapchain needs to be created.
VkSurfaceKHR surface
Surface to which we need to present the swapchain images.
void create()
Creates the swapchain image resources and chooses the optimal settings for given hardware.
void cleanup()
Cleans up the assets that are rendered invalid during MSAA changes or swapchain.
GLFWwindow * window
The window to present the surface to.
void recreate()
When the swapchain is rendered invalid, recreate it.
void init(Chronos::Engine::Device *device, VkSurfaceKHR surface, GLFWwindow *window)
Initilize the swapchain.
Definition swapchain.cpp:94
void createColorResources()
Creates the color images along with the associated objects.
VkPresentModeKHR chooseSwapPresentMode(const std::vector< VkPresentModeKHR > &availablePresentModes)
From the available present mode, this chooses the the best present mode.
void changeMsaa()
Changes the MSAA count of the swapchain images.
Contains various common functions used by other classes in the Engine namespace.
VkImageView createImageView(Chronos::Engine::Device device, VkFormat format, VkImage image)
Create a VkImageView for a given VkImage.
Definition texture.cpp:255
VkExtent2D chooseSwapExtent(const VkSurfaceCapabilitiesKHR &capabilities, GLFWwindow *window)
Gets the maximum extent of the swapchain images(framebuffer size).
Definition swapchain.cpp:41
VkSurfaceFormatKHR chooseSwapSurfaceFormat(const std::vector< VkSurfaceFormatKHR > &availableFormats)
Chooses the best present mode among the supported modes.
Definition swapchain.cpp:26
void createImage(Chronos::Engine::Device device, uint32_t width, uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags properties, VkImage *image, VkDeviceMemory *imageMemory, VkSampleCountFlagBits numSamples)
For a given image dimensons, it creates a VkImage and.
Definition texture.cpp:42
SwapChainSupportDetails querySwapChainSupport(VkPhysicalDevice device, VkSurfaceKHR surface)
For a given swapchain mode, it gets the capabilites, formats and present modes.
Definition swapchain.cpp:65
QueueFamilyIndices findQueueFamilies(VkPhysicalDevice device, VkSurfaceKHR surface)
Gets the indices of the needed queue families.
Definition helper.cpp:126
This is used to check if a given familty supports graphics and presentation.
Definition helper.hpp:44
std::optional< uint32_t > presentFamily
Definition helper.hpp:46
std::optional< uint32_t > graphicsFamily
Definition helper.hpp:45
Contains the fields to the support details of a physical device.
Definition swapchain.hpp:36
VkSurfaceCapabilitiesKHR capabilities
Definition swapchain.hpp:37
std::vector< VkSurfaceFormatKHR > formats
Definition swapchain.hpp:38
std::vector< VkPresentModeKHR > presentModes
Definition swapchain.hpp:39
Contains the swapChain class along with all the swapChain related functions.
Contains the functions for image manipulation along with the Texture class.