SimpleGL  1.1.0
A framework for platform independent rendering
swapchain.cpp
Go to the documentation of this file.
1 
9 
10 #include <stdexcept>
11 #include <algorithm>
12 
14 
15 using namespace std;
16 
17 namespace sgl {
18 
19  Swapchain::Swapchain(Surface* surface, glm::ivec2 size) {
20  VkDevice device = VulkanContext::getCurrent()->getDevice()->getHandle();
21  SwapchainSupportDetails swapchainSupportDetail = VulkanContext::getCurrent()->getPhysicalDevice()->getSwapchainSupportDetails();
22 
23  /* Check if the surface has no preferred format */
24  VkSurfaceFormatKHR surfaceFormat = swapchainSupportDetail.surfaceFormats[0];
25  if (swapchainSupportDetail.surfaceFormats.size() == 1 &&
26  swapchainSupportDetail.surfaceFormats[0].format == VK_FORMAT_UNDEFINED) {
27  surfaceFormat.format = VK_FORMAT_B8G8R8A8_UNORM;
28  surfaceFormat.colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
29  } else {
30  /* Choose a surface format */
31  for (uint32_t i = 0; i < swapchainSupportDetail.surfaceFormats.size(); i++) {
32  VkSurfaceFormatKHR surfaceFormatCandidate = swapchainSupportDetail.surfaceFormats[i];
33  if (surfaceFormatCandidate.format == VK_FORMAT_B8G8R8A8_UNORM &&
34  surfaceFormatCandidate.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
35  surfaceFormat = surfaceFormatCandidate;
36  break;
37  }
38  }
39  }
40 
41  /* Choose a present mode */
42  VkPresentModeKHR presentMode = VK_PRESENT_MODE_FIFO_KHR;
43  for (uint32_t i = 0; i < swapchainSupportDetail.presentModes.size(); i++) {
44  VkPresentModeKHR presentModeCandidate = swapchainSupportDetail.presentModes[i];
45  if (presentModeCandidate == VK_PRESENT_MODE_MAILBOX_KHR) {
46  presentMode = presentModeCandidate;
47  break;
48  } else if (presentModeCandidate == VK_PRESENT_MODE_IMMEDIATE_KHR) {
49  presentMode = presentModeCandidate;
50  }
51  }
52 
53  /* Check if the extent is defined */
54  VkExtent2D extent = {static_cast<uint32_t> (size.x), static_cast<uint32_t> (size.y)};
55  if (swapchainSupportDetail.surfaceCapabilities.currentExtent.width != numeric_limits<uint32_t>::max()) {
56  extent = swapchainSupportDetail.surfaceCapabilities.currentExtent;
57  } else {
58  /* Choose a swapchain extent */
59  extent.width = max(swapchainSupportDetail.surfaceCapabilities.minImageExtent.width,
60  min(swapchainSupportDetail.surfaceCapabilities.maxImageExtent.width, extent.width));
61  extent.height = max(swapchainSupportDetail.surfaceCapabilities.minImageExtent.height,
62  min(swapchainSupportDetail.surfaceCapabilities.maxImageExtent.height, extent.height));
63  }
64 
65  /* Check for image limits */
66  uint32_t imageCount = swapchainSupportDetail.surfaceCapabilities.minImageCount;
67  if (swapchainSupportDetail.surfaceCapabilities.maxImageCount > 0 &&
68  imageCount > swapchainSupportDetail.surfaceCapabilities.maxImageCount) {
69  imageCount = swapchainSupportDetail.surfaceCapabilities.maxImageCount;
70  }
71 
72  /* Initialize a swapchain create info */
73  QueueFamilyIndices queueFamilyIndices = VulkanContext::getCurrent()->getPhysicalDevice()->getQueueFamilyIndices();
74  vector<uint32_t> queueFamilyIndicesVector = {
75  static_cast<uint32_t> (queueFamilyIndices.graphics),
76  static_cast<uint32_t> (queueFamilyIndices.presentation)
77  };
78  VkSwapchainCreateInfoKHR createInfo = {};
79  createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
80  createInfo.surface = surface->getHandle();
81  createInfo.minImageCount = imageCount;
82  createInfo.imageFormat = surfaceFormat.format;
83  createInfo.imageColorSpace = surfaceFormat.colorSpace;
84  createInfo.imageExtent = extent;
85  createInfo.imageArrayLayers = 1;
86  createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
87  if (queueFamilyIndices.graphics != queueFamilyIndices.presentation) {
88  createInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
89  createInfo.queueFamilyIndexCount = queueFamilyIndicesVector.size();
90  createInfo.pQueueFamilyIndices = queueFamilyIndicesVector.data();
91  } else {
92  createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
93  }
94  createInfo.preTransform = swapchainSupportDetail.surfaceCapabilities.currentTransform;
95  createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
96  createInfo.presentMode = presentMode;
97  createInfo.clipped = VK_TRUE;
98  createInfo.oldSwapchain = VK_NULL_HANDLE;
99 
100  /* Create the swapchain */
101  if (vkCreateSwapchainKHR(device, &createInfo, nullptr, &handle) != VK_SUCCESS) {
102  throw runtime_error("Could not create a swapchain!");
103  }
104 
105  /* Get the number of available swapchain images */
106  vkGetSwapchainImagesKHR(device, handle, &imageCount, nullptr);
107 
108  /* Get all swapchain images */
109  swapchainData.images.resize(imageCount);
110  vkGetSwapchainImagesKHR(device, handle, &imageCount, swapchainData.images.data());
111 
112  /* Create the image views */
113  swapchainData.imageViews.resize(swapchainData.images.size());
114  for (uint32_t i = 0; i < swapchainData.images.size(); i++) {
115  /* Initialize a image view create info */
116  VkImageViewCreateInfo viewCreateInfo = {};
117  viewCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
118  viewCreateInfo.image = swapchainData.images[i];
119  viewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
120  viewCreateInfo.format = surfaceFormat.format;
121  viewCreateInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
122  viewCreateInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
123  viewCreateInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
124  viewCreateInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
125  viewCreateInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
126  viewCreateInfo.subresourceRange.baseMipLevel = 0;
127  viewCreateInfo.subresourceRange.levelCount = 1;
128  viewCreateInfo.subresourceRange.baseArrayLayer = 0;
129  viewCreateInfo.subresourceRange.layerCount = 1;
130 
131  /* Create the image view */
132  if (vkCreateImageView(device, &viewCreateInfo, nullptr, &swapchainData.imageViews[i]) != VK_SUCCESS) {
133  throw runtime_error("Could not create image views for the swapchain images!");
134  }
135  }
136 
137  /* Initialize the swapchain data */
138  swapchainData.imageFormat = surfaceFormat.format;
139  swapchainData.extent = extent;
140  swapchainData.index = -1;
141  }
142 
143  Swapchain::~Swapchain(void) {
144  VkDevice device = VulkanContext::getCurrent()->getDevice()->getHandle();
145 
146  /* Destroy the image views */
147  for (uint32_t i = 0; i < swapchainData.imageViews.size(); i++) {
148  vkDestroyImageView(device, swapchainData.imageViews[i], nullptr);
149  }
150 
151  /* Destroy the swapchain */
152  vkDestroySwapchainKHR(device, handle, nullptr);
153  }
154 
155  VkSwapchainKHR Swapchain::getHandle() {
156  return handle;
157  }
158 
159  SwapchainData Swapchain::getSwapchainData() {
160  return swapchainData;
161  }
162 
163  void Swapchain::acquireNextImage() {
164  VkDevice device = VulkanContext::getCurrent()->getDevice()->getHandle();
165  VkFence fence = VulkanContext::getCurrent()->getRenderFence()->getHandle();
166 
167  /* Wait for the submit fence */
168  vkWaitForFences(device, 1, &fence, VK_TRUE, std::numeric_limits<uint64_t>::max());
169  vkResetFences(device, 1, &fence);
170 
171  /* Acquire the next image */
172  VkResult result = vkAcquireNextImageKHR(device, handle, numeric_limits<uint64_t>::max(), VK_NULL_HANDLE, fence, &swapchainData.index);
173 
174  /* Error handling */
175  if (result == VK_ERROR_OUT_OF_DATE_KHR) {
176  // ToDo: Swapchain recreation
177  } else if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR) {
178  throw runtime_error("Could not acquire next swapchain image!");
179  }
180  }
181 
182  void Swapchain::present() {
183  VkQueue queue = VulkanContext::getCurrent()->getDevice()->getQueues().presentation;
184 
185  /* Initialize a present info */
186  VkPresentInfoKHR presentInfo = {};
187  presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
188  presentInfo.swapchainCount = 1;
189  presentInfo.pSwapchains = &handle;
190  presentInfo.pImageIndices = &swapchainData.index;
191 
192  /* Present the swapchain image */
193  VkResult result = vkQueuePresentKHR(queue, &presentInfo);
194 
195  /* Error handling */
196  if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR) {
197  // ToDo: Swapchain recreation
198  } else if (result != VK_SUCCESS) {
199  throw runtime_error("Could not present swapchain image!");
200  }
201  }
202 }
int32_t presentation
The index of the presentation queue family.
This struct stores relevant queue family indices.
std::vector< VkSurfaceFormatKHR > surfaceFormats
The supported surface formats.
This struct stores necessary data for swapchain support.
Generic namespace for the SimpleGL framework.
Definition: application.hpp:18
VkSurfaceKHR getHandle()
Returns the hande of the surface.
Definition: surface.cpp:37
This struct stores relevant swapchain data.
Definition: swapchain.hpp:28
VkSurfaceCapabilitiesKHR surfaceCapabilities
The basic capabilities of a surface.
std::vector< VkPresentModeKHR > presentModes
The supported present modes.
int32_t graphics
The index of the graphics queue family.
This class wraps a Vulkan surface.
Definition: surface.hpp:25