window resize handled, instance improved a bit

This commit is contained in:
Blue 2023-10-14 19:57:47 -03:00
parent e114c36690
commit 2b33897b4a
Signed by: blue
GPG Key ID: 9B203B252A63EE38
16 changed files with 182 additions and 115 deletions

View File

@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.0)
cmake_minimum_required(VERSION 3.5)
project(stories VERSION 0.0.1 LANGUAGES CXX)
cmake_policy(SET CMP0076 NEW)

View File

@ -1,51 +1,23 @@
#include "engine.h"
#include "instance.h"
constexpr const char* validationLayerName("VK_LAYER_KHRONOS_validation");
Engine::Engine::Engine() :
initialized(false),
window(new Window()),
instance(nullptr),
instance(new Instance()),
surface(nullptr),
physicalDevice(nullptr),
logicalDevice(nullptr),
layerNames(),
instanceExtensionNames(),
deviceExtensionNames(),
layers(),
instanceExtensions(),
deviceExtensions()
{
addDeviceExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
}
Engine::Engine::~Engine() {
delete instance;
delete window;
}
bool Engine::Engine::enableValidationLayers() const {
return instanceExtensionNames.count(VK_EXT_DEBUG_REPORT_EXTENSION_NAME) > 0 &&
instanceExtensionNames.count(VK_EXT_DEBUG_UTILS_EXTENSION_NAME) > 0 &&
layerNames.count(validationLayerName) > 0;
}
void Engine::Engine::addLayer(const std::string& layerName) {
if (initialized)
throw std::runtime_error("Adding layers to an initialized engine is not supported yet");
layerNames.insert(layerName);
}
void Engine::Engine::addInstanceExtension(const std::string& extensionName) {
if (initialized)
throw std::runtime_error("Adding extension to an initialized engine is not supported yet");
std::pair<std::set<std::string>::const_iterator, bool> pair = instanceExtensionNames.insert(extensionName);
if (pair.second)
instanceExtensions.push_back(pair.first->c_str());
}
void Engine::Engine::addDeviceExtension(const std::string& extensionName) {
if (initialized)
throw std::runtime_error("Adding extension to an initialized engine is not supported yet");
@ -56,17 +28,15 @@ void Engine::Engine::addDeviceExtension(const std::string& extensionName) {
}
void Engine::Engine::enableDebug() {
addLayer(validationLayerName);
addInstanceExtension(VK_EXT_DEBUG_REPORT_EXTENSION_NAME);
addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
instance->enableDebug();
}
void Engine::Engine::initVulkan() {
instance = new Instance(this);
instance->initialize(window->getRequiredVulkanExtensions());
surface = new Surface(instance, window);
pickPhysicalDevice();
logicalDevice = new LogicalDevice(physicalDevice, surface, deviceExtensions, layers);
logicalDevice = new LogicalDevice(physicalDevice, surface, deviceExtensions, instance->getLayers());
logicalDevice->createGraphicsPipeline("shaders/shader.vert.spv", "shaders/shader.frag.spv");
logicalDevice->createSwapChain();
@ -82,8 +52,7 @@ void Engine::Engine::cleanup() {
delete surface;
surface = nullptr;
delete instance;
instance = nullptr;
instance->deinitialize();
}
void Engine::Engine::pickPhysicalDevice() {
@ -108,10 +77,6 @@ void Engine::Engine::pickPhysicalDevice() {
throw std::runtime_error("failed to find a suitable GPU!");
}
std::vector<const char *> Engine::Engine::getRequiredVulkanExtensions() const {
return window->getRequiredVulkanExtensions();
}
void Engine::Engine::run() {
initVulkan();
mainLoop();
@ -127,8 +92,14 @@ void Engine::Engine::mainLoop() {
//Handle events on queue
while (SDL_PollEvent(&e) != 0) {
//close the window when user clicks the X button or alt-f4s
if (e.type == SDL_QUIT)
bQuit = true;
switch (e.type) {
case SDL_QUIT:
bQuit = true;
break;
case SDL_WINDOWEVENT:
handleWindowEvent(e.window);
break;
}
}
logicalDevice->drawFrame();
@ -136,3 +107,12 @@ void Engine::Engine::mainLoop() {
logicalDevice->waitIdle();
}
void Engine::Engine::handleWindowEvent(const SDL_WindowEvent& e) {
switch (e.event) {
case SDL_WINDOWEVENT_RESIZED:
case SDL_WINDOWEVENT_SIZE_CHANGED:
logicalDevice->setResized();
break;
}
}

View File

@ -23,6 +23,7 @@
#include "window.h"
#include "surface.h"
#include "instance.h"
#include "physicaldevice.h"
#include "logicaldevice.h"
@ -30,21 +31,21 @@ namespace Engine {
const int MAX_FRAMES_IN_FLIGHT = 2;
class Instance;
class Engine {
friend class Instance;
public:
Engine();
~Engine();
void run();
bool enableValidationLayers() const;
void addLayer(const std::string& layerName);
void addInstanceExtension(const std::string& extensionName);
void addDeviceExtension(const std::string& extensionName);
void enableDebug();
std::vector<const char *> getRequiredVulkanExtensions() const;
private:
void initVulkan();
void mainLoop();
void cleanup();
void pickPhysicalDevice();
void handleWindowEvent(const SDL_WindowEvent& e);
private:
bool initialized;
@ -53,17 +54,9 @@ private:
Surface* surface;
PhysicalDevice* physicalDevice;
LogicalDevice* logicalDevice;
std::set<std::string> layerNames;
std::set<std::string> instanceExtensionNames;
std::set<std::string> deviceExtensionNames;
std::vector<const char*> layers;
std::vector<const char*> instanceExtensions;
std::vector<const char*> deviceExtensions;
void initVulkan();
void mainLoop();
void cleanup();
void pickPhysicalDevice();
};
}

View File

@ -1,13 +1,26 @@
#include "instance.h"
#include "engine.h"
constexpr const char* validationLayerName("VK_LAYER_KHRONOS_validation");
Engine::Instance::Instance(Engine* eng) :
Engine::Instance::Instance() :
initialized(false),
validationLayersEnabledAndSupported(false),
engine(eng),
layerNames(),
extensionNames(),
layers(),
extensions(),
vk(),
debugMessenger()
{
{}
Engine::Instance::~Instance() {
deinitialize();
}
void Engine::Instance::initialize(const std::vector<const char*>& requiredExtensions) {
if (initialized)
return;
VkApplicationInfo appInfo {};
appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
appInfo.pApplicationName = "Hello Triangle";
@ -18,19 +31,19 @@ Engine::Instance::Instance(Engine* eng) :
appInfo.pNext = nullptr;
//TODO handle exception
Support exts = getVulkanExtensions(engine->instanceExtensionNames, engine->getRequiredVulkanExtensions());
Support exts = getVulkanExtensions(extensionNames, requiredExtensions);
if (exts.unsupportedCritical.size() > 0) {
std::string error("Unable to create Vulkan instance, following critical extensions are unsupported:\n");
for (const char* ext : exts.unsupportedCritical) {
for (const char* ext : exts.unsupportedCritical)
error += "\t" + std::string(ext) + "\n";
}
throw std::runtime_error(error);
}
//TODO log unsupported;
exts.logSupported("Applying extensions:");
//TODO handle exception
Support layers = getVulkanLayers(engine->layerNames);
Support layers = getVulkanLayers(layerNames);
//TODO log unsupported
layers.logSupported("Applying layers:");
@ -44,7 +57,7 @@ Engine::Instance::Instance(Engine* eng) :
createInfo.ppEnabledLayerNames = layers.supported.data();
VkDebugUtilsMessengerCreateInfoEXT debugCreateInfo {};
if (engine->enableValidationLayers()) {
if (hasValidationLayers()) {
validationLayersEnabledAndSupported = true; //TODO make sure it's actually supported, this shows that they are just enabled;
populateDebugMessengerCreateInfo(debugCreateInfo, debugCallback);
createInfo.pNext = (VkDebugUtilsMessengerCreateInfoEXT*) &debugCreateInfo;
@ -72,13 +85,49 @@ Engine::Instance::Instance(Engine* eng) :
if (validationLayersEnabledAndSupported)
setupDebugMessenger();
initialized = true;
}
Engine::Instance::~Instance() {
void Engine::Instance::deinitialize() {
if (!initialized)
return;
if (validationLayersEnabledAndSupported)
destroyDebugUtilsMessengerEXT(vk, debugMessenger, nullptr);
vkDestroyInstance(vk, nullptr);
initialized = false;
}
void Engine::Instance::addExtension(const std::string& extensionName) {
if (initialized)
throw std::runtime_error("Adding extension to an initialized engine is not supported yet");
std::pair<std::set<std::string>::const_iterator, bool> pair = extensionNames.insert(extensionName);
if (pair.second)
extensions.push_back(pair.first->c_str());
}
void Engine::Instance::addLayer(const std::string& layerName) {
if (initialized)
throw std::runtime_error("Adding layers to an initialized engine is not supported yet");
std::pair<std::set<std::string>::const_iterator, bool> pair = layerNames.insert(layerName);
if (pair.second)
layers.push_back(pair.first->c_str());
}
bool Engine::Instance::hasValidationLayers() {
return extensionNames.count(VK_EXT_DEBUG_REPORT_EXTENSION_NAME) > 0 &&
extensionNames.count(VK_EXT_DEBUG_UTILS_EXTENSION_NAME) > 0 &&
layerNames.count(validationLayerName) > 0;
}
void Engine::Instance::enableDebug() {
addLayer(validationLayerName);
addExtension(VK_EXT_DEBUG_REPORT_EXTENSION_NAME);
addExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
}
void Engine::Instance::setupDebugMessenger() {
@ -108,3 +157,6 @@ std::vector<VkPhysicalDevice> Engine::Instance::enumeratePhysicalDevices() const
return devices;
}
std::vector<const char *> Engine::Instance::getLayers() const {
return layers;
}

View File

@ -2,30 +2,40 @@
#include <vulkan/vulkan.h>
#include <vector>
#include <set>
#include "utils.h"
namespace Engine {
class Engine;
class Window;
class Surface;
class Instance {
friend class Engine;
friend class Surface;
public:
Instance(Engine* engine);
Instance();
~Instance();
void initialize(const std::vector<const char*>& requiredExtensions);
void deinitialize();
void addLayer(const std::string& layerName);
void addExtension(const std::string& extensionName);
void enableDebug();
std::vector<const char*> getLayers() const;
std::vector<VkPhysicalDevice> enumeratePhysicalDevices() const;
private:
void setupDebugMessenger();
bool hasValidationLayers();
private:
bool initialized;
bool validationLayersEnabledAndSupported;
Engine* engine;
std::set<std::string> layerNames;
std::set<std::string> extensionNames;
std::vector<const char*> layers;
std::vector<const char*> extensions;
VkInstance vk;
VkDebugUtilsMessengerEXT debugMessenger;
};

View File

@ -1,6 +1,7 @@
#include "logicaldevice.h"
#include "swapchain.h"
#include <iostream>
constexpr int MAX_FRAMES_IN_FLIGHT = 2;
constexpr float queuePriority = 1.0f;
@ -269,6 +270,10 @@ void Engine::LogicalDevice::drawFrame() {
currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT;
}
void Engine::LogicalDevice::setResized() {
framebufferResized = true;
}
VkExtent2D Engine::LogicalDevice::chooseSwapExtent() const {
return surface->chooseSwapExtent(phys->swapChainSupport.capabilities);
}
@ -564,5 +569,6 @@ void Engine::LogicalDevice::recordCommandBuffer(VkCommandBuffer commandBuffer, u
void Engine::LogicalDevice::recreateSwapChain() {
surface->waitForResize();
waitIdle();
phys->recreateSwapChainSupportDetails(surface);
createSwapChain();
}

View File

@ -10,11 +10,9 @@
#include "surface.h"
namespace Engine {
class Engine;
class SwapChain;
class LogicalDevice {
friend class Engine;
public:
LogicalDevice(
PhysicalDevice* physicalDevice,
@ -28,6 +26,7 @@ public:
void clearSwapChain();
void createGraphicsPipeline(const std::string& vertexShaderPath, const std::string& fragmentShaderPath);
void recreateSwapChain();
void setResized();
void drawFrame();

View File

@ -32,3 +32,7 @@ bool Engine::PhysicalDevice::checkDeviceExtensionSupport(VkPhysicalDevice device
return requiredExtensions.empty();
}
void Engine::PhysicalDevice::recreateSwapChainSupportDetails(const Surface* surface) {
swapChainSupport = surface->querySwapChainSupport(vk);
}

View File

@ -7,21 +7,22 @@
#include <vulkan/vulkan.h>
#include "utils.h"
#include "surface.h"
namespace Engine {
class Engine;
class LogicalDevice;
class PhysicalDevice {
friend class Engine;
friend class LogicalDevice;
public:
PhysicalDevice(VkPhysicalDevice raw, const QueueFamilyIndices& indices, const SwapChainSupportDetails& swapChainSupport);
void recreateSwapChainSupportDetails(const Surface* surface);
static bool checkDeviceExtensionSupport(VkPhysicalDevice device, std::set<std::string> requiredExtensions);
const QueueFamilyIndices indices;
const SwapChainSupportDetails swapChainSupport;
SwapChainSupportDetails swapChainSupport;
private:
VkPhysicalDevice vk;

View File

@ -86,3 +86,6 @@ VkExtent2D Engine::Surface::waitForResize() const {
return window->waitForResize();
}
VkExtent2D Engine::Surface::getSize() const {
return window->getSize();
}

View File

@ -20,6 +20,7 @@ public:
VkExtent2D waitForResize() const;
VkExtent2D chooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities) const;
VkExtent2D getSize() const;
VkSurfaceFormatKHR chooseSwapSurfaceFormat(const SwapChainSupportDetails& swapChainSupport) const;
bool isDeviceSutable(VkPhysicalDevice device) const;
SwapChainSupportDetails querySwapChainSupport(VkPhysicalDevice device) const;

View File

@ -10,6 +10,21 @@ Engine::SwapChain::SwapChain(LogicalDevice* logical):
imageViews(),
frameBuffers()
{
create();
}
Engine::SwapChain::SwapChain(LogicalDevice* logical, const VkExtent2D& extent):
logical(logical),
vk(),
images(),
extent(extent),
imageViews(),
frameBuffers()
{
create();
}
void Engine::SwapChain::create() {
VkResult result = logical->createVkSwapChain(extent, vk);
if (result != VK_SUCCESS)
@ -31,6 +46,7 @@ Engine::SwapChain::SwapChain(LogicalDevice* logical):
}
}
Engine::SwapChain::~SwapChain() {
for (VkFramebuffer& buffer : frameBuffers)
logical->destroyVkFrameBuffer(buffer);

View File

@ -11,11 +11,15 @@ class SwapChain {
friend class LogicalDevice;
public:
SwapChain(LogicalDevice* logical);
SwapChain(LogicalDevice* logical, const VkExtent2D& extent);
~SwapChain();
VkExtent2D getExtent() const;
VkFramebuffer getFrameBuffer(uint32_t index);
private:
void create();
private:
LogicalDevice* logical;
VkSwapchainKHR vk;

View File

@ -10,18 +10,17 @@ Engine::Support Engine::getVulkanLayers(const std::set<std::string>& requestedLa
Engine::Support result;
if (!discoveredLayers) {
std::vector<VkLayerProperties> props = getAvailableVulkanLayers();
for (const VkLayerProperties& prop : props) {
for (const VkLayerProperties& prop : props)
availableLayers.insert(std::make_pair(prop.layerName, prop));
}
discoveredLayers = true;
}
for (const std::string& ext : requestedLayers) {
if (availableLayers.count(ext) > 0) {
if (availableLayers.count(ext) > 0)
result.supported.push_back(ext.c_str());
} else {
else
result.unsupported.push_back(ext.c_str());
}
}
return result;
@ -34,26 +33,24 @@ Engine::Support Engine::getVulkanExtensions(
Support result;
if (!discoveredExtensions) {
std::vector<VkExtensionProperties> props = getAvailableVulkanExtensions();
for (const VkExtensionProperties& prop : props) {
for (const VkExtensionProperties& prop : props)
availableExtensions.insert(std::make_pair(prop.extensionName, prop));
}
discoveredExtensions = true;
}
for (const char* ext : criticalExtensions) {
if (availableExtensions.count(ext) > 0) {
if (availableExtensions.count(ext) > 0)
result.supported.push_back(ext);
} else {
else
result.unsupportedCritical.push_back(ext);
}
}
for (const std::string& ext : requestedExtensions) {
if (availableExtensions.count(ext) > 0) {
if (availableExtensions.count(ext) > 0)
result.supported.push_back(ext.c_str());
} else {
else
result.unsupported.push_back(ext.c_str());
}
}
return result;
@ -62,15 +59,13 @@ Engine::Support Engine::getVulkanExtensions(
std::vector<VkExtensionProperties> Engine::getAvailableVulkanExtensions() {
unsigned int extCount = 0;
VkResult res = vkEnumerateInstanceExtensionProperties(nullptr, &extCount, nullptr);
if (res != VK_SUCCESS) {
if (res != VK_SUCCESS)
throw std::runtime_error("unable to query vulkan extension property count");
}
std::vector<VkExtensionProperties> extensions(extCount);
res = vkEnumerateInstanceExtensionProperties(nullptr, &extCount, extensions.data());
if (res != VK_SUCCESS) {
if (res != VK_SUCCESS)
throw std::runtime_error("unable to retrieve vulkan instance layer names");
}
return extensions;
}
@ -95,15 +90,13 @@ void Engine::populateDebugMessengerCreateInfo(
std::vector<VkLayerProperties> Engine::getAvailableVulkanLayers() {
unsigned int layerCount = 0;
VkResult res = vkEnumerateInstanceLayerProperties(&layerCount, nullptr);
if (res != VK_SUCCESS) {
if (res != VK_SUCCESS)
throw std::runtime_error("unable to query vulkan instance layer property count");
}
std::vector<VkLayerProperties> layers(layerCount);
res = vkEnumerateInstanceLayerProperties(&layerCount, layers.data());
if (res != VK_SUCCESS) {
if (res != VK_SUCCESS)
throw std::runtime_error("unable to retrieve vulkan instance layer names");
}
return layers;
}
@ -175,9 +168,8 @@ std::vector<char> Engine::readFile(const std::string& filename) {
VkSurfaceFormatKHR Engine::chooseSwapSurfaceFormat(const std::vector<VkSurfaceFormatKHR>& availableFormats) {
for (const VkSurfaceFormatKHR& availableFormat : availableFormats) {
if (availableFormat.format == VK_FORMAT_B8G8R8A8_SRGB && availableFormat.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
if (availableFormat.format == VK_FORMAT_B8G8R8A8_SRGB && availableFormat.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR)
return availableFormat;
}
}
return availableFormats[0];
@ -185,9 +177,8 @@ VkSurfaceFormatKHR Engine::chooseSwapSurfaceFormat(const std::vector<VkSurfaceFo
VkPresentModeKHR Engine::chooseSwapPresentMode(const std::vector<VkPresentModeKHR>& availablePresentModes) {
for (const auto& availablePresentMode : availablePresentModes) {
if (availablePresentMode == VK_PRESENT_MODE_MAILBOX_KHR) {
if (availablePresentMode == VK_PRESENT_MODE_MAILBOX_KHR)
return availablePresentMode;
}
}
return VK_PRESENT_MODE_FIFO_KHR;

View File

@ -1,18 +1,11 @@
#include "window.h"
#include <iostream>
Engine::Window::Window(uint32_t width, uint32_t height) :
sdl(createWindow(width, height)),
extent({width, height})
{
//glfwSetWindowUserPointer(window, this);
//glfwSetFramebufferSizeCallback(window, framebufferResizeCallback);
}
// static void framebufferResizeCallback(SDL_Window* window, int width, int height) {
// auto app = reinterpret_cast<HelloTriangleApplication*>(glfwGetWindowUserPointer(window));
// app->framebufferResized = true;
// }
{}
Engine::Window::~Window() {
SDL_DestroyWindow(sdl);
@ -27,7 +20,7 @@ SDL_Window* Engine::Window::createWindow(uint32_t width, uint32_t height) {
SDL_WINDOWPOS_UNDEFINED,
width,
height,
SDL_WINDOW_VULKAN
SDL_WINDOW_VULKAN | SDL_WINDOW_RESIZABLE
);
return wnd;
@ -59,6 +52,18 @@ VkExtent2D Engine::Window::getDrawableSize() const {
return actualExtent;
}
VkExtent2D Engine::Window::getSize() const {
int width, height;
SDL_GetWindowSize(sdl, &width, &height);
VkExtent2D actualExtent = {
static_cast<uint32_t>(width),
static_cast<uint32_t>(height)
};
return actualExtent;
}
void Engine::Window::createSurface(VkInstance instance, VkSurfaceKHR* out) const {
if (SDL_Vulkan_CreateSurface(sdl, instance, out) != SDL_TRUE) {
throw std::runtime_error("failed to create window surface!");
@ -74,6 +79,7 @@ VkExtent2D Engine::Window::chooseSwapExtent(const VkSurfaceCapabilitiesKHR& capa
actualExtent.width = std::clamp(actualExtent.width, capabilities.minImageExtent.width, capabilities.maxImageExtent.width);
actualExtent.height = std::clamp(actualExtent.height, capabilities.minImageExtent.height, capabilities.maxImageExtent.height);
std::cout << actualExtent.width << ":" << actualExtent.height << std::endl;
return actualExtent;
}
}

View File

@ -21,6 +21,7 @@ public:
std::vector<const char *> getRequiredVulkanExtensions() const;
VkExtent2D waitForResize() const;
VkExtent2D getSize() const;
VkExtent2D getDrawableSize() const;
VkExtent2D chooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities) const;
void createSurface(VkInstance instance, VkSurfaceKHR* out) const;