Files
SDL3CPlusPlus/src/app/sdl3_app_swapchain.cpp
Richard Ward 0832cd0fc7 various fixes
2025-12-18 21:21:12 +00:00

193 lines
7.7 KiB
C++

#include "app/sdl3_app.hpp"
#include <algorithm>
#include <stdexcept>
namespace sdl3cpp::app {
void Sdl3App::CreateSwapChain() {
SwapChainSupportDetails support = QuerySwapChainSupport(physicalDevice_);
VkSurfaceFormatKHR surfaceFormat = ChooseSwapSurfaceFormat(support.formats);
VkPresentModeKHR presentMode = ChooseSwapPresentMode(support.presentModes);
VkExtent2D extent = ChooseSwapExtent(support.capabilities);
uint32_t imageCount = support.capabilities.minImageCount + 1;
if (support.capabilities.maxImageCount > 0 && imageCount > support.capabilities.maxImageCount) {
imageCount = support.capabilities.maxImageCount;
}
VkSwapchainCreateInfoKHR createInfo{};
createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
createInfo.surface = surface_;
createInfo.minImageCount = imageCount;
createInfo.imageFormat = surfaceFormat.format;
createInfo.imageColorSpace = surfaceFormat.colorSpace;
createInfo.imageExtent = extent;
createInfo.imageArrayLayers = 1;
createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
QueueFamilyIndices indices = FindQueueFamilies(physicalDevice_);
uint32_t queueFamilyIndices[] = {*indices.graphicsFamily, *indices.presentFamily};
if (indices.graphicsFamily != indices.presentFamily) {
createInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
createInfo.queueFamilyIndexCount = 2;
createInfo.pQueueFamilyIndices = queueFamilyIndices;
} else {
createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
}
createInfo.preTransform = support.capabilities.currentTransform;
createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
createInfo.presentMode = presentMode;
createInfo.clipped = VK_TRUE;
if (vkCreateSwapchainKHR(device_, &createInfo, nullptr, &swapChain_) != VK_SUCCESS) {
throw std::runtime_error("Failed to create swap chain");
}
vkGetSwapchainImagesKHR(device_, swapChain_, &imageCount, nullptr);
swapChainImages_.resize(imageCount);
vkGetSwapchainImagesKHR(device_, swapChain_, &imageCount, swapChainImages_.data());
swapChainImageFormat_ = surfaceFormat.format;
swapChainExtent_ = extent;
}
void Sdl3App::CreateImageViews() {
swapChainImageViews_.resize(swapChainImages_.size());
for (size_t i = 0; i < swapChainImages_.size(); ++i) {
VkImageViewCreateInfo viewInfo{};
viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
viewInfo.image = swapChainImages_[i];
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
viewInfo.format = swapChainImageFormat_;
viewInfo.components = {VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY,
VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY};
viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
viewInfo.subresourceRange.baseMipLevel = 0;
viewInfo.subresourceRange.levelCount = 1;
viewInfo.subresourceRange.baseArrayLayer = 0;
viewInfo.subresourceRange.layerCount = 1;
if (vkCreateImageView(device_, &viewInfo, nullptr, &swapChainImageViews_[i]) != VK_SUCCESS) {
throw std::runtime_error("Failed to create image views");
}
}
}
void Sdl3App::CreateRenderPass() {
VkAttachmentDescription colorAttachment{};
colorAttachment.format = swapChainImageFormat_;
colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT;
colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
colorAttachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
VkAttachmentReference colorAttachmentRef{};
colorAttachmentRef.attachment = 0;
colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
VkSubpassDescription subpass{};
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subpass.colorAttachmentCount = 1;
subpass.pColorAttachments = &colorAttachmentRef;
VkSubpassDependency dependency{};
dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
dependency.dstSubpass = 0;
dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependency.srcAccessMask = 0;
dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
VkRenderPassCreateInfo renderPassInfo{};
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
renderPassInfo.attachmentCount = 1;
renderPassInfo.pAttachments = &colorAttachment;
renderPassInfo.subpassCount = 1;
renderPassInfo.pSubpasses = &subpass;
renderPassInfo.dependencyCount = 1;
renderPassInfo.pDependencies = &dependency;
if (vkCreateRenderPass(device_, &renderPassInfo, nullptr, &renderPass_) != VK_SUCCESS) {
throw std::runtime_error("Failed to create render pass");
}
}
void Sdl3App::CleanupSwapChain() {
for (auto framebuffer : swapChainFramebuffers_) {
vkDestroyFramebuffer(device_, framebuffer, nullptr);
}
vkFreeCommandBuffers(device_, commandPool_,
static_cast<uint32_t>(commandBuffers_.size()), commandBuffers_.data());
for (auto& entry : graphicsPipelines_) {
vkDestroyPipeline(device_, entry.second, nullptr);
}
graphicsPipelines_.clear();
if (pipelineLayout_ != VK_NULL_HANDLE) {
vkDestroyPipelineLayout(device_, pipelineLayout_, nullptr);
pipelineLayout_ = VK_NULL_HANDLE;
}
vkDestroyRenderPass(device_, renderPass_, nullptr);
for (auto imageView : swapChainImageViews_) {
vkDestroyImageView(device_, imageView, nullptr);
}
vkDestroySwapchainKHR(device_, swapChain_, nullptr);
}
void Sdl3App::RecreateSwapChain() {
int width = 0;
int height = 0;
while (width == 0 || height == 0) {
SDL_GetWindowSize(window_, &width, &height);
SDL_Event event;
SDL_WaitEvent(&event);
}
vkDeviceWaitIdle(device_);
CleanupSwapChain();
CreateSwapChain();
CreateImageViews();
CreateRenderPass();
CreateGraphicsPipeline();
CreateFramebuffers();
CreateCommandBuffers();
framebufferResized_ = false;
}
VkSurfaceFormatKHR Sdl3App::ChooseSwapSurfaceFormat(const std::vector<VkSurfaceFormatKHR>& availableFormats) {
for (const auto& availableFormat : availableFormats) {
if (availableFormat.format == VK_FORMAT_B8G8R8A8_SRGB &&
availableFormat.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
return availableFormat;
}
}
return availableFormats[0];
}
VkPresentModeKHR Sdl3App::ChooseSwapPresentMode(const std::vector<VkPresentModeKHR>& availablePresentModes) {
for (const auto& availablePresentMode : availablePresentModes) {
if (availablePresentMode == VK_PRESENT_MODE_MAILBOX_KHR) {
return availablePresentMode;
}
}
return VK_PRESENT_MODE_FIFO_KHR;
}
VkExtent2D Sdl3App::ChooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities) {
int width, height;
SDL_GetWindowSize(window_, &width, &height);
VkExtent2D actualExtent = {
static_cast<uint32_t>(std::clamp(width, static_cast<int>(capabilities.minImageExtent.width),
static_cast<int>(capabilities.maxImageExtent.width))),
static_cast<uint32_t>(std::clamp(height, static_cast<int>(capabilities.minImageExtent.height),
static_cast<int>(capabilities.maxImageExtent.height)))
};
return actualExtent;
}
} // namespace sdl3cpp::app