VEX Engine
Retro looking game engine made in vulkan mostly because i wanted to understand it better.
Loading...
Searching...
No Matches
SwapchainManager.cpp
2
3#include <vector>
4#include <algorithm>
5#include <set>
6#include <limits>
7#include <cassert>
8#include <array>
9#include "limits.hpp"
10
11namespace vex {
12 VulkanSwapchainManager::VulkanSwapchainManager(VulkanContext& context, SDL_Window* window) : m_r_context(context) {
13 m_p_window = window;
14 }
19
21 log("Creating Swapchain");
22 VkSurfaceCapabilitiesKHR capabilities;
23 if (vkGetPhysicalDeviceSurfaceCapabilitiesKHR(m_r_context.physicalDevice, m_r_context.surface, &capabilities) != VK_SUCCESS) {
24 throw_error("Failed to get surface capabilities");
25 }
26
27 uint32_t formatCount;
28 vkGetPhysicalDeviceSurfaceFormatsKHR(m_r_context.physicalDevice, m_r_context.surface, &formatCount, nullptr);
29 if (formatCount == 0) {
30 throw_error("No surface formats supported");
31 }
32 std::vector<VkSurfaceFormatKHR> formats(formatCount);
33 vkGetPhysicalDeviceSurfaceFormatsKHR(m_r_context.physicalDevice, m_r_context.surface, &formatCount, formats.data());
34
35 uint32_t presentModeCount;
36 vkGetPhysicalDeviceSurfacePresentModesKHR(m_r_context.physicalDevice, m_r_context.surface, &presentModeCount, nullptr);
37 if (presentModeCount == 0) {
38 throw_error("No present modes supported");
39 }
40
41 std::vector<VkPresentModeKHR> presentModes(presentModeCount);
42 vkGetPhysicalDeviceSurfacePresentModesKHR(m_r_context.physicalDevice, m_r_context.surface, &presentModeCount, presentModes.data());
43
44 VkSurfaceFormatKHR surfaceFormat = chooseSwapSurfaceFormat(formats);
45 VkPresentModeKHR presentMode = chooseSwapPresentMode(presentModes);
46 VkExtent2D extent = chooseSwapExtent(capabilities);
47
48 VkFormatProperties formatProps;
49 vkGetPhysicalDeviceFormatProperties(m_r_context.physicalDevice, surfaceFormat.format, &formatProps);
50
51 uint32_t imageCount = capabilities.minImageCount + 1;
52 if (capabilities.maxImageCount > 0 && imageCount > capabilities.maxImageCount) {
53 imageCount = capabilities.maxImageCount;
54 }
55
56 m_r_context.MAX_FRAMES_IN_FLIGHT = imageCount;
57 VkSwapchainKHR oldSwapchain = m_r_context.swapchain;
58
59 VkSwapchainCreateInfoKHR createInfo = {};
60 createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
61 createInfo.surface = m_r_context.surface;
62 createInfo.minImageCount = imageCount;
63 createInfo.imageFormat = surfaceFormat.format;
64 createInfo.imageColorSpace = surfaceFormat.colorSpace;
65 createInfo.imageExtent = extent;
66 createInfo.imageArrayLayers = 1;
67 createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
68
69 uint32_t queueFamilyIndices[] = {m_r_context.graphicsQueueFamily, m_r_context.presentQueueFamily};
70 if (m_r_context.graphicsQueueFamily != m_r_context.presentQueueFamily) {
71 createInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
72 createInfo.queueFamilyIndexCount = 2;
73 createInfo.pQueueFamilyIndices = queueFamilyIndices;
74 } else {
75 createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
76 createInfo.queueFamilyIndexCount = 0;
77 createInfo.pQueueFamilyIndices = nullptr;
78 }
79
80 createInfo.preTransform = capabilities.currentTransform;
81 createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
82 createInfo.presentMode = presentMode;
83 createInfo.clipped = VK_TRUE;
84 createInfo.oldSwapchain = oldSwapchain;
85
86 VkSwapchainKHR newSwapchain;
87 if (vkCreateSwapchainKHR(m_r_context.device, &createInfo, nullptr, &newSwapchain) != VK_SUCCESS)
88 {
89 throw_error("Failed to create swapchain");
90 }
91
92 if (oldSwapchain != VK_NULL_HANDLE)
93 {
94 vkDestroySwapchainKHR(m_r_context.device, oldSwapchain, nullptr);
95 }
96
97 m_r_context.swapchain = newSwapchain;
98 vkGetSwapchainImagesKHR(m_r_context.device, m_r_context.swapchain, &imageCount, nullptr);
99 m_r_context.swapchainImages.resize(imageCount);
100 vkGetSwapchainImagesKHR(m_r_context.device, m_r_context.swapchain, &imageCount, m_r_context.swapchainImages.data());
101
102 m_r_context.swapchainImageFormat = surfaceFormat.format;
103 m_r_context.swapchainExtent = extent;
104
105 for (auto &view : m_r_context.swapchainImageViews)
106 {
107 if (view != VK_NULL_HANDLE)
108 vkDestroyImageView(m_r_context.device, view, nullptr);
109 }
110 m_r_context.swapchainImageViews.clear();
111
113
114 if (m_r_context.commandPools.empty()) {
116 }
117
118 VkCommandBuffer cmd = m_r_context.beginSingleTimeCommands();
119
120 for (auto& image : m_r_context.swapchainImages) {
121 VkImageMemoryBarrier barrier{};
122 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
123 barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
124 barrier.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
125 barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
126 barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
127 barrier.image = image;
128 barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
129 barrier.subresourceRange.levelCount = 1;
130 barrier.subresourceRange.layerCount = 1;
131
132 vkCmdPipelineBarrier(
133 cmd,
134 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
135 VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
136 0,
137 0, nullptr,
138 0, nullptr,
139 1, &barrier
140 );
141 }
142
143 m_r_context.endSingleTimeCommands(cmd);
144 }
145
147 if (m_r_context.depthImage != VK_NULL_HANDLE) {
148 vmaDestroyImage(m_r_context.allocator, m_r_context.depthImage, m_r_context.depthAllocation);
149 m_r_context.depthImage = VK_NULL_HANDLE;
150 m_r_context.depthAllocation = VK_NULL_HANDLE;
151 }
152 if (m_r_context.depthImageView != VK_NULL_HANDLE) {
153 vkDestroyImageView(m_r_context.device, m_r_context.depthImageView, nullptr);
154 m_r_context.depthImageView = VK_NULL_HANDLE;
155 }
156
157 log("Creating depth resources...");
158
159 VkFormat depthFormat = findDepthFormat();
160
161 VkImageCreateInfo imageInfo{};
162 imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
163 imageInfo.imageType = VK_IMAGE_TYPE_2D;
164 imageInfo.extent = {std::max(m_r_context.swapchainExtent.width, m_r_context.currentRenderResolution.x), std::max(m_r_context.swapchainExtent.height, m_r_context.currentRenderResolution.y), 1};
165 imageInfo.mipLevels = 1;
166 imageInfo.arrayLayers = 1;
167 imageInfo.format = depthFormat;
168 imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
169 imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
170 imageInfo.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
171 imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
172 imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
173
174 VmaAllocationCreateInfo allocInfo{};
175 allocInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
176
177 if (vmaCreateImage(m_r_context.allocator, &imageInfo, &allocInfo,
178 &m_r_context.depthImage, &m_r_context.depthAllocation, nullptr) != VK_SUCCESS) {
179 throw_error("Failed to create depth image");
180 }
181
182 VkImageViewCreateInfo viewInfo{};
183 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
184 viewInfo.image = m_r_context.depthImage;
185 viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
186 viewInfo.format = depthFormat;
187 viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
188 viewInfo.subresourceRange.baseMipLevel = 0;
189 viewInfo.subresourceRange.levelCount = 1;
190 viewInfo.subresourceRange.baseArrayLayer = 0;
191 viewInfo.subresourceRange.layerCount = 1;
192
193 if (vkCreateImageView(m_r_context.device, &viewInfo, nullptr, &m_r_context.depthImageView) != VK_SUCCESS) {
194 throw_error("Failed to create depth image view");
195 }
196
197 m_r_context.depthFormat = depthFormat;
198 }
199
201 log("creating imageviews");
202 m_r_context.swapchainImageViews.resize(m_r_context.swapchainImages.size());
203
204 for (size_t i = 0; i < m_r_context.swapchainImages.size(); i++) {
205 VkImageViewCreateInfo createInfo = {};
206 createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
207 createInfo.image = m_r_context.swapchainImages[i];
208 createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
209 createInfo.format = m_r_context.swapchainImageFormat;
210 createInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
211 createInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
212 createInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
213 createInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
214 createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
215 createInfo.subresourceRange.baseMipLevel = 0;
216 createInfo.subresourceRange.levelCount = 1;
217 createInfo.subresourceRange.baseArrayLayer = 0;
218 createInfo.subresourceRange.layerCount = 1;
219
220 if (vkCreateImageView(m_r_context.device, &createInfo, nullptr, &m_r_context.swapchainImageViews[i]) != VK_SUCCESS) {
221 throw_error("Failed to create image views");
222 }
223 }
224
226 }
227
229 log("creating command pools");
230
231 if (!m_r_context.commandPools.empty()) return;
232
233 m_r_context.commandPools.resize(m_r_context.MAX_FRAMES_IN_FLIGHT);
234
235 for (int i = 0; i < m_r_context.MAX_FRAMES_IN_FLIGHT; i++) {
236 VkCommandPoolCreateInfo poolInfo = {};
237 poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
238 poolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
239 poolInfo.queueFamilyIndex = m_r_context.graphicsQueueFamily;
240
241 if (vkCreateCommandPool(m_r_context.device, &poolInfo, nullptr, &m_r_context.commandPools[i]) != VK_SUCCESS) {
242 throw_error("Failed to create command pool");
243 }
244 }
245
246 VkCommandPoolCreateInfo poolInfo = {};
247 poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
248 poolInfo.flags = VK_COMMAND_POOL_CREATE_TRANSIENT_BIT |
249 VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
250 poolInfo.queueFamilyIndex = m_r_context.graphicsQueueFamily;
251
252 if (vkCreateCommandPool(m_r_context.device, &poolInfo, nullptr, &m_r_context.singleTimePool) != VK_SUCCESS) {
253 throw_error("Failed to create single time command pool");
254 }
255
257 }
258
260 log("creating command buffers");
261
262 if (!m_r_context.commandBuffers.empty()) return;
263
264 m_r_context.commandBuffers.resize(m_r_context.MAX_FRAMES_IN_FLIGHT);
265
266 for (int i = 0; i < m_r_context.MAX_FRAMES_IN_FLIGHT; i++) {
267 VkCommandBufferAllocateInfo allocInfo = {};
268 allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
269 allocInfo.commandPool = m_r_context.commandPools[i];
270 allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
271 allocInfo.commandBufferCount = 1;
272
273 if (vkAllocateCommandBuffers(m_r_context.device, &allocInfo, &m_r_context.commandBuffers[i]) != VK_SUCCESS) {
274 throw_error("Failed to allocate command buffer");
275 }
276 }
277
279 }
280
282 if (!m_r_context.imageAvailableSemaphores.empty()) return;
283
284 log("Creating synchronization objects...");
285
286 m_r_context.imageAvailableSemaphores.resize(m_r_context.MAX_FRAMES_IN_FLIGHT);
287 m_r_context.renderFinishedSemaphores.resize(m_r_context.MAX_FRAMES_IN_FLIGHT);
288 m_r_context.inFlightFences.resize(m_r_context.MAX_FRAMES_IN_FLIGHT);
289
290 VkSemaphoreCreateInfo semaphoreInfo = {};
291 semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
292
293 VkFenceCreateInfo fenceInfo = {};
294 fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
295 fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
296
297 VkResult result;
298
299 for (size_t i = 0; i < m_r_context.MAX_FRAMES_IN_FLIGHT; i++) {
300 result = vkCreateSemaphore(m_r_context.device, &semaphoreInfo, nullptr, &m_r_context.imageAvailableSemaphores[i]);
301 if (result != VK_SUCCESS) {
302 throw_error("Failed to create image available semaphore");
303 }
304
305 result = vkCreateSemaphore(m_r_context.device, &semaphoreInfo, nullptr, &m_r_context.renderFinishedSemaphores[i]);
306 if (result != VK_SUCCESS) {
307 throw_error("Failed to create render finished semaphore");
308 }
309
310 result = vkCreateFence(m_r_context.device, &fenceInfo, nullptr, &m_r_context.inFlightFences[i]);
311 if (result != VK_SUCCESS) {
312 throw_error("Failed to create fence");
313 }
314
315 assert(m_r_context.inFlightFences[i] != VK_NULL_HANDLE);
316
317 log("Created sync objects: fence=%p", (void*)m_r_context.inFlightFences[i]);
318 }
319
320 if (m_r_context.depthImageView) {
322 } else {
323 log(LogLevel::WARNING,
324 "Deferring low-res resource creation - depth image not ready");
325 }
326 }
327
329 if (m_r_context.currentRenderResolution.x == 0 || m_r_context.currentRenderResolution.y == 0) {
330 log(LogLevel::ERROR, "Invalid render resolution for low-res resources");
331 return;
332 }
333
335
336 VkImageCreateInfo imageInfo{};
337 imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
338 imageInfo.imageType = VK_IMAGE_TYPE_2D;
339 imageInfo.extent = {m_r_context.currentRenderResolution.x, m_r_context.currentRenderResolution.y, 1};
340 imageInfo.mipLevels = 1;
341 imageInfo.arrayLayers = 1;
342 imageInfo.format = m_r_context.swapchainImageFormat;
343 imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
344 imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
345 imageInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
346 imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
347
348 VmaAllocationCreateInfo allocInfo{};
349 allocInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
350
351 if (vmaCreateImage(m_r_context.allocator, &imageInfo, &allocInfo,
352 &m_r_context.lowResColorImage, &m_r_context.lowResColorAlloc, nullptr) != VK_SUCCESS) {
353 log(LogLevel::ERROR, "Failed to create low-res color image");
354 return;
355 }
356
357 VkImageViewCreateInfo viewInfo{};
358 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
359 viewInfo.image = m_r_context.lowResColorImage;
360 viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
361 viewInfo.format = m_r_context.swapchainImageFormat;
362 viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
363 viewInfo.subresourceRange.levelCount = 1;
364 viewInfo.subresourceRange.layerCount = 1;
365
366 if (vkCreateImageView(m_r_context.device, &viewInfo, nullptr, &m_r_context.lowResColorView) != VK_SUCCESS) {
367 log(LogLevel::ERROR, "Failed to create low-res color image view");
368 vmaDestroyImage(m_r_context.allocator, m_r_context.lowResColorImage, m_r_context.lowResColorAlloc);
369 m_r_context.lowResColorImage = VK_NULL_HANDLE;
370 m_r_context.lowResColorAlloc = VK_NULL_HANDLE;
371 return;
372 }
373
374 if (vmaCreateImage(m_r_context.allocator, &imageInfo, &allocInfo,
375 &m_r_context.uiImage, &m_r_context.uiAlloc, nullptr) != VK_SUCCESS) {
376 log(LogLevel::ERROR, "Failed to create ui image");
377 return;
378 }
379
380 VkImageViewCreateInfo uiViewInfo = viewInfo;
381 uiViewInfo.image = m_r_context.uiImage;
382
383 if (vkCreateImageView(m_r_context.device, &uiViewInfo, nullptr, &m_r_context.uiView) != VK_SUCCESS) {
384 log(LogLevel::ERROR, "Failed to create ui image view");
385 vmaDestroyImage(m_r_context.allocator, m_r_context.uiImage, m_r_context.uiAlloc);
386 m_r_context.uiImage = VK_NULL_HANDLE;
387 m_r_context.uiAlloc = VK_NULL_HANDLE;
388 return;
389 }
390
391 VkImageCreateInfo accumInfo = imageInfo;
392 accumInfo.format = VK_FORMAT_R16G16B16A16_SFLOAT;
393 if(vmaCreateImage(m_r_context.allocator, &accumInfo, &allocInfo, &m_r_context.accumImage, &m_r_context.accumAlloc, nullptr) != VK_SUCCESS) {
394 log(LogLevel::ERROR, "Failed to create accum image");
395 vmaDestroyImage(m_r_context.allocator, m_r_context.accumImage, m_r_context.accumAlloc);
396 m_r_context.accumImage = VK_NULL_HANDLE;
397 m_r_context.accumAlloc = VK_NULL_HANDLE;
398 return;
399 }
400
401 VkImageViewCreateInfo accumViewInfo = viewInfo;
402 accumViewInfo.image = m_r_context.accumImage;
403 accumViewInfo.format = VK_FORMAT_R16G16B16A16_SFLOAT;
404 if(vkCreateImageView(m_r_context.device, &accumViewInfo, nullptr, &m_r_context.accumView) != VK_SUCCESS) {
405 log(LogLevel::ERROR, "Failed to create accum image view");
406 vmaDestroyImage(m_r_context.allocator, m_r_context.accumImage, m_r_context.accumAlloc);
407 m_r_context.accumImage = VK_NULL_HANDLE;
408 m_r_context.accumAlloc = VK_NULL_HANDLE;
409 return;
410 }
411
412 VkImageCreateInfo revealInfo = imageInfo;
413 revealInfo.format = VK_FORMAT_R8_UNORM;
414 if(vmaCreateImage(m_r_context.allocator, &revealInfo, &allocInfo, &m_r_context.revealImage, &m_r_context.revealAlloc, nullptr) != VK_SUCCESS) {
415 log(LogLevel::ERROR, "Failed to create reveal image");
416 vmaDestroyImage(m_r_context.allocator, m_r_context.revealImage, m_r_context.revealAlloc);
417 m_r_context.revealImage = VK_NULL_HANDLE;
418 m_r_context.revealAlloc = VK_NULL_HANDLE;
419 return;
420 }
421
422 VkImageViewCreateInfo revealViewInfo = viewInfo;
423 revealViewInfo.image = m_r_context.revealImage;
424 revealViewInfo.format = VK_FORMAT_R8_UNORM;
425 if(vkCreateImageView(m_r_context.device, &revealViewInfo, nullptr, &m_r_context.revealView) != VK_SUCCESS) {
426 log(LogLevel::ERROR, "Failed to create reveal image view");
427 vmaDestroyImage(m_r_context.allocator, m_r_context.revealImage, m_r_context.revealAlloc);
428 m_r_context.revealImage = VK_NULL_HANDLE;
429 m_r_context.revealAlloc = VK_NULL_HANDLE;
430 return;
431 }
432
433
434 VkImageCreateInfo compositeInfo = imageInfo;
435 compositeInfo.mipLevels = 3;
436 compositeInfo.usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
437 if(vmaCreateImage(m_r_context.allocator, &compositeInfo, &allocInfo, &m_r_context.compositeImage, &m_r_context.compositeAlloc, nullptr) != VK_SUCCESS) {
438 log(LogLevel::ERROR, "Failed to create composite image");
439 return;
440 }
441
442 VkImageViewCreateInfo compositeViewInfo = viewInfo;
443 compositeViewInfo.image = m_r_context.compositeImage;
444 compositeViewInfo.subresourceRange.levelCount = 3;
445 if(vkCreateImageView(m_r_context.device, &compositeViewInfo, nullptr, &m_r_context.compositeView) != VK_SUCCESS) {
446 log(LogLevel::ERROR, "Failed to create composite image view");
447 return;
448 }
449
450 VkImageCreateInfo gameViewInfo = imageInfo;
451 gameViewInfo.format = m_r_context.swapchainImageFormat;
452 gameViewInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
453 vmaCreateImage(m_r_context.allocator, &gameViewInfo, &allocInfo, &m_r_context.gameViewImage, &m_r_context.gameViewAlloc, nullptr);
454
455 VkImageViewCreateInfo gameViewViewInfo = viewInfo;
456 gameViewViewInfo.image = m_r_context.gameViewImage;
457 gameViewViewInfo.format = m_r_context.swapchainImageFormat;
458 vkCreateImageView(m_r_context.device, &gameViewViewInfo, nullptr, &m_r_context.gameViewView);
459
460 m_r_context.lowResColorFormat = m_r_context.swapchainImageFormat;
461 }
462
464
465 if (m_r_context.compositeView != VK_NULL_HANDLE) {
466 vkDestroyImageView(m_r_context.device, m_r_context.compositeView, nullptr);
467 m_r_context.compositeView = VK_NULL_HANDLE;
468 }
469 if (m_r_context.compositeImage != VK_NULL_HANDLE && m_r_context.compositeAlloc != VK_NULL_HANDLE) {
470 vmaDestroyImage(m_r_context.allocator, m_r_context.compositeImage, m_r_context.compositeAlloc);
471 m_r_context.compositeImage = VK_NULL_HANDLE;
472 m_r_context.compositeAlloc = VK_NULL_HANDLE;
473 }
474if (m_r_context.lowResColorView != VK_NULL_HANDLE) {
475 vkDestroyImageView(m_r_context.device, m_r_context.lowResColorView, nullptr);
476 m_r_context.lowResColorView = VK_NULL_HANDLE;
477 }
478
479 if (m_r_context.lowResColorImage != VK_NULL_HANDLE && m_r_context.lowResColorAlloc != VK_NULL_HANDLE) {
480 vmaDestroyImage(m_r_context.allocator, m_r_context.lowResColorImage, m_r_context.lowResColorAlloc);
481 m_r_context.lowResColorImage = VK_NULL_HANDLE;
482 m_r_context.lowResColorAlloc = VK_NULL_HANDLE;
483 }
484
485 if (m_r_context.uiView != VK_NULL_HANDLE) {
486 vkDestroyImageView(m_r_context.device, m_r_context.uiView, nullptr);
487 m_r_context.uiView = VK_NULL_HANDLE;
488 }
489
490 if (m_r_context.uiImage != VK_NULL_HANDLE && m_r_context.uiAlloc != VK_NULL_HANDLE) {
491 vmaDestroyImage(m_r_context.allocator, m_r_context.uiImage, m_r_context.uiAlloc);
492 m_r_context.uiImage = VK_NULL_HANDLE;
493 m_r_context.uiAlloc = VK_NULL_HANDLE;
494 }
495
496 if(m_r_context.accumView != VK_NULL_HANDLE) {
497 vkDestroyImageView(m_r_context.device, m_r_context.accumView, nullptr);
498 m_r_context.accumView = VK_NULL_HANDLE;
499 }
500 if(m_r_context.accumImage != VK_NULL_HANDLE && m_r_context.accumAlloc != VK_NULL_HANDLE) {
501 vmaDestroyImage(m_r_context.allocator, m_r_context.accumImage, m_r_context.accumAlloc);
502 m_r_context.accumImage = VK_NULL_HANDLE;
503 m_r_context.accumAlloc = VK_NULL_HANDLE;
504 }
505
506 if(m_r_context.revealView != VK_NULL_HANDLE) {
507 vkDestroyImageView(m_r_context.device, m_r_context.revealView, nullptr);
508 m_r_context.revealView = VK_NULL_HANDLE;
509 }
510 if(m_r_context.revealImage != VK_NULL_HANDLE && m_r_context.revealAlloc != VK_NULL_HANDLE) {
511 vmaDestroyImage(m_r_context.allocator, m_r_context.revealImage, m_r_context.revealAlloc);
512 m_r_context.revealImage = VK_NULL_HANDLE;
513 m_r_context.revealAlloc = VK_NULL_HANDLE;
514 }
515
516 if(m_r_context.gameViewView != VK_NULL_HANDLE) {
517 vkDestroyImageView(m_r_context.device, m_r_context.gameViewView, nullptr);
518 m_r_context.gameViewView = VK_NULL_HANDLE;
519 }
520 if(m_r_context.gameViewImage != VK_NULL_HANDLE && m_r_context.gameViewAlloc != VK_NULL_HANDLE) {
521 vmaDestroyImage(m_r_context.allocator, m_r_context.gameViewImage, m_r_context.gameViewAlloc);
522 m_r_context.gameViewImage = VK_NULL_HANDLE;
523 m_r_context.gameViewAlloc = VK_NULL_HANDLE;
524 }
525 }
526
529
530 if (m_r_context.depthImageView) {
531 vkDestroyImageView(m_r_context.device, m_r_context.depthImageView, nullptr);
532 m_r_context.depthImageView = VK_NULL_HANDLE;
533 }
534 if (m_r_context.depthImage) {
535 vmaDestroyImage(m_r_context.allocator, m_r_context.depthImage, m_r_context.depthAllocation);
536 m_r_context.depthImage = VK_NULL_HANDLE;
537 m_r_context.depthAllocation = VK_NULL_HANDLE;
538 }
539
540 for (auto& imageView : m_r_context.swapchainImageViews) {
541 vkDestroyImageView(m_r_context.device, imageView, nullptr);
542 }
543 m_r_context.swapchainImageViews.clear();
544
545 if (m_r_context.swapchain) {
546 vkDestroySwapchainKHR(m_r_context.device, m_r_context.swapchain, nullptr);
547 m_r_context.swapchain = VK_NULL_HANDLE;
548 }
549 }
550
552 for (auto pool : m_r_context.commandPools) {
553 if (pool != VK_NULL_HANDLE) vkDestroyCommandPool(m_r_context.device, pool, nullptr);
554 }
555 m_r_context.commandPools.clear();
556
557 if (m_r_context.singleTimePool != VK_NULL_HANDLE) {
558 vkDestroyCommandPool(m_r_context.device, m_r_context.singleTimePool, nullptr);
559 m_r_context.singleTimePool = VK_NULL_HANDLE;
560 }
561
562 m_r_context.commandBuffers.clear();
563
564 for (size_t i = 0; i < m_r_context.imageAvailableSemaphores.size(); i++) {
565 if (m_r_context.imageAvailableSemaphores[i]) vkDestroySemaphore(m_r_context.device, m_r_context.imageAvailableSemaphores[i], nullptr);
566 if (m_r_context.renderFinishedSemaphores[i]) vkDestroySemaphore(m_r_context.device, m_r_context.renderFinishedSemaphores[i], nullptr);
567 if (m_r_context.inFlightFences[i]) vkDestroyFence(m_r_context.device, m_r_context.inFlightFences[i], nullptr);
568 }
569
570 m_r_context.imageAvailableSemaphores.clear();
571 m_r_context.renderFinishedSemaphores.clear();
572 m_r_context.inFlightFences.clear();
573 }
574
576 int width = 0, height = 0;
577 SDL_GetWindowSizeInPixels(m_p_window, &width, &height);
578
579 if (width == 0 || height == 0) {
580 return;
581 }
582
583 if (m_r_context.surface == VK_NULL_HANDLE) {
584 return;
585 }
586
587 VkSurfaceCapabilitiesKHR capabilities;
588 if (vkGetPhysicalDeviceSurfaceCapabilitiesKHR(m_r_context.physicalDevice, m_r_context.surface, &capabilities) != VK_SUCCESS) {
589 return;
590 }
591
592 if (capabilities.currentExtent.width == 0 || capabilities.currentExtent.height == 0) {
593 return;
594 }
595
596 log("recreating swapchains");
597 vkDeviceWaitIdle(m_r_context.device);
598 log("cleanupSwapchain");
601
605 m_r_context.requestSwapchainRecreation = false;
606 }
607
608 VkSurfaceFormatKHR VulkanSwapchainManager::chooseSwapSurfaceFormat(const std::vector<VkSurfaceFormatKHR>& availableFormats) {
609 log("choosing swapsurface format");
610 for (const auto& availableFormat : availableFormats) {
611 if (availableFormat.format == VK_FORMAT_B8G8R8A8_SRGB &&
612 availableFormat.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
613 return availableFormat;
614 }
615 }
616 return availableFormats[0];
617 }
618
620 m_vsyncEnabled = enabled;
621 }
622
623 VkPresentModeKHR VulkanSwapchainManager::chooseSwapPresentMode(const std::vector<VkPresentModeKHR>& availablePresentModes) {
624 log("choosing swap present mode");
625
626 if (!m_vsyncEnabled) {
627 for (const auto& availablePresentMode : availablePresentModes) {
628 if (availablePresentMode == VK_PRESENT_MODE_MAILBOX_KHR) {
629 return availablePresentMode;
630 }
631 if (availablePresentMode == VK_PRESENT_MODE_IMMEDIATE_KHR) {
632 return availablePresentMode;
633 }
634 }
635 }
636 return VK_PRESENT_MODE_FIFO_KHR;
637 }
638
639 VkExtent2D VulkanSwapchainManager::chooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities) {
640 log("choosing swap extent");
641 if (capabilities.currentExtent.width != std::numeric_limits<uint32_t>::max()) {
642 return capabilities.currentExtent;
643 } else {
644 int width, height;
645 SDL_GetWindowSizeInPixels(m_p_window, &width, &height);
646
647 VkExtent2D actualExtent = {
648 static_cast<uint32_t>(width),
649 static_cast<uint32_t>(height)
650 };
651
652 actualExtent.width = std::clamp(
653 actualExtent.width,
654 capabilities.minImageExtent.width,
655 capabilities.maxImageExtent.width);
656 actualExtent.height = std::clamp(
657 actualExtent.height,
658 capabilities.minImageExtent.height,
659 capabilities.maxImageExtent.height);
660
661 return actualExtent;
662 }
663 }
664
666 std::vector<VkFormat> candidates = {
667 VK_FORMAT_D32_SFLOAT,
668 VK_FORMAT_D32_SFLOAT_S8_UINT,
669 VK_FORMAT_D24_UNORM_S8_UINT
670 };
671
672 for (VkFormat format : candidates) {
673 VkFormatProperties props;
674 vkGetPhysicalDeviceFormatProperties(m_r_context.physicalDevice, format, &props);
675 if (props.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) {
676 return format;
677 }
678 }
679 throw_error("Failed to find supported depth format");
680 return VK_FORMAT_UNDEFINED;
681 }
682}
This file defines VulkanSwapchainManager Class.
void cleanupSwapchain()
Cleans up swapchain resources.
void createDepthResources()
Helper function to create depth resources for swapchain creation.
~VulkanSwapchainManager()
Simple destructor.
void setVSync(bool enabled)
Sets the vsync enabled state.
void cleanupSyncObjects()
Cleans up synchronization objects.
VulkanSwapchainManager(VulkanContext &context, SDL_Window *window)
Constructor for VulkanSwapchainManager.
VkSurfaceFormatKHR chooseSwapSurfaceFormat(const std::vector< VkSurfaceFormatKHR > &availableFormats)
Helper function choosing SwapSurfaceFormat based on hardware capabilities.
VkPresentModeKHR chooseSwapPresentMode(const std::vector< VkPresentModeKHR > &availablePresentModes)
Helper function choosing SwapPresentMode based on hardware capabilities.
void cleanupLowResResources()
Helper function to cleanup low resolution resources, since low res resources can be changed without c...
VkExtent2D chooseSwapExtent(const VkSurfaceCapabilitiesKHR &capabilities)
Helper function choosing SwapExtent based on hardware capabilities.
void createImageViews()
Helper function to create image views for swapchain images.
void recreateSwapchain()
Recreates the swapchain.
void createSyncObjects()
Helper function to create synchronization objects for swapchain creation.
void createCommandPool()
Helper function to create command pool for swapchain creation.
void createLowResResources()
Helper function to create low resolution resources for low res rendering.
VkFormat findDepthFormat()
Helper function to find depth format based on hardware capabilities.
void createCommandBuffers()
Helper function to create command buffers for swapchain creation.
void createSwapchain()
Creates or recreates the swapchain.
This files defines global variables defining vulkan limits.
void VEX_EXPORT throw_error(const std::string &msg)
Throws an error or terminates the application.
void VEX_EXPORT log(const char *fmt,...)
Logs a formatted message.
Struct holding all vulkan data, like device, surface, swapchain, images, views, and more.
Definition context.hpp:26