10#include "SDL3/SDL_video.h"
16bool VulkanRenderer::CreateSwapChain() {
17 auto details = QuerySwapchain();
18 if (!details.has_value())
21 if (details->formats.empty() && details->presentModes.empty())
24 auto format = ChooseFormat(details->formats);
25 auto mode = ChoosePresentMode(details->presentModes);
26 auto extent = ChooseExtend(details.value());
28 uint32_t imageCount = details->caps.minImageCount + 1;
29 if (details->caps.maxImageCount > 0 &&
30 imageCount > details->caps.maxImageCount)
31 imageCount = details->caps.maxImageCount;
33 VkSwapchainCreateInfoKHR info{};
34 info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
35 info.minImageCount = imageCount;
36 info.imageColorSpace = format.colorSpace;
37 info.imageFormat = format.format;
38 info.imageExtent = extent;
39 info.imageArrayLayers = 1;
40 info.presentMode = mode;
41 info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
43 uint32_t indices[] = {QueueIDs.GraphicsIndex, QueueIDs.PresentIndex};
45 if (QueueIDs.GraphicsIndex != QueueIDs.PresentIndex) {
46 info.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
47 info.queueFamilyIndexCount = 2;
48 info.pQueueFamilyIndices = indices;
50 info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
53 info.surface = surface;
54 info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
55 info.preTransform = details->caps.currentTransform;
56 info.clipped = VK_TRUE;
57 info.oldSwapchain = VK_NULL_HANDLE;
60 vkCreateSwapchainKHR(device, &info,
nullptr, &swapChain);
61 if (result != VK_SUCCESS)
64 uint32_t scImageCount = 0;
65 vkGetSwapchainImagesKHR(device, swapChain, &scImageCount,
nullptr);
66 swapChainImages.resize(scImageCount);
67 vkGetSwapchainImagesKHR(device, swapChain, &scImageCount,
68 swapChainImages.data());
70 scImageFormat = format.format;
78 CleanupDepthResources();
79 CleanupMSAAColorResources();
81 for (
auto framebuffer : swapChainFramebuffers) {
82 vkDestroyFramebuffer(device, framebuffer,
nullptr);
84 swapChainFramebuffers.clear();
86 for (
auto imageView : swapChainImageViews) {
87 vkDestroyImageView(device, imageView,
nullptr);
89 swapChainImageViews.clear();
92 vkDestroySwapchainKHR(device, swapChain,
nullptr);
93 swapChain = VK_NULL_HANDLE;
98bool VulkanRenderer::CreateMSAAColorResources() {
99 if (m_msaaSamples == VK_SAMPLE_COUNT_1_BIT)
102 VkImageCreateInfo imageInfo{};
103 imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
104 imageInfo.imageType = VK_IMAGE_TYPE_2D;
105 imageInfo.extent.width = scExtent.width;
106 imageInfo.extent.height = scExtent.height;
107 imageInfo.extent.depth = 1;
108 imageInfo.mipLevels = 1;
109 imageInfo.arrayLayers = 1;
110 imageInfo.format = scImageFormat;
111 imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
112 imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
113 imageInfo.usage = VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
114 imageInfo.samples = m_msaaSamples;
115 imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
117 if (vkCreateImage(device, &imageInfo,
nullptr, &m_msaaColorImage) != VK_SUCCESS)
120 VkMemoryRequirements memRequirements;
121 vkGetImageMemoryRequirements(device, m_msaaColorImage, &memRequirements);
123 VkMemoryAllocateInfo allocInfo{};
124 allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
125 allocInfo.allocationSize = memRequirements.size;
126 allocInfo.memoryTypeIndex = FindMemoryType(
127 memRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
129 if (vkAllocateMemory(device, &allocInfo,
nullptr, &m_msaaColorImageMemory) != VK_SUCCESS)
132 vkBindImageMemory(device, m_msaaColorImage, m_msaaColorImageMemory, 0);
134 VkImageViewCreateInfo viewInfo{};
135 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
136 viewInfo.image = m_msaaColorImage;
137 viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
138 viewInfo.format = scImageFormat;
139 viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
140 viewInfo.subresourceRange.baseMipLevel = 0;
141 viewInfo.subresourceRange.levelCount = 1;
142 viewInfo.subresourceRange.baseArrayLayer = 0;
143 viewInfo.subresourceRange.layerCount = 1;
145 if (vkCreateImageView(device, &viewInfo,
nullptr, &m_msaaColorImageView) != VK_SUCCESS)
152void VulkanRenderer::CleanupMSAAColorResources() {
153 if (m_msaaColorImageView) {
154 vkDestroyImageView(device, m_msaaColorImageView,
nullptr);
155 m_msaaColorImageView = VK_NULL_HANDLE;
157 if (m_msaaColorImage) {
158 vkDestroyImage(device, m_msaaColorImage,
nullptr);
159 m_msaaColorImage = VK_NULL_HANDLE;
161 if (m_msaaColorImageMemory) {
162 vkFreeMemory(device, m_msaaColorImageMemory,
nullptr);
163 m_msaaColorImageMemory = VK_NULL_HANDLE;
168VkSampleCountFlagBits VulkanRenderer::GetMaxUsableSampleCount() {
169 VkPhysicalDeviceProperties props;
170 vkGetPhysicalDeviceProperties(physicalDevice, &props);
171 VkSampleCountFlags counts = props.limits.framebufferColorSampleCounts
172 & props.limits.framebufferDepthSampleCounts;
173 if (counts & VK_SAMPLE_COUNT_8_BIT)
return VK_SAMPLE_COUNT_8_BIT;
174 if (counts & VK_SAMPLE_COUNT_4_BIT)
return VK_SAMPLE_COUNT_4_BIT;
175 if (counts & VK_SAMPLE_COUNT_2_BIT)
return VK_SAMPLE_COUNT_2_BIT;
176 return VK_SAMPLE_COUNT_1_BIT;
180bool VulkanRenderer::CreateImageViews() {
181 swapChainImageViews.resize(swapChainImages.size());
183 for (
size_t i = 0; i < swapChainImageViews.size(); i++) {
184 VkImageViewCreateInfo info{};
185 info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
186 info.image = swapChainImages[i];
187 info.viewType = VK_IMAGE_VIEW_TYPE_2D;
188 info.format = scImageFormat;
190 info.components = {VK_COMPONENT_SWIZZLE_IDENTITY,
191 VK_COMPONENT_SWIZZLE_IDENTITY,
192 VK_COMPONENT_SWIZZLE_IDENTITY,
193 VK_COMPONENT_SWIZZLE_IDENTITY};
195 info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
196 info.subresourceRange.baseMipLevel = 0;
197 info.subresourceRange.levelCount = 1;
198 info.subresourceRange.baseArrayLayer = 0;
199 info.subresourceRange.layerCount = 1;
201 auto result = vkCreateImageView(device, &info,
nullptr,
202 &swapChainImageViews[i]);
203 if (result != VK_SUCCESS)
205 "Failed to create image view of swapchain, index: {}", i);
212bool VulkanRenderer::CreateDepthResources() {
213 depthFormat = FindDepthFormat();
216 VkImageCreateInfo imageInfo{};
217 imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
218 imageInfo.imageType = VK_IMAGE_TYPE_2D;
219 imageInfo.extent.width = scExtent.width;
220 imageInfo.extent.height = scExtent.height;
221 imageInfo.extent.depth = 1;
222 imageInfo.mipLevels = 1;
223 imageInfo.arrayLayers = 1;
224 imageInfo.format = depthFormat;
225 imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
226 imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
230 ? VK_SAMPLE_COUNT_1_BIT : m_msaaSamples;
231 imageInfo.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT
232 | VK_IMAGE_USAGE_SAMPLED_BIT;
233 imageInfo.samples = depthSamples;
234 imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
236 if (vkCreateImage(device, &imageInfo,
nullptr, &depthImage) !=
241 VkMemoryRequirements memRequirements;
242 vkGetImageMemoryRequirements(device, depthImage, &memRequirements);
244 VkMemoryAllocateInfo allocInfo{};
245 allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
246 allocInfo.allocationSize = memRequirements.size;
247 allocInfo.memoryTypeIndex = FindMemoryType(
248 memRequirements.memoryTypeBits,
249 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
251 if (vkAllocateMemory(device, &allocInfo,
nullptr, &depthImageMemory) !=
255 vkBindImageMemory(device, depthImage, depthImageMemory, 0);
258 VkImageViewCreateInfo viewInfo{};
259 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
260 viewInfo.image = depthImage;
261 viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
262 viewInfo.format = depthFormat;
263 viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
264 viewInfo.subresourceRange.baseMipLevel = 0;
265 viewInfo.subresourceRange.levelCount = 1;
266 viewInfo.subresourceRange.baseArrayLayer = 0;
267 viewInfo.subresourceRange.layerCount = 1;
269 if (vkCreateImageView(device, &viewInfo,
nullptr, &depthImageView) !=
277void VulkanRenderer::CleanupDepthResources() {
278 if (depthImageView) {
279 vkDestroyImageView(device, depthImageView,
nullptr);
280 depthImageView = VK_NULL_HANDLE;
283 vkDestroyImage(device, depthImage,
nullptr);
284 depthImage = VK_NULL_HANDLE;
286 if (depthImageMemory) {
287 vkFreeMemory(device, depthImageMemory,
nullptr);
288 depthImageMemory = VK_NULL_HANDLE;
293VkFormat VulkanRenderer::FindDepthFormat() {
294 std::vector<VkFormat> candidates = {VK_FORMAT_D32_SFLOAT,
295 VK_FORMAT_D32_SFLOAT_S8_UINT,
296 VK_FORMAT_D24_UNORM_S8_UINT};
298 for (VkFormat format : candidates) {
299 VkFormatProperties props;
300 vkGetPhysicalDeviceFormatProperties(physicalDevice, format, &props);
302 if (props.optimalTilingFeatures &
303 VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) {
308 return VK_FORMAT_D32_SFLOAT;
312uint32_t VulkanRenderer::FindMemoryType(
313 uint32_t typeFilter, VkMemoryPropertyFlags properties) {
314 VkPhysicalDeviceMemoryProperties memProperties;
315 vkGetPhysicalDeviceMemoryProperties(physicalDevice, &memProperties);
317 for (uint32_t i = 0; i < memProperties.memoryTypeCount; i++) {
318 if ((typeFilter & (1 << i)) &&
319 (memProperties.memoryTypes[i].propertyFlags & properties) ==
325 SLEAK_ERROR(
"Failed to find suitable memory type!");
330std::optional<SwapchainDetails> VulkanRenderer::QuerySwapchain() {
331 SwapchainDetails details;
333 VkResult result = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(
334 physicalDevice, surface, &details.caps);
335 if (result != VK_SUCCESS) {
336 SLEAK_ERROR(
"Failed to retrieve surface information!");
341 uint32_t formatCount = 0;
342 result = vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface,
343 &formatCount,
nullptr);
344 if (result != VK_SUCCESS || formatCount < 1) {
345 SLEAK_ERROR(
"Failed to retrieve supported surface formats");
349 details.formats.resize(formatCount);
350 vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface,
352 details.formats.data());
355 uint32_t modeCount = 0;
356 result = vkGetPhysicalDeviceSurfacePresentModesKHR(
357 physicalDevice, surface, &modeCount,
nullptr);
358 if (result != VK_SUCCESS || modeCount < 1) {
363 details.presentModes.resize(modeCount);
364 vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface,
366 details.presentModes.data());
372VkSurfaceFormatKHR VulkanRenderer::ChooseFormat(
373 const std::vector<VkSurfaceFormatKHR>& formats) {
379 for (
auto& format : formats)
380 if (format.format == VK_FORMAT_B8G8R8A8_UNORM &&
381 format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR)
385 for (
auto& format : formats)
386 if (format.format == VK_FORMAT_R8G8B8A8_UNORM &&
387 format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR)
394VkPresentModeKHR VulkanRenderer::ChoosePresentMode(
395 const std::vector<VkPresentModeKHR>& modes) {
398 return VK_PRESENT_MODE_FIFO_KHR;
402 for (
auto& mode : modes)
403 if (mode == VK_PRESENT_MODE_MAILBOX_KHR)
405 for (
auto& mode : modes)
406 if (mode == VK_PRESENT_MODE_IMMEDIATE_KHR)
409 return VK_PRESENT_MODE_FIFO_KHR;
414VkExtent2D VulkanRenderer::ChooseExtend(SwapchainDetails details) {
415 if (details.caps.currentExtent.width !=
416 std::numeric_limits<uint32_t>::max())
417 return details.caps.currentExtent;
420 SDL_GetWindowSizeInPixels(sdlWindow->GetSDLWindow(), &
width, &
height);
422 VkExtent2D actualExtent = {
static_cast<uint32_t
>(
width),
423 static_cast<uint32_t
>(
height)};
426 std::clamp(actualExtent.width,
427 details.caps.minImageExtent.width,
428 details.caps.maxImageExtent.width);
430 actualExtent.height =
431 std::clamp(actualExtent.height,
432 details.caps.minImageExtent.height,
433 details.caps.maxImageExtent.height);
#define SLEAK_RETURN_ERR(...)
VulkanRenderer(Window *window)
Backend-facing rendering layer shared by the four graphics backends.
Root namespace for everything the engine exposes.