Refactored main function to use a singleton patten
This commit is contained in:
parent
29599e4b9a
commit
db832a7dae
@ -18,7 +18,6 @@ namespace DeviceControl {
|
|||||||
VkPhysicalDeviceProperties deviceProperties;
|
VkPhysicalDeviceProperties deviceProperties;
|
||||||
VkPhysicalDeviceFeatures deviceFeatures;
|
VkPhysicalDeviceFeatures deviceFeatures;
|
||||||
|
|
||||||
|
|
||||||
std::vector<VkImage> swapChainImages;
|
std::vector<VkImage> swapChainImages;
|
||||||
VkFormat swapChainImageFormat;
|
VkFormat swapChainImageFormat;
|
||||||
VkExtent2D swapChainExtent;
|
VkExtent2D swapChainExtent;
|
||||||
@ -298,6 +297,7 @@ namespace DeviceControl {
|
|||||||
vkDestroySwapchainKHR(Global::device, Global::swapChain, nullptr);
|
vkDestroySwapchainKHR(Global::device, Global::swapChain, nullptr);
|
||||||
if(Global::enableValidationLayers) std::cout << "Destroyed Swap Chain safely\n" << std::endl;
|
if(Global::enableValidationLayers) std::cout << "Destroyed Swap Chain safely\n" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
void devicelibrary::createImageViews() {
|
void devicelibrary::createImageViews() {
|
||||||
swapChainImageViews.resize(swapChainImages.size());
|
swapChainImageViews.resize(swapChainImages.size());
|
||||||
for(size_t i = 0; i < swapChainImages.size(); i++) {
|
for(size_t i = 0; i < swapChainImages.size(); i++) {
|
||||||
@ -332,7 +332,6 @@ namespace DeviceControl {
|
|||||||
}
|
}
|
||||||
if(Global::enableValidationLayers) std::cout << "Image destroyed safely\n" << std::endl;
|
if(Global::enableValidationLayers) std::cout << "Image destroyed safely\n" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------------------------------- Getters & Setters ------------------------------------------ //
|
// --------------------------------------- Getters & Setters ------------------------------------------ //
|
||||||
VkFormat devicelibrary::getImageFormat() {
|
VkFormat devicelibrary::getImageFormat() {
|
||||||
return swapChainImageFormat;
|
return swapChainImageFormat;
|
||||||
@ -340,6 +339,7 @@ namespace DeviceControl {
|
|||||||
std::vector<VkImageView> devicelibrary::getSwapChainImageViews() {
|
std::vector<VkImageView> devicelibrary::getSwapChainImageViews() {
|
||||||
return swapChainImageViews;
|
return swapChainImageViews;
|
||||||
}
|
}
|
||||||
|
|
||||||
VkExtent2D devicelibrary::getSwapChainExtent() {
|
VkExtent2D devicelibrary::getSwapChainExtent() {
|
||||||
return swapChainExtent;
|
return swapChainExtent;
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "global.h"
|
#include "global.h"
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
#include <vulkan/vulkan_core.h>
|
||||||
namespace DeviceControl {
|
namespace DeviceControl {
|
||||||
class devicelibrary {
|
class devicelibrary {
|
||||||
public:
|
public:
|
||||||
@ -19,6 +20,7 @@ class devicelibrary {
|
|||||||
VkFormat getImageFormat();
|
VkFormat getImageFormat();
|
||||||
std::vector<VkImageView> getSwapChainImageViews();
|
std::vector<VkImageView> getSwapChainImageViews();
|
||||||
VkExtent2D getSwapChainExtent();
|
VkExtent2D getSwapChainExtent();
|
||||||
|
std::vector<VkFramebuffer> getSwapChainFramebuffers();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
119
src/entrypoint.cpp
Normal file
119
src/entrypoint.cpp
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
#include "entrypoint.h"
|
||||||
|
DeviceControl::devicelibrary deviceLibs;
|
||||||
|
Debug::vulkandebuglibs debugController;
|
||||||
|
Graphics::graphicspipeline graphicsPipeline;
|
||||||
|
RenderPresent::render renderPresentation;
|
||||||
|
VkInstance vulkaninstance;
|
||||||
|
|
||||||
|
|
||||||
|
void EntryApp::setFramebufferResized(bool setter) {
|
||||||
|
framebufferResized = setter;
|
||||||
|
}
|
||||||
|
bool EntryApp::getFramebufferResized() const {
|
||||||
|
return framebufferResized;
|
||||||
|
}
|
||||||
|
static void framebufferResizeCallback(GLFWwindow* window, int width, int height) {
|
||||||
|
auto app = reinterpret_cast<EntryApp*>(glfwGetWindowUserPointer(window));
|
||||||
|
app->EntryApp::getInstance().setFramebufferResized(true);
|
||||||
|
}
|
||||||
|
// Initialize GLFW Window. First, Initialize GLFW lib, disable resizing for
|
||||||
|
// now, and create window.
|
||||||
|
void initWindow() {
|
||||||
|
glfwInit();
|
||||||
|
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
||||||
|
glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
|
||||||
|
|
||||||
|
// Settings for the window are set, create window reference.
|
||||||
|
Global::window = glfwCreateWindow(Global::WIDTH, Global::HEIGHT, "Vulkan", nullptr, nullptr);
|
||||||
|
glfwSetWindowUserPointer(Global::window, &EntryApp::getInstance());
|
||||||
|
glfwSetFramebufferSizeCallback(Global::window, framebufferResizeCallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void createInstance() {
|
||||||
|
debugController.checkUnavailableValidationLayers(); // Check if there is a mistake with our Validation Layers.
|
||||||
|
|
||||||
|
// Set application info for the vulkan instance!
|
||||||
|
VkApplicationInfo appInfo{};
|
||||||
|
|
||||||
|
appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; // Tell vulkan that appInfo is a Application Info structure
|
||||||
|
appInfo.pApplicationName = "Triangle Test"; // Give the struct a name to use
|
||||||
|
appInfo.applicationVersion = VK_MAKE_VERSION(1,0,0); // Create a Major Minor Patch version number for the application!
|
||||||
|
appInfo.pEngineName = "Agnosia Engine"; // Give an internal name for the engine running
|
||||||
|
appInfo.engineVersion = VK_MAKE_VERSION(1,0,0); // Similar to the App version, give vulkan an *engine* version
|
||||||
|
appInfo.apiVersion = VK_API_VERSION_1_1; // Tell vulkan what the highest API version we will allow this program to run on
|
||||||
|
|
||||||
|
VkInstanceCreateInfo createInfo{}; // Define parameters of new vulkan instance
|
||||||
|
createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; // Tell vulkan this is a info structure
|
||||||
|
createInfo.pApplicationInfo = &appInfo; // We just created a new appInfo structure, so we pass the pointer to it.
|
||||||
|
|
||||||
|
debugController.vulkanDebugSetup(createInfo, vulkaninstance); // Handoff to the debug library to wrap the validation libs in! (And set the window up!)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void initVulkan() {
|
||||||
|
createInstance();
|
||||||
|
debugController.setupDebugMessenger(vulkaninstance); // The debug messenger is out holy grail, it gives us Vulkan related debug info when built with the -DNDEBUG flag (as per the makefile)
|
||||||
|
deviceLibs.createSurface(vulkaninstance, Global::window);
|
||||||
|
deviceLibs.pickPhysicalDevice(vulkaninstance);
|
||||||
|
deviceLibs.createLogicalDevice();
|
||||||
|
deviceLibs.createSwapChain(Global::window);
|
||||||
|
deviceLibs.createImageViews();
|
||||||
|
graphicsPipeline.createRenderPass();
|
||||||
|
graphicsPipeline.createGraphicsPipeline();
|
||||||
|
graphicsPipeline.createFramebuffers();
|
||||||
|
graphicsPipeline.createCommandPool();
|
||||||
|
graphicsPipeline.createCommandBuffer();
|
||||||
|
renderPresentation.createSyncObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
void mainLoop() { // This loop just updates the GLFW window.
|
||||||
|
while (!glfwWindowShouldClose(Global::window)) {
|
||||||
|
glfwPollEvents();
|
||||||
|
renderPresentation.drawFrame();
|
||||||
|
}
|
||||||
|
vkDeviceWaitIdle(Global::device);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cleanup() { // Similar to the last handoff, destroy the utils in a safe manner in the library!
|
||||||
|
renderPresentation.cleanupSwapChain();
|
||||||
|
graphicsPipeline.destroyGraphicsPipeline();
|
||||||
|
graphicsPipeline.destroyRenderPass();
|
||||||
|
renderPresentation.destroyFenceSemaphores();
|
||||||
|
graphicsPipeline.destroyCommandPool();
|
||||||
|
|
||||||
|
deviceLibs.destroyImageViews();
|
||||||
|
deviceLibs.destroySwapChain();
|
||||||
|
|
||||||
|
vkDestroyDevice(Global::device, nullptr);
|
||||||
|
if(Global::enableValidationLayers) {
|
||||||
|
debugController.DestroyDebugUtilsMessengerEXT(vulkaninstance, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
deviceLibs.destroySurface(vulkaninstance);
|
||||||
|
vkDestroyInstance(vulkaninstance, nullptr);
|
||||||
|
glfwDestroyWindow(Global::window);
|
||||||
|
glfwTerminate();
|
||||||
|
}
|
||||||
|
|
||||||
|
EntryApp& EntryApp::getInstance() {
|
||||||
|
static EntryApp instance;
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
EntryApp::EntryApp() : initialized(false), framebufferResized(false) {}
|
||||||
|
|
||||||
|
void EntryApp::initialize() {
|
||||||
|
initialized = true;
|
||||||
|
}
|
||||||
|
bool EntryApp::isInitialized() const {
|
||||||
|
return initialized;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EntryApp::run() {
|
||||||
|
initWindow();
|
||||||
|
initVulkan();
|
||||||
|
mainLoop();
|
||||||
|
cleanup();
|
||||||
|
}
|
||||||
|
|
24
src/entrypoint.h
Normal file
24
src/entrypoint.h
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
#include <cstdlib>
|
||||||
|
#include "devicelibrary.h" // Device Library includes global, redundant to include with it here
|
||||||
|
#include "debug/vulkandebuglibs.h"
|
||||||
|
#include "graphics/graphicspipeline.h"
|
||||||
|
#include "graphics/render.h"
|
||||||
|
class EntryApp {
|
||||||
|
public:
|
||||||
|
static EntryApp& getInstance();
|
||||||
|
void initialize();
|
||||||
|
bool isInitialized() const;
|
||||||
|
void run();
|
||||||
|
void setFramebufferResized(bool frame);
|
||||||
|
bool getFramebufferResized() const;
|
||||||
|
private:
|
||||||
|
EntryApp();
|
||||||
|
|
||||||
|
EntryApp(const EntryApp&) = delete;
|
||||||
|
void operator=(const EntryApp&) = delete;
|
||||||
|
|
||||||
|
bool framebufferResized;
|
||||||
|
bool initialized;
|
||||||
|
|
||||||
|
|
||||||
|
};
|
@ -1,5 +1,6 @@
|
|||||||
#include "global.h"
|
#include "global.h"
|
||||||
#include "devicelibrary.h"
|
#include "devicelibrary.h"
|
||||||
|
#include <vulkan/vulkan_core.h>
|
||||||
namespace Global {
|
namespace Global {
|
||||||
|
|
||||||
const std::vector<const char*> validationLayers = {
|
const std::vector<const char*> validationLayers = {
|
||||||
@ -11,14 +12,16 @@ namespace Global {
|
|||||||
const bool enableValidationLayers = false;
|
const bool enableValidationLayers = false;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
VkSurfaceKHR surface = VK_NULL_HANDLE;
|
VkSurfaceKHR surface;
|
||||||
VkDevice device = VK_NULL_HANDLE;
|
VkDevice device;
|
||||||
VkPhysicalDevice physicalDevice = VK_NULL_HANDLE;
|
VkPhysicalDevice physicalDevice;
|
||||||
VkSwapchainKHR swapChain = VK_NULL_HANDLE;
|
VkSwapchainKHR swapChain;
|
||||||
VkCommandPool commandPool = VK_NULL_HANDLE;
|
VkCommandPool commandPool;
|
||||||
std::vector<VkCommandBuffer> commandBuffers;
|
std::vector<VkCommandBuffer> commandBuffers;
|
||||||
VkQueue graphicsQueue = VK_NULL_HANDLE;
|
VkQueue graphicsQueue;
|
||||||
VkQueue presentQueue = VK_NULL_HANDLE;
|
VkQueue presentQueue;
|
||||||
|
GLFWwindow* window;
|
||||||
|
|
||||||
Global::QueueFamilyIndices findQueueFamilies(VkPhysicalDevice device) {
|
Global::QueueFamilyIndices findQueueFamilies(VkPhysicalDevice device) {
|
||||||
// First we feed in a integer we want to use to hold the number of queued items, that fills it, then we create that amount of default constructed *VkQueueFamilyProperties* structs.
|
// First we feed in a integer we want to use to hold the number of queued items, that fills it, then we create that amount of default constructed *VkQueueFamilyProperties* structs.
|
||||||
// These store the flags, the amount of queued items in the family, and timestamp data. Queue families are simply group collections of tasks we want to get done.
|
// These store the flags, the amount of queued items in the family, and timestamp data. Queue families are simply group collections of tasks we want to get done.
|
||||||
|
@ -19,6 +19,11 @@ namespace Global {
|
|||||||
extern VkQueue graphicsQueue;
|
extern VkQueue graphicsQueue;
|
||||||
extern VkQueue presentQueue;
|
extern VkQueue presentQueue;
|
||||||
const int MAX_FRAMES_IN_FLIGHT = 2;
|
const int MAX_FRAMES_IN_FLIGHT = 2;
|
||||||
|
extern GLFWwindow* window;
|
||||||
|
|
||||||
|
const uint32_t WIDTH = 800;
|
||||||
|
const uint32_t HEIGHT = 600;
|
||||||
|
|
||||||
struct QueueFamilyIndices {
|
struct QueueFamilyIndices {
|
||||||
// We need to check that the Queue families support graphics operations and window presentation, sometimes they can support one or the other,
|
// We need to check that the Queue families support graphics operations and window presentation, sometimes they can support one or the other,
|
||||||
// therefore, we take into account both for completion.
|
// therefore, we take into account both for completion.
|
||||||
|
@ -9,7 +9,6 @@ namespace Graphics {
|
|||||||
VK_DYNAMIC_STATE_VIEWPORT,
|
VK_DYNAMIC_STATE_VIEWPORT,
|
||||||
VK_DYNAMIC_STATE_SCISSOR
|
VK_DYNAMIC_STATE_SCISSOR
|
||||||
};
|
};
|
||||||
std::vector<VkFramebuffer> swapChainFramebuffers;
|
|
||||||
|
|
||||||
|
|
||||||
VkRenderPass renderPass;
|
VkRenderPass renderPass;
|
||||||
@ -17,6 +16,8 @@ namespace Graphics {
|
|||||||
VkPipeline graphicsPipeline;
|
VkPipeline graphicsPipeline;
|
||||||
DeviceControl::devicelibrary deviceLibs;
|
DeviceControl::devicelibrary deviceLibs;
|
||||||
|
|
||||||
|
std::vector<VkFramebuffer> swapChainFramebuffers;
|
||||||
|
|
||||||
static std::vector<char> readFile(const std::string& filename) {
|
static std::vector<char> readFile(const std::string& filename) {
|
||||||
std::ifstream file(filename, std::ios::ate | std::ios::binary);
|
std::ifstream file(filename, std::ios::ate | std::ios::binary);
|
||||||
if (!file.is_open()) {
|
if (!file.is_open()) {
|
||||||
@ -233,12 +234,6 @@ namespace Graphics {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void graphicspipeline::destroyFramebuffers() {
|
|
||||||
for (auto framebuffer : swapChainFramebuffers) {
|
|
||||||
vkDestroyFramebuffer(Global::device, framebuffer, nullptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void graphicspipeline::createCommandPool() {
|
void graphicspipeline::createCommandPool() {
|
||||||
|
|
||||||
Global::QueueFamilyIndices queueFamilyIndices = Global::findQueueFamilies(Global::physicalDevice);
|
Global::QueueFamilyIndices queueFamilyIndices = Global::findQueueFamilies(Global::physicalDevice);
|
||||||
@ -319,4 +314,7 @@ namespace Graphics {
|
|||||||
throw std::runtime_error("failed to record command buffer!");
|
throw std::runtime_error("failed to record command buffer!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
std::vector<VkFramebuffer> graphicspipeline::getSwapChainFramebuffers() {
|
||||||
|
return swapChainFramebuffers;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,5 +14,6 @@ namespace Graphics {
|
|||||||
void destroyCommandPool();
|
void destroyCommandPool();
|
||||||
void createCommandBuffer();
|
void createCommandBuffer();
|
||||||
void recordCommandBuffer(VkCommandBuffer cmndBuffer, uint32_t imageIndex);
|
void recordCommandBuffer(VkCommandBuffer cmndBuffer, uint32_t imageIndex);
|
||||||
|
std::vector<VkFramebuffer> getSwapChainFramebuffers();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,31 @@
|
|||||||
#include "render.h"
|
#include "render.h"
|
||||||
#include "graphicspipeline.h"
|
#include "graphicspipeline.h"
|
||||||
|
#include "../devicelibrary.h"
|
||||||
|
#include "../entrypoint.h"
|
||||||
namespace RenderPresent {
|
namespace RenderPresent {
|
||||||
|
|
||||||
std::vector<VkSemaphore> imageAvailableSemaphores;
|
std::vector<VkSemaphore> imageAvailableSemaphores;
|
||||||
std::vector<VkSemaphore> renderFinishedSemaphores;
|
std::vector<VkSemaphore> renderFinishedSemaphores;
|
||||||
std::vector<VkFence> inFlightFences;
|
std::vector<VkFence> inFlightFences;
|
||||||
Graphics::graphicspipeline pipeline;
|
Graphics::graphicspipeline pipeline;
|
||||||
|
DeviceControl::devicelibrary deviceLibs;
|
||||||
uint32_t currentFrame = 0;
|
uint32_t currentFrame = 0;
|
||||||
|
|
||||||
|
void recreateSwapChain() {
|
||||||
|
vkDeviceWaitIdle(Global::device);
|
||||||
|
// Don't really wanna do this but I also don't want to create an extra class instance just to call the cleanup function.
|
||||||
|
for(auto framebuffer : pipeline.getSwapChainFramebuffers()) {
|
||||||
|
vkDestroyFramebuffer(Global::device, framebuffer, nullptr);
|
||||||
|
}
|
||||||
|
for(auto imageView : deviceLibs.getSwapChainImageViews()) {
|
||||||
|
vkDestroyImageView(Global::device, imageView, nullptr);
|
||||||
|
}
|
||||||
|
vkDestroySwapchainKHR(Global::device, Global::swapChain, nullptr);
|
||||||
|
|
||||||
|
deviceLibs.createSwapChain(Global::window);
|
||||||
|
deviceLibs.createImageViews();
|
||||||
|
pipeline.createFramebuffers();
|
||||||
|
}
|
||||||
// At a high level, rendering in Vulkan consists of 5 steps:
|
// At a high level, rendering in Vulkan consists of 5 steps:
|
||||||
// Wait for the previous frame, acquire a image from the swap chain
|
// Wait for the previous frame, acquire a image from the swap chain
|
||||||
// record a comman d buffer which draws the scene onto that image
|
// record a comman d buffer which draws the scene onto that image
|
||||||
@ -17,7 +36,14 @@ namespace RenderPresent {
|
|||||||
vkResetFences(Global::device, 1, &inFlightFences[currentFrame]);
|
vkResetFences(Global::device, 1, &inFlightFences[currentFrame]);
|
||||||
|
|
||||||
uint32_t imageIndex;
|
uint32_t imageIndex;
|
||||||
vkAcquireNextImageKHR(Global::device, Global::swapChain, UINT64_MAX, imageAvailableSemaphores[currentFrame], VK_NULL_HANDLE, &imageIndex);
|
VkResult result = vkAcquireNextImageKHR(Global::device, Global::swapChain, UINT64_MAX, imageAvailableSemaphores[currentFrame], VK_NULL_HANDLE, &imageIndex);
|
||||||
|
if (result == VK_ERROR_OUT_OF_DATE_KHR) {
|
||||||
|
recreateSwapChain();
|
||||||
|
return;
|
||||||
|
} else if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR) {
|
||||||
|
throw std::runtime_error("failed to acquire swap chain image!");
|
||||||
|
}
|
||||||
|
vkResetFences(Global::device, 1, &inFlightFences[currentFrame]);
|
||||||
|
|
||||||
vkResetCommandBuffer(Global::commandBuffers[currentFrame], /*VkCommandBufferResetFlagBits*/ 0);
|
vkResetCommandBuffer(Global::commandBuffers[currentFrame], /*VkCommandBufferResetFlagBits*/ 0);
|
||||||
pipeline.recordCommandBuffer(Global::commandBuffers[currentFrame], imageIndex);
|
pipeline.recordCommandBuffer(Global::commandBuffers[currentFrame], imageIndex);
|
||||||
@ -54,7 +80,13 @@ namespace RenderPresent {
|
|||||||
|
|
||||||
presentInfo.pImageIndices = &imageIndex;
|
presentInfo.pImageIndices = &imageIndex;
|
||||||
|
|
||||||
vkQueuePresentKHR(Global::presentQueue, &presentInfo);
|
result = vkQueuePresentKHR(Global::presentQueue, &presentInfo);
|
||||||
|
if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || EntryApp::getInstance().getFramebufferResized()) {
|
||||||
|
EntryApp::getInstance().setFramebufferResized(false);
|
||||||
|
recreateSwapChain();
|
||||||
|
} else if (result != VK_SUCCESS) {
|
||||||
|
throw std::runtime_error("failed to present swap chain image!");
|
||||||
|
}
|
||||||
currentFrame = (currentFrame + 1) % Global::MAX_FRAMES_IN_FLIGHT;
|
currentFrame = (currentFrame + 1) % Global::MAX_FRAMES_IN_FLIGHT;
|
||||||
}
|
}
|
||||||
#pragma info
|
#pragma info
|
||||||
@ -70,7 +102,8 @@ namespace RenderPresent {
|
|||||||
// enqueue QueueOne, Signal semaphore when done, start now.
|
// enqueue QueueOne, Signal semaphore when done, start now.
|
||||||
// vkQueueSubmit(work: QueueOne, signal: semaphore, wait: none)
|
// vkQueueSubmit(work: QueueOne, signal: semaphore, wait: none)
|
||||||
// enqueue QueueTwo, wait on semaphore to start
|
// enqueue QueueTwo, wait on semaphore to start
|
||||||
// vkQueueSubmit(work: QueueTwo, signal: None, wait: semaphore)
|
// vkQueueSubmit(
|
||||||
|
// work: QueueTwo, signal: None, wait: semaphore)
|
||||||
// FENCES
|
// FENCES
|
||||||
// Fences are basically semaphores for the CPU! Otherwise known as the host. If the host needs to know when the GPU has finished a task, we use a fence.
|
// Fences are basically semaphores for the CPU! Otherwise known as the host. If the host needs to know when the GPU has finished a task, we use a fence.
|
||||||
// VkCommandBuffer cmndBuf = ...
|
// VkCommandBuffer cmndBuf = ...
|
||||||
@ -103,11 +136,21 @@ namespace RenderPresent {
|
|||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
void destroyFenceSemaphore() {
|
void render::destroyFenceSemaphores() {
|
||||||
for (size_t i = 0; i < Global::MAX_FRAMES_IN_FLIGHT; i++) {
|
for (size_t i = 0; i < Global::MAX_FRAMES_IN_FLIGHT; i++) {
|
||||||
vkDestroySemaphore(Global::device, imageAvailableSemaphores[i], nullptr);
|
vkDestroySemaphore(Global::device, imageAvailableSemaphores[i], nullptr);
|
||||||
vkDestroySemaphore(Global::device, renderFinishedSemaphores[i], nullptr);
|
vkDestroySemaphore(Global::device, renderFinishedSemaphores[i], nullptr);
|
||||||
vkDestroyFence(Global::device, inFlightFences[i], nullptr);
|
vkDestroyFence(Global::device, inFlightFences[i], nullptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
void render::cleanupSwapChain() {
|
||||||
|
for(auto framebuffer : pipeline.getSwapChainFramebuffers()) {
|
||||||
|
vkDestroyFramebuffer(Global::device, framebuffer, nullptr);
|
||||||
|
}
|
||||||
|
for(auto imageView : deviceLibs.getSwapChainImageViews()) {
|
||||||
|
vkDestroyImageView(Global::device, imageView, nullptr);
|
||||||
|
}
|
||||||
|
vkDestroySwapchainKHR(Global::device, Global::swapChain, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -7,5 +7,7 @@ class render {
|
|||||||
public:
|
public:
|
||||||
void drawFrame();
|
void drawFrame();
|
||||||
void createSyncObject();
|
void createSyncObject();
|
||||||
|
void destroyFenceSemaphores();
|
||||||
|
void cleanupSwapChain();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
111
src/main.cpp
111
src/main.cpp
@ -1,114 +1,9 @@
|
|||||||
#include "devicelibrary.h" // Device Library includes global, redundant to include with it here
|
#include "entrypoint.h"
|
||||||
#include "debug/vulkandebuglibs.h"
|
|
||||||
#include "graphics/graphicspipeline.h"
|
|
||||||
#include "graphics/render.h"
|
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
#include <cstring>
|
|
||||||
#include <cstdlib>
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
const uint32_t WIDTH = 800;
|
|
||||||
const uint32_t HEIGHT = 600;
|
|
||||||
|
|
||||||
// Define a base class structure to handle public and private methods
|
|
||||||
class TriangleTestApplication {
|
|
||||||
|
|
||||||
public:
|
|
||||||
void run() {
|
|
||||||
initWindow();
|
|
||||||
initVulkan();
|
|
||||||
mainLoop();
|
|
||||||
cleanup();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
DeviceControl::devicelibrary deviceLibs;
|
|
||||||
Debug::vulkandebuglibs debugController;
|
|
||||||
Graphics::graphicspipeline graphicsPipeline;
|
|
||||||
RenderPresent::render renderPresentation;
|
|
||||||
GLFWwindow* window;
|
|
||||||
VkInstance instance;
|
|
||||||
|
|
||||||
// Initialize GLFW Window. First, Initialize GLFW lib, disable resizing for
|
|
||||||
// now, and create window.
|
|
||||||
void initWindow() {
|
|
||||||
glfwInit();
|
|
||||||
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
|
||||||
glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
|
|
||||||
|
|
||||||
// Settings for the window are set, create window reference.
|
|
||||||
window = glfwCreateWindow(WIDTH, HEIGHT, "Vulkan", nullptr, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void initVulkan() {
|
|
||||||
createInstance();
|
|
||||||
debugController.setupDebugMessenger(instance); // The debug messenger is out holy grail, it gives us Vulkan related debug info when built with the -DNDEBUG flag (as per the makefile)
|
|
||||||
deviceLibs.createSurface(instance, window);
|
|
||||||
deviceLibs.pickPhysicalDevice(instance);
|
|
||||||
deviceLibs.createLogicalDevice();
|
|
||||||
deviceLibs.createSwapChain(window);
|
|
||||||
deviceLibs.createImageViews();
|
|
||||||
graphicsPipeline.createRenderPass();
|
|
||||||
graphicsPipeline.createGraphicsPipeline();
|
|
||||||
graphicsPipeline.createFramebuffers();
|
|
||||||
graphicsPipeline.createCommandPool();
|
|
||||||
graphicsPipeline.createCommandBuffer();
|
|
||||||
renderPresentation.createSyncObject();
|
|
||||||
}
|
|
||||||
|
|
||||||
void createInstance() {
|
|
||||||
debugController.checkUnavailableValidationLayers(); // Check if there is a mistake with our Validation Layers.
|
|
||||||
|
|
||||||
// Set application info for the vulkan instance!
|
|
||||||
VkApplicationInfo appInfo{};
|
|
||||||
|
|
||||||
appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; // Tell vulkan that appInfo is a Application Info structure
|
|
||||||
appInfo.pApplicationName = "Triangle Test"; // Give the struct a name to use
|
|
||||||
appInfo.applicationVersion = VK_MAKE_VERSION(1,0,0); // Create a Major Minor Patch version number for the application!
|
|
||||||
appInfo.pEngineName = "Agnosia Engine"; // Give an internal name for the engine running
|
|
||||||
appInfo.engineVersion = VK_MAKE_VERSION(1,0,0); // Similar to the App version, give vulkan an *engine* version
|
|
||||||
appInfo.apiVersion = VK_API_VERSION_1_1; // Tell vulkan what the highest API version we will allow this program to run on
|
|
||||||
|
|
||||||
VkInstanceCreateInfo createInfo{}; // Define parameters of new vulkan instance
|
|
||||||
createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; // Tell vulkan this is a info structure
|
|
||||||
createInfo.pApplicationInfo = &appInfo; // We just created a new appInfo structure, so we pass the pointer to it.
|
|
||||||
|
|
||||||
debugController.vulkanDebugSetup(createInfo, instance); // Handoff to the debug library to wrap the validation libs in! (And set the window up!)
|
|
||||||
}
|
|
||||||
|
|
||||||
void mainLoop() { // This loop just updates the GLFW window.
|
|
||||||
while (!glfwWindowShouldClose(window)) {
|
|
||||||
glfwPollEvents();
|
|
||||||
renderPresentation.drawFrame();
|
|
||||||
}
|
|
||||||
vkDeviceWaitIdle(Global::device);
|
|
||||||
}
|
|
||||||
|
|
||||||
void cleanup() { // Similar to the last handoff, destroy the utils in a safe manner in the library!
|
|
||||||
graphicsPipeline.destroyCommandPool();
|
|
||||||
graphicsPipeline.destroyFramebuffers();
|
|
||||||
graphicsPipeline.destroyGraphicsPipeline();
|
|
||||||
graphicsPipeline.destroyRenderPass();
|
|
||||||
deviceLibs.destroyImageViews();
|
|
||||||
deviceLibs.destroySwapChain();
|
|
||||||
vkDestroyDevice(Global::device, nullptr);
|
|
||||||
if(Global::enableValidationLayers) {
|
|
||||||
debugController.DestroyDebugUtilsMessengerEXT(instance, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
deviceLibs.destroySurface(instance);
|
|
||||||
vkDestroyInstance(instance, nullptr);
|
|
||||||
glfwDestroyWindow(window);
|
|
||||||
glfwTerminate();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
TriangleTestApplication app;
|
EntryApp::getInstance().initialize();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
app.run();
|
EntryApp::getInstance().run();
|
||||||
} catch (const std::exception &e) {
|
} catch (const std::exception &e) {
|
||||||
std::cerr << e.what() << std::endl;
|
std::cerr << e.what() << std::endl;
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
|
Loading…
Reference in New Issue
Block a user