From 1824b73d666095feb43766ea3a8e65c32210d3d5 Mon Sep 17 00:00:00 2001 From: Grayson Riffe Date: Tue, 11 Feb 2025 03:24:53 -0600 Subject: [PATCH] Create Vulkan swapchain --- NothinFancy/src/Engine.cpp | 2 +- NothinFancy/src/client/Client.cpp | 2 +- NothinFancy/src/client/Client.h | 2 +- NothinFancy/src/client/Window.cpp | 2 +- NothinFancy/src/client/Window.h | 2 +- .../src/client/render/RenderEngine.cpp | 82 ++++++++++++++++++- NothinFancy/src/client/render/RenderEngine.h | 6 +- NothinFancy/src/pch.h | 1 + NothinFancy/src/util/util.cpp | 2 - 9 files changed, 90 insertions(+), 11 deletions(-) diff --git a/NothinFancy/src/Engine.cpp b/NothinFancy/src/Engine.cpp index d3540f7..d17bd54 100644 --- a/NothinFancy/src/Engine.cpp +++ b/NothinFancy/src/Engine.cpp @@ -25,7 +25,7 @@ namespace nf { // Start client { - cli::Client client(config); + client::Client client(config); client.run(); } diff --git a/NothinFancy/src/client/Client.cpp b/NothinFancy/src/client/Client.cpp index 09b2843..236b665 100644 --- a/NothinFancy/src/client/Client.cpp +++ b/NothinFancy/src/client/Client.cpp @@ -4,7 +4,7 @@ #include "Client.h" #include "util.h" -namespace nf::cli { +namespace nf::client { Client::Client(ClientConfig config) : m_running(true) , m_config(config) diff --git a/NothinFancy/src/client/Client.h b/NothinFancy/src/client/Client.h index 576027a..1668c04 100644 --- a/NothinFancy/src/client/Client.h +++ b/NothinFancy/src/client/Client.h @@ -5,7 +5,7 @@ #include "Window.h" #include "render/RenderEngine.h" -namespace nf::cli { +namespace nf::client { class Client { public: Client(ClientConfig config); diff --git a/NothinFancy/src/client/Window.cpp b/NothinFancy/src/client/Window.cpp index fad0ab9..9571056 100644 --- a/NothinFancy/src/client/Window.cpp +++ b/NothinFancy/src/client/Window.cpp @@ -4,7 +4,7 @@ #include "Window.h" #include "util.h" -namespace nf::cli { +namespace nf::client { Window::Window(const char* windowTitle) : m_handle(nullptr) , m_wndClassName("NothinFancyWindow") diff --git a/NothinFancy/src/client/Window.h b/NothinFancy/src/client/Window.h index fb70f63..ecbb59b 100644 --- a/NothinFancy/src/client/Window.h +++ b/NothinFancy/src/client/Window.h @@ -5,7 +5,7 @@ #include -namespace nf::cli { +namespace nf::client { class Window { public: Window(const char* windowTitle); diff --git a/NothinFancy/src/client/render/RenderEngine.cpp b/NothinFancy/src/client/render/RenderEngine.cpp index ac96b32..1e24dfa 100644 --- a/NothinFancy/src/client/render/RenderEngine.cpp +++ b/NothinFancy/src/client/render/RenderEngine.cpp @@ -4,7 +4,7 @@ #include "RenderEngine.h" #include "util.h" -namespace nf::cli::render { +namespace nf::client::render { RenderEngine::RenderEngine(std::shared_ptr window, DisplayConfig display) : m_window(window) , m_display(display) @@ -17,16 +17,21 @@ namespace nf::cli::render { , m_queueGraphics() , m_queuePresent() , m_renderPassOutput() + , m_swapchain() + , m_swapchainImageFormat() + , m_swapchainImages() { NFLog("Initializing render engine"); m_window->setDisplay(m_display); - m_window->show(); createInstance(); createSurface(m_window->getHandle()); pickPhysicalDevice(); createDevice(); + createSwapchain(); createRenderPass(); + + m_window->show(); } void RenderEngine::createInstance() { @@ -43,6 +48,7 @@ namespace nf::cli::render { std::vector instanceExtNames = { VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_WIN32_SURFACE_EXTENSION_NAME }; instanceCI.ppEnabledExtensionNames = instanceExtNames.data(); instanceCI.enabledExtensionCount = instanceExtNames.size(); + if (vkCreateInstance(&instanceCI, nullptr, &m_instance) != VK_SUCCESS) NFError("Could not create Vulkan instance"); } @@ -50,6 +56,7 @@ namespace nf::cli::render { void RenderEngine::createSurface(HWND window) { VkWin32SurfaceCreateInfoKHR surfaceCI = { VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR }; surfaceCI.hwnd = window; + if (vkCreateWin32SurfaceKHR(m_instance, &surfaceCI, nullptr, &m_surface) != VK_SUCCESS) NFError("Could not create Vulkan surface"); } @@ -154,6 +161,7 @@ namespace nf::cli::render { const char* swapChainExtName = VK_KHR_SWAPCHAIN_EXTENSION_NAME; deviceCI.enabledExtensionCount = 1; deviceCI.ppEnabledExtensionNames = &swapChainExtName; + if (vkCreateDevice(m_physicalDevice, &deviceCI, nullptr, &m_device) != VK_SUCCESS) NFError("Could not create Vulkan device"); @@ -161,9 +169,75 @@ namespace nf::cli::render { vkGetDeviceQueue(m_device, m_queueFIPresent, 0, &m_queuePresent); } + void RenderEngine::createSwapchain() { + VkSurfaceCapabilitiesKHR surfaceCapabilities = {}; + vkGetPhysicalDeviceSurfaceCapabilitiesKHR(m_physicalDevice, m_surface, &surfaceCapabilities); + + uint32_t numSurfaceFormats = 0; + vkGetPhysicalDeviceSurfaceFormatsKHR(m_physicalDevice, m_surface, &numSurfaceFormats, nullptr); + if (numSurfaceFormats == 0) + NFError("No Vulkan surface formats found"); + + std::vector surfaceFormats(numSurfaceFormats); + vkGetPhysicalDeviceSurfaceFormatsKHR(m_physicalDevice, m_surface, &numSurfaceFormats, surfaceFormats.data()); + VkSurfaceFormatKHR chosenSurfaceFormat = surfaceFormats[0]; + for (int i = 0; i < surfaceFormats.size(); i++) + if (surfaceFormats[i].format == VK_FORMAT_B8G8R8A8_SRGB && surfaceFormats[i].colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) + chosenSurfaceFormat = surfaceFormats[i]; + + uint32_t numPresentModes = 0; + vkGetPhysicalDeviceSurfacePresentModesKHR(m_physicalDevice, m_surface, &numPresentModes, nullptr); + if (numPresentModes == 0) + NFError("No Vulkan surface present modes found"); + + std::vector presentModes(numPresentModes); + vkGetPhysicalDeviceSurfacePresentModesKHR(m_physicalDevice, m_surface, &numPresentModes, presentModes.data()); + VkPresentModeKHR chosenPresentMode = VK_PRESENT_MODE_FIFO_KHR; + // TODO: IMMEDIATE isn't always available, so do something about that + for (int i = 0; i < presentModes.size(); i++) + if (presentModes[i] == VK_PRESENT_MODE_IMMEDIATE_KHR) + chosenPresentMode = presentModes[i]; + + VkExtent2D swapchainExtent = surfaceCapabilities.currentExtent; + if (swapchainExtent.width == std::numeric_limits::max()) + swapchainExtent.width = m_display.width, swapchainExtent.height = m_display.height; + + uint32_t numRequestedImages = surfaceCapabilities.minImageCount + (surfaceCapabilities.minImageCount != surfaceCapabilities.maxImageCount ? 1 : 0); + + VkSwapchainCreateInfoKHR swapchainCI = { VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR }; + swapchainCI.surface = m_surface; + swapchainCI.minImageCount = numRequestedImages; + swapchainCI.imageFormat = m_swapchainImageFormat = chosenSurfaceFormat.format; + swapchainCI.imageColorSpace = chosenSurfaceFormat.colorSpace; + swapchainCI.imageExtent = swapchainExtent; + swapchainCI.imageArrayLayers = 1; + swapchainCI.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + + std::vector queueFamilyIndices = { m_queueFIGraphics, m_queueFIPresent }; + if (m_queueFIGraphics != m_queueFIPresent) { + swapchainCI.imageSharingMode = VK_SHARING_MODE_CONCURRENT; + swapchainCI.queueFamilyIndexCount = 2; + swapchainCI.pQueueFamilyIndices = queueFamilyIndices.data(); + } + + swapchainCI.preTransform = surfaceCapabilities.currentTransform; + swapchainCI.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; + swapchainCI.presentMode = chosenPresentMode; + swapchainCI.clipped = VK_TRUE; + swapchainCI.oldSwapchain = VK_NULL_HANDLE; + + if (vkCreateSwapchainKHR(m_device, &swapchainCI, nullptr, &m_swapchain) != VK_SUCCESS) + NFError("Could not create Vulkan swapchain"); + + uint32_t numSwapchainImages = 0; + vkGetSwapchainImagesKHR(m_device, m_swapchain, &numSwapchainImages, nullptr); + m_swapchainImages.resize(numSwapchainImages); + vkGetSwapchainImagesKHR(m_device, m_swapchain, &numSwapchainImages, m_swapchainImages.data()); + } + void RenderEngine::createRenderPass() { VkAttachmentDescription outputColorAttachment = {}; - outputColorAttachment.format = VK_FORMAT_R8G8B8A8_SRGB; + outputColorAttachment.format = m_swapchainImageFormat; outputColorAttachment.samples = VK_SAMPLE_COUNT_1_BIT; outputColorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; outputColorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; @@ -186,12 +260,14 @@ namespace nf::cli::render { renderPassCI.pAttachments = &outputColorAttachment; renderPassCI.subpassCount = 1; renderPassCI.pSubpasses = &subpassDescription; + if (vkCreateRenderPass(m_device, &renderPassCI, nullptr, &m_renderPassOutput) != VK_SUCCESS) NFError("Could not create Vulkan render pass"); } RenderEngine::~RenderEngine() { vkDestroyRenderPass(m_device, m_renderPassOutput, nullptr); + vkDestroySwapchainKHR(m_device, m_swapchain, nullptr); vkDestroyDevice(m_device, nullptr); vkDestroySurfaceKHR(m_instance, m_surface, nullptr); vkDestroyInstance(m_instance, nullptr); diff --git a/NothinFancy/src/client/render/RenderEngine.h b/NothinFancy/src/client/render/RenderEngine.h index c0f6654..709bac0 100644 --- a/NothinFancy/src/client/render/RenderEngine.h +++ b/NothinFancy/src/client/render/RenderEngine.h @@ -4,7 +4,7 @@ #include "client/Window.h" #include "nf/config.h" -namespace nf::cli::render { +namespace nf::client::render { class RenderEngine { public: RenderEngine(std::shared_ptr window, DisplayConfig display); @@ -15,6 +15,7 @@ namespace nf::cli::render { void createSurface(HWND window); void pickPhysicalDevice(); void createDevice(); + void createSwapchain(); void createRenderPass(); std::shared_ptr m_window; @@ -27,5 +28,8 @@ namespace nf::cli::render { VkDevice m_device; VkQueue m_queueGraphics, m_queuePresent; VkRenderPass m_renderPassOutput; + VkSwapchainKHR m_swapchain; + VkFormat m_swapchainImageFormat; + std::vector m_swapchainImages; }; } diff --git a/NothinFancy/src/pch.h b/NothinFancy/src/pch.h index 2d31879..f907c21 100644 --- a/NothinFancy/src/pch.h +++ b/NothinFancy/src/pch.h @@ -37,6 +37,7 @@ // Windows #define WIN32_LEAN_AND_MEAN #include +#undef max // Vulkan #define VK_USE_PLATFORM_WIN32_KHR diff --git a/NothinFancy/src/util/util.cpp b/NothinFancy/src/util/util.cpp index 337d42d..cd9160c 100644 --- a/NothinFancy/src/util/util.cpp +++ b/NothinFancy/src/util/util.cpp @@ -3,8 +3,6 @@ #include "util.h" -#undef max - namespace nf::util { double getRand() { static std::random_device dev;