Create Vulkan swapchain
This commit is contained in:
parent
b0005c250f
commit
1824b73d66
@ -25,7 +25,7 @@ namespace nf {
|
|||||||
|
|
||||||
// Start client
|
// Start client
|
||||||
{
|
{
|
||||||
cli::Client client(config);
|
client::Client client(config);
|
||||||
client.run();
|
client.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
@ -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);
|
||||||
|
@ -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")
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user