Create Vulkan swapchain

This commit is contained in:
Grayson Riffe 2025-02-11 03:24:53 -06:00
parent b0005c250f
commit 1824b73d66
9 changed files with 90 additions and 11 deletions

View File

@ -25,7 +25,7 @@ namespace nf {
// Start client // Start client
{ {
cli::Client client(config); client::Client client(config);
client.run(); client.run();
} }

View File

@ -4,7 +4,7 @@
#include "Client.h" #include "Client.h"
#include "util.h" #include "util.h"
namespace nf::cli { namespace nf::client {
Client::Client(ClientConfig config) Client::Client(ClientConfig config)
: m_running(true) : m_running(true)
, m_config(config) , m_config(config)

View File

@ -5,7 +5,7 @@
#include "Window.h" #include "Window.h"
#include "render/RenderEngine.h" #include "render/RenderEngine.h"
namespace nf::cli { namespace nf::client {
class Client { class Client {
public: public:
Client(ClientConfig config); Client(ClientConfig config);

View File

@ -4,7 +4,7 @@
#include "Window.h" #include "Window.h"
#include "util.h" #include "util.h"
namespace nf::cli { namespace nf::client {
Window::Window(const char* windowTitle) Window::Window(const char* windowTitle)
: m_handle(nullptr) : m_handle(nullptr)
, m_wndClassName("NothinFancyWindow") , m_wndClassName("NothinFancyWindow")

View File

@ -5,7 +5,7 @@
#include <Windows.h> #include <Windows.h>
namespace nf::cli { namespace nf::client {
class Window { class Window {
public: public:
Window(const char* windowTitle); Window(const char* windowTitle);

View File

@ -4,7 +4,7 @@
#include "RenderEngine.h" #include "RenderEngine.h"
#include "util.h" #include "util.h"
namespace nf::cli::render { namespace nf::client::render {
RenderEngine::RenderEngine(std::shared_ptr<Window> window, DisplayConfig display) RenderEngine::RenderEngine(std::shared_ptr<Window> window, DisplayConfig display)
: m_window(window) : m_window(window)
, m_display(display) , m_display(display)
@ -17,16 +17,21 @@ namespace nf::cli::render {
, m_queueGraphics() , m_queueGraphics()
, m_queuePresent() , m_queuePresent()
, m_renderPassOutput() , m_renderPassOutput()
, m_swapchain()
, m_swapchainImageFormat()
, m_swapchainImages()
{ {
NFLog("Initializing render engine"); NFLog("Initializing render engine");
m_window->setDisplay(m_display); m_window->setDisplay(m_display);
m_window->show();
createInstance(); createInstance();
createSurface(m_window->getHandle()); createSurface(m_window->getHandle());
pickPhysicalDevice(); pickPhysicalDevice();
createDevice(); createDevice();
createSwapchain();
createRenderPass(); createRenderPass();
m_window->show();
} }
void RenderEngine::createInstance() { void RenderEngine::createInstance() {
@ -43,6 +48,7 @@ namespace nf::cli::render {
std::vector<const char*> instanceExtNames = { VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_WIN32_SURFACE_EXTENSION_NAME }; std::vector<const char*> instanceExtNames = { VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_WIN32_SURFACE_EXTENSION_NAME };
instanceCI.ppEnabledExtensionNames = instanceExtNames.data(); instanceCI.ppEnabledExtensionNames = instanceExtNames.data();
instanceCI.enabledExtensionCount = instanceExtNames.size(); instanceCI.enabledExtensionCount = instanceExtNames.size();
if (vkCreateInstance(&instanceCI, nullptr, &m_instance) != VK_SUCCESS) if (vkCreateInstance(&instanceCI, nullptr, &m_instance) != VK_SUCCESS)
NFError("Could not create Vulkan instance"); NFError("Could not create Vulkan instance");
} }
@ -50,6 +56,7 @@ namespace nf::cli::render {
void RenderEngine::createSurface(HWND window) { void RenderEngine::createSurface(HWND window) {
VkWin32SurfaceCreateInfoKHR surfaceCI = { VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR }; VkWin32SurfaceCreateInfoKHR surfaceCI = { VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR };
surfaceCI.hwnd = window; surfaceCI.hwnd = window;
if (vkCreateWin32SurfaceKHR(m_instance, &surfaceCI, nullptr, &m_surface) != VK_SUCCESS) if (vkCreateWin32SurfaceKHR(m_instance, &surfaceCI, nullptr, &m_surface) != VK_SUCCESS)
NFError("Could not create Vulkan surface"); NFError("Could not create Vulkan surface");
} }
@ -154,6 +161,7 @@ namespace nf::cli::render {
const char* swapChainExtName = VK_KHR_SWAPCHAIN_EXTENSION_NAME; const char* swapChainExtName = VK_KHR_SWAPCHAIN_EXTENSION_NAME;
deviceCI.enabledExtensionCount = 1; deviceCI.enabledExtensionCount = 1;
deviceCI.ppEnabledExtensionNames = &swapChainExtName; deviceCI.ppEnabledExtensionNames = &swapChainExtName;
if (vkCreateDevice(m_physicalDevice, &deviceCI, nullptr, &m_device) != VK_SUCCESS) if (vkCreateDevice(m_physicalDevice, &deviceCI, nullptr, &m_device) != VK_SUCCESS)
NFError("Could not create Vulkan device"); NFError("Could not create Vulkan device");
@ -161,9 +169,75 @@ namespace nf::cli::render {
vkGetDeviceQueue(m_device, m_queueFIPresent, 0, &m_queuePresent); 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<VkSurfaceFormatKHR> 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<VkPresentModeKHR> 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<uint32_t>::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<uint32_t> 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() { void RenderEngine::createRenderPass() {
VkAttachmentDescription outputColorAttachment = {}; VkAttachmentDescription outputColorAttachment = {};
outputColorAttachment.format = VK_FORMAT_R8G8B8A8_SRGB; outputColorAttachment.format = m_swapchainImageFormat;
outputColorAttachment.samples = VK_SAMPLE_COUNT_1_BIT; outputColorAttachment.samples = VK_SAMPLE_COUNT_1_BIT;
outputColorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; outputColorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
outputColorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; outputColorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
@ -186,12 +260,14 @@ namespace nf::cli::render {
renderPassCI.pAttachments = &outputColorAttachment; renderPassCI.pAttachments = &outputColorAttachment;
renderPassCI.subpassCount = 1; renderPassCI.subpassCount = 1;
renderPassCI.pSubpasses = &subpassDescription; renderPassCI.pSubpasses = &subpassDescription;
if (vkCreateRenderPass(m_device, &renderPassCI, nullptr, &m_renderPassOutput) != VK_SUCCESS) if (vkCreateRenderPass(m_device, &renderPassCI, nullptr, &m_renderPassOutput) != VK_SUCCESS)
NFError("Could not create Vulkan render pass"); NFError("Could not create Vulkan render pass");
} }
RenderEngine::~RenderEngine() { RenderEngine::~RenderEngine() {
vkDestroyRenderPass(m_device, m_renderPassOutput, nullptr); vkDestroyRenderPass(m_device, m_renderPassOutput, nullptr);
vkDestroySwapchainKHR(m_device, m_swapchain, nullptr);
vkDestroyDevice(m_device, nullptr); vkDestroyDevice(m_device, nullptr);
vkDestroySurfaceKHR(m_instance, m_surface, nullptr); vkDestroySurfaceKHR(m_instance, m_surface, nullptr);
vkDestroyInstance(m_instance, nullptr); vkDestroyInstance(m_instance, nullptr);

View File

@ -4,7 +4,7 @@
#include "client/Window.h" #include "client/Window.h"
#include "nf/config.h" #include "nf/config.h"
namespace nf::cli::render { namespace nf::client::render {
class RenderEngine { class RenderEngine {
public: public:
RenderEngine(std::shared_ptr<Window> window, DisplayConfig display); RenderEngine(std::shared_ptr<Window> window, DisplayConfig display);
@ -15,6 +15,7 @@ namespace nf::cli::render {
void createSurface(HWND window); void createSurface(HWND window);
void pickPhysicalDevice(); void pickPhysicalDevice();
void createDevice(); void createDevice();
void createSwapchain();
void createRenderPass(); void createRenderPass();
std::shared_ptr<Window> m_window; std::shared_ptr<Window> m_window;
@ -27,5 +28,8 @@ namespace nf::cli::render {
VkDevice m_device; VkDevice m_device;
VkQueue m_queueGraphics, m_queuePresent; VkQueue m_queueGraphics, m_queuePresent;
VkRenderPass m_renderPassOutput; VkRenderPass m_renderPassOutput;
VkSwapchainKHR m_swapchain;
VkFormat m_swapchainImageFormat;
std::vector<VkImage> m_swapchainImages;
}; };
} }

View File

@ -37,6 +37,7 @@
// Windows // Windows
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
#include <Windows.h> #include <Windows.h>
#undef max
// Vulkan // Vulkan
#define VK_USE_PLATFORM_WIN32_KHR #define VK_USE_PLATFORM_WIN32_KHR

View File

@ -3,8 +3,6 @@
#include "util.h" #include "util.h"
#undef max
namespace nf::util { namespace nf::util {
double getRand() { double getRand() {
static std::random_device dev; static std::random_device dev;