clean up a RIDICULOUS amount of shit code lmfao, instantiation < static calls (im dumb as hell)

This commit is contained in:
Lillian Salehi 2024-10-16 06:02:15 -05:00
parent 56fb496ec7
commit af7b533f50
18 changed files with 341 additions and 382 deletions

View File

@ -1,27 +1,26 @@
#include "vulkandebuglibs.h" #include "vulkandebuglibs.h"
using namespace Debug;
// This is our messenger object! It handles passing along debug messages to the debug callback we will also set. // This is our messenger object! It handles passing along debug messages to the debug callback we will also set.
VkDebugUtilsMessengerEXT debugMessenger; VkDebugUtilsMessengerEXT debugMessenger;
// This is the set of "layers" to hook into. Basically, layers are used to tell the messenger what data we want, its a filter. *validation* is the general blanket layer to cover incorrect usage. // This is the set of "layers" to hook into. Basically, layers are used to tell the messenger what data we want, its a filter. *validation* is the general blanket layer to cover incorrect usage.
namespace debug_libs {
std::vector<const char*> getRequiredExtensions() { std::vector<const char*> getRequiredExtensions() {
// This gets a little weird, Vulkan is platform agnostic, so you need to figure out what extensions to interface with the current system are needed // This gets a little weird, Vulkan is platform agnostic, so you need to figure out what extensions to interface with the current system are needed
// So, to figure out what extension codes and how many to use, feed the pointer into *glfwGetRequiredInstanceExtensions*, which will get the necessary extensions! // So, to figure out what extension codes and how many to use, feed the pointer into *glfwGetRequiredInstanceExtensions*, which will get the necessary extensions!
// From there, we can send that over to our createInfo Vulkan info struct to make it fully platform agnostic! // From there, we can send that over to our createInfo Vulkan info struct to make it fully platform agnostic!
uint32_t glfwExtensionCount = 0; uint32_t glfwExtensionCount = 0;
const char** glfwExtensions; const char** glfwExtensions;
glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount); glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);
std::vector<const char*> extensions(glfwExtensions, glfwExtensions + glfwExtensionCount); std::vector<const char*> extensions(glfwExtensions, glfwExtensions + glfwExtensionCount);
if(Global::enableValidationLayers) { if(Global::enableValidationLayers) {
extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
}
return extensions;
} }
return extensions;
}
static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback( static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback(
VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
VkDebugUtilsMessageTypeFlagsEXT messageType, VkDebugUtilsMessageTypeFlagsEXT messageType,
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
@ -33,119 +32,119 @@ static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback(
std::cout << "\n"; std::cout << "\n";
return VK_FALSE; return VK_FALSE;
}
void populateDebugMessengerCreateInfo(VkDebugUtilsMessengerCreateInfoEXT& createInfo) {
// There is absolutely nothing about this i like, those long ass flags for messageType and Severity are just fucking hex values. Khronos should never cook again ToT
// On a serious note, this is just a struct to define the parameters of the debug messenger, nothing super special.
createInfo = {};
createInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
createInfo.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
createInfo.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
createInfo.pfnUserCallback = debugCallback;
createInfo.pUserData = nullptr; // Optional
}
void vulkandebuglibs::vulkanDebugSetup(VkInstanceCreateInfo& createInfo, VkInstance& instance) {
// This function is quite useful, we first populate the debug create info structure, all the parameters dictating how the debug messenger will operate.
// The reason we populate the debug messenger so late is actually on purpose, we need to set the createInfo, which depends on the debugMessenger info,
// and if we set it before the creation of the instance, we cant debug vkCreateInstance or vkDestroyInstance! It's timed perfectly as of now.
VkDebugUtilsMessengerCreateInfoEXT debugCreateInfo{};
auto extensions = getRequiredExtensions();
createInfo.enabledExtensionCount = static_cast<uint32_t>(extensions.size());
createInfo.ppEnabledExtensionNames = extensions.data();
if(Global::enableValidationLayers) {
createInfo.enabledLayerCount = static_cast<uint32_t>(Global::validationLayers.size());
createInfo.ppEnabledLayerNames = Global::validationLayers.data();
populateDebugMessengerCreateInfo(debugCreateInfo);
createInfo.pNext = (VkDebugUtilsMessengerCreateInfoEXT*) &debugCreateInfo;
} else {
createInfo.enabledLayerCount = 0;
createInfo.pNext = nullptr;
} }
if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) {
throw std::runtime_error("failed to create instance!");
void populateDebugMessengerCreateInfo(VkDebugUtilsMessengerCreateInfoEXT& createInfo) {
// There is absolutely nothing about this i like, those long ass flags for messageType and Severity are just fucking hex values. Khronos should never cook again ToT
// On a serious note, this is just a struct to define the parameters of the debug messenger, nothing super special.
createInfo = {};
createInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
createInfo.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
createInfo.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
createInfo.pfnUserCallback = debugCallback;
createInfo.pUserData = nullptr; // Optional
} }
}
void vulkandebuglibs::checkUnavailableValidationLayers() { void Debug::vulkanDebugSetup(VkInstanceCreateInfo& createInfo, VkInstance& instance) {
// Check if we are trying to hook validation layers in without support. // This function is quite useful, we first populate the debug create info structure, all the parameters dictating how the debug messenger will operate.
if(Global::enableValidationLayers && !checkValidationLayerSupport()) { // The reason we populate the debug messenger so late is actually on purpose, we need to set the createInfo, which depends on the debugMessenger info,
throw std::runtime_error("Validation layers request, but not available! Are your SDK path variables set?"); // and if we set it before the creation of the instance, we cant debug vkCreateInstance or vkDestroyInstance! It's timed perfectly as of now.
VkDebugUtilsMessengerCreateInfoEXT debugCreateInfo{};
auto extensions = getRequiredExtensions();
createInfo.enabledExtensionCount = static_cast<uint32_t>(extensions.size());
createInfo.ppEnabledExtensionNames = extensions.data();
if(Global::enableValidationLayers) {
createInfo.enabledLayerCount = static_cast<uint32_t>(Global::validationLayers.size());
createInfo.ppEnabledLayerNames = Global::validationLayers.data();
populateDebugMessengerCreateInfo(debugCreateInfo);
createInfo.pNext = (VkDebugUtilsMessengerCreateInfoEXT*) &debugCreateInfo;
} else {
createInfo.enabledLayerCount = 0;
createInfo.pNext = nullptr;
}
if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) {
throw std::runtime_error("failed to create instance!");
}
} }
}
bool vulkandebuglibs::checkValidationLayerSupport() { void Debug::checkUnavailableValidationLayers() {
// This function is used to check Validation Layer Support, validation layers are the debug trace tools in the Vulkan SDK. // Check if we are trying to hook validation layers in without support.
// layerCount will be used as the var to keep track of the number of requested validation layer if(Global::enableValidationLayers && !checkValidationLayerSupport()) {
// VkLayerProperties is a structure with data on the layername, desc, versions and etc. throw std::runtime_error("Validation layers request, but not available! Are your SDK path variables set?");
}
}
uint32_t layerCount; bool Debug::checkValidationLayerSupport() {
vkEnumerateInstanceLayerProperties(&layerCount, nullptr); // This function is used to check Validation Layer Support, validation layers are the debug trace tools in the Vulkan SDK.
// layerCount will be used as the var to keep track of the number of requested validation layer
// VkLayerProperties is a structure with data on the layername, desc, versions and etc.
std::vector<VkLayerProperties> availableLayers(layerCount); uint32_t layerCount;
vkEnumerateInstanceLayerProperties(&layerCount, availableLayers.data()); vkEnumerateInstanceLayerProperties(&layerCount, nullptr);
for(const char* layerName : Global::validationLayers) { std::vector<VkLayerProperties> availableLayers(layerCount);
bool layerFound = false; vkEnumerateInstanceLayerProperties(&layerCount, availableLayers.data());
for(const auto& layerProperties : availableLayers) { for(const char* layerName : Global::validationLayers) {
if(strcmp(layerName, layerProperties.layerName) == 0) { bool layerFound = false;
layerFound = true;
break; for(const auto& layerProperties : availableLayers) {
if(strcmp(layerName, layerProperties.layerName) == 0) {
layerFound = true;
break;
}
}
if(!layerFound) {
return false;
} }
} }
return true;
if(!layerFound) {
return false;
}
} }
return true;
}
VkResult CreateDebugUtilsMessengerEXT( VkResult CreateDebugUtilsMessengerEXT(
VkInstance instance, VkInstance instance,
const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo, const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo,
const VkAllocationCallbacks* pAllocator, const VkAllocationCallbacks* pAllocator,
VkDebugUtilsMessengerEXT* pDebugMessenger) { VkDebugUtilsMessengerEXT* pDebugMessenger) {
// This function builds out debug messenger structure! // This function builds out debug messenger structure!
// It's a little odd, we have to look up the address of the vkCreateDebugUtilsMessengerEXT ourselves because its an extension function, // It's a little odd, we have to look up the address of the vkCreateDebugUtilsMessengerEXT ourselves because its an extension function,
// therefore, not auto-loaded. // therefore, not auto-loaded.
auto func = (PFN_vkCreateDebugUtilsMessengerEXT) vkGetInstanceProcAddr(instance, "vkCreateDebugUtilsMessengerEXT"); auto func = (PFN_vkCreateDebugUtilsMessengerEXT) vkGetInstanceProcAddr(instance, "vkCreateDebugUtilsMessengerEXT");
if (func != nullptr) { if (func != nullptr) {
return func(instance, pCreateInfo, pAllocator, pDebugMessenger); return func(instance, pCreateInfo, pAllocator, pDebugMessenger);
} else { } else {
return VK_ERROR_EXTENSION_NOT_PRESENT; return VK_ERROR_EXTENSION_NOT_PRESENT;
} }
} }
void vulkandebuglibs::DestroyDebugUtilsMessengerEXT(VkInstance instance, void Debug::DestroyDebugUtilsMessengerEXT(VkInstance instance,
const VkAllocationCallbacks* pAllocator) { const VkAllocationCallbacks* pAllocator) {
// We are doing kind of the same thing as before in the create function, find the address of the DestroyDebugUtils function, and call it. // We are doing kind of the same thing as before in the create function, find the address of the DestroyDebugUtils function, and call it.
auto func = (PFN_vkDestroyDebugUtilsMessengerEXT) vkGetInstanceProcAddr(instance, "vkDestroyDebugUtilsMessengerEXT"); auto func = (PFN_vkDestroyDebugUtilsMessengerEXT) vkGetInstanceProcAddr(instance, "vkDestroyDebugUtilsMessengerEXT");
if(func != nullptr) { if(func != nullptr) {
func(instance, debugMessenger, pAllocator); func(instance, debugMessenger, pAllocator);
}
}
void Debug::setupDebugMessenger(VkInstance& vulkanInstance) {
// This is a pretty simple function! we just pass in the values to build the debug messenger, populate the structure with the data we want,
// and safely create it, covering for runtime errors as per usual, this is the first thing that will be called!
if(!Global::enableValidationLayers) return;
VkDebugUtilsMessengerCreateInfoEXT createInfo;
populateDebugMessengerCreateInfo(createInfo);
if(CreateDebugUtilsMessengerEXT(vulkanInstance, &createInfo, nullptr, &debugMessenger) != VK_SUCCESS) {
throw std::runtime_error("Failed to set up the Debug Messenger!");
}
} }
} }
void vulkandebuglibs::setupDebugMessenger(VkInstance& vulkanInstance) {
// This is a pretty simple function! we just pass in the values to build the debug messenger, populate the structure with the data we want,
// and safely create it, covering for runtime errors as per usual, this is the first thing that will be called!
if(!Global::enableValidationLayers) return;
VkDebugUtilsMessengerCreateInfoEXT createInfo;
populateDebugMessengerCreateInfo(createInfo);
if(CreateDebugUtilsMessengerEXT(vulkanInstance, &createInfo, nullptr, &debugMessenger) != VK_SUCCESS) {
throw std::runtime_error("Failed to set up the Debug Messenger!");
}
}

View File

@ -1,17 +1,14 @@
#pragma once #pragma once
#include <vulkan/vulkan_core.h>
#include <cstdint>
#include <cstring> #include <cstring>
#include "../global.h" #include "../global.h"
namespace Debug { namespace debug_libs {
class vulkandebuglibs { class Debug {
public: public:
void vulkanDebugSetup(VkInstanceCreateInfo& createInfo, VkInstance& instance); static void vulkanDebugSetup(VkInstanceCreateInfo& createInfo, VkInstance& instance);
bool checkValidationLayerSupport(); static bool checkValidationLayerSupport();
void checkUnavailableValidationLayers(); static void checkUnavailableValidationLayers();
void setupDebugMessenger(VkInstance& vulkanInstance); static void setupDebugMessenger(VkInstance& vulkanInstance);
void DestroyDebugUtilsMessengerEXT(VkInstance instance, const VkAllocationCallbacks* pAllocator); static void DestroyDebugUtilsMessengerEXT(VkInstance instance, const VkAllocationCallbacks* pAllocator);
}; };
} }

View File

@ -1,10 +1,6 @@
#include "devicelibrary.h" #include "devicelibrary.h"
#include "global.h"
#include <vulkan/vulkan_core.h>
namespace DeviceControl {
namespace device_libs {
VkPhysicalDeviceProperties deviceProperties; VkPhysicalDeviceProperties deviceProperties;
@ -13,8 +9,6 @@ namespace DeviceControl {
VkExtent2D swapChainExtent; VkExtent2D swapChainExtent;
std::vector<VkImageView> swapChainImageViews; std::vector<VkImageView> swapChainImageViews;
struct SwapChainSupportDetails { struct SwapChainSupportDetails {
VkSurfaceCapabilitiesKHR capabilities; VkSurfaceCapabilitiesKHR capabilities;
std::vector<VkSurfaceFormatKHR> formats; std::vector<VkSurfaceFormatKHR> formats;
@ -143,7 +137,7 @@ namespace DeviceControl {
} }
} }
// --------------------------------------- External Functions ----------------------------------------- // // --------------------------------------- External Functions ----------------------------------------- //
void devicelibrary::pickPhysicalDevice(VkInstance& instance) { void DeviceControl::pickPhysicalDevice(VkInstance& instance) {
uint32_t deviceCount = 0; uint32_t deviceCount = 0;
vkEnumeratePhysicalDevices(instance, &deviceCount, nullptr); vkEnumeratePhysicalDevices(instance, &deviceCount, nullptr);
@ -165,17 +159,17 @@ namespace DeviceControl {
throw std::runtime_error("Failed to find a suitable GPU!"); throw std::runtime_error("Failed to find a suitable GPU!");
} }
} }
void devicelibrary::destroySurface(VkInstance& instance) { void DeviceControl::destroySurface(VkInstance& instance) {
vkDestroySurfaceKHR(instance, Global::surface, nullptr); vkDestroySurfaceKHR(instance, Global::surface, nullptr);
if(Global::enableValidationLayers) std::cout << "Destroyed surface safely\n" << std::endl; if(Global::enableValidationLayers) std::cout << "Destroyed surface safely\n" << std::endl;
} }
void devicelibrary::createSurface(VkInstance& instance, GLFWwindow* window) { void DeviceControl::createSurface(VkInstance& instance, GLFWwindow* window) {
if(glfwCreateWindowSurface(instance, window, nullptr, &Global::surface) != VK_SUCCESS) { if(glfwCreateWindowSurface(instance, window, nullptr, &Global::surface) != VK_SUCCESS) {
throw std::runtime_error("Failed to create window surface!!"); throw std::runtime_error("Failed to create window surface!!");
} }
if(Global::enableValidationLayers) std::cout << "GLFW Window Surface created successfully\n" << std::endl; if(Global::enableValidationLayers) std::cout << "GLFW Window Surface created successfully\n" << std::endl;
} }
void devicelibrary::createLogicalDevice() { void DeviceControl::createLogicalDevice() {
// Describe how many queues we want for a single family (1) here, right now we are solely interested in graphics capabilites, // Describe how many queues we want for a single family (1) here, right now we are solely interested in graphics capabilites,
// but Compute Shaders, transfer ops, decode and encode operations can also queued with setup! We also assign each queue a priority. // but Compute Shaders, transfer ops, decode and encode operations can also queued with setup! We also assign each queue a priority.
// We do this by looping over all the queueFamilies and sorting them by indices to fill the queue at the end! // We do this by looping over all the queueFamilies and sorting them by indices to fill the queue at the end!
@ -221,7 +215,7 @@ namespace DeviceControl {
vkGetDeviceQueue(Global::device, indices.graphicsFamily.value(), 0, &Global::graphicsQueue); vkGetDeviceQueue(Global::device, indices.graphicsFamily.value(), 0, &Global::graphicsQueue);
vkGetDeviceQueue(Global::device, indices.presentFamily.value(), 0, &Global::presentQueue); vkGetDeviceQueue(Global::device, indices.presentFamily.value(), 0, &Global::presentQueue);
} }
void devicelibrary::createSwapChain(GLFWwindow* window) { void DeviceControl::createSwapChain(GLFWwindow* window) {
SwapChainSupportDetails swapChainSupport = querySwapChainSupport(Global::physicalDevice); SwapChainSupportDetails swapChainSupport = querySwapChainSupport(Global::physicalDevice);
VkSurfaceFormatKHR surfaceFormat = chooseSwapSurfaceFormat(swapChainSupport.formats); VkSurfaceFormatKHR surfaceFormat = chooseSwapSurfaceFormat(swapChainSupport.formats);
@ -287,11 +281,11 @@ namespace DeviceControl {
swapChainImageFormat = surfaceFormat.format; swapChainImageFormat = surfaceFormat.format;
swapChainExtent = extent; swapChainExtent = extent;
} }
void devicelibrary::destroySwapChain() { void DeviceControl::destroySwapChain() {
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;
} }
VkImageView devicelibrary::createImageView(VkImage image, VkFormat format, VkImageAspectFlags flags) { VkImageView DeviceControl::createImageView(VkImage image, VkFormat format, VkImageAspectFlags flags) {
// This defines the parameters of a newly created image object! // This defines the parameters of a newly created image object!
VkImageViewCreateInfo viewInfo{}; VkImageViewCreateInfo viewInfo{};
viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
@ -311,28 +305,27 @@ namespace DeviceControl {
return imageView; return imageView;
} }
void devicelibrary::createImageViews() { void DeviceControl::createImageViews() {
swapChainImageViews.resize(swapChainImages.size()); swapChainImageViews.resize(swapChainImages.size());
for (uint32_t i = 0; i < swapChainImages.size(); i++) { for (uint32_t i = 0; i < swapChainImages.size(); i++) {
swapChainImageViews[i] = createImageView(swapChainImages[i], swapChainImageFormat, VK_IMAGE_ASPECT_COLOR_BIT); swapChainImageViews[i] = createImageView(swapChainImages[i], swapChainImageFormat, VK_IMAGE_ASPECT_COLOR_BIT);
} }
} }
void devicelibrary::destroyImageViews() { void DeviceControl::destroyImageViews() {
for (auto imageView : swapChainImageViews) { for (auto imageView : swapChainImageViews) {
vkDestroyImageView(Global::device, imageView, nullptr); vkDestroyImageView(Global::device, imageView, nullptr);
} }
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 DeviceControl::getImageFormat() {
return swapChainImageFormat; return swapChainImageFormat;
} }
std::vector<VkImageView> devicelibrary::getSwapChainImageViews() { std::vector<VkImageView> DeviceControl::getSwapChainImageViews() {
return swapChainImageViews; return swapChainImageViews;
} }
VkExtent2D DeviceControl::getSwapChainExtent() {
VkExtent2D devicelibrary::getSwapChainExtent() {
return swapChainExtent; return swapChainExtent;
} }
} }

View File

@ -1,33 +1,30 @@
#pragma once #pragma once
#include "global.h" #include "global.h"
#include <GLFW/glfw3.h>
#include <optional>
#include <algorithm> #include <algorithm>
#include <limits> #include <limits>
#include <ostream>
#include <set> #include <set>
#include <string> #include <string>
#include <vector>
namespace DeviceControl { namespace device_libs {
class devicelibrary { class DeviceControl {
public: public:
void pickPhysicalDevice(VkInstance& instance); static void pickPhysicalDevice(VkInstance& instance);
void createLogicalDevice(); static void createLogicalDevice();
void createSurface(VkInstance& instance, GLFWwindow* window); static void createSurface(VkInstance& instance, GLFWwindow* window);
void destroySurface(VkInstance& instance); static void destroySurface(VkInstance& instance);
void createSwapChain(GLFWwindow* window); static void createSwapChain(GLFWwindow* window);
void destroySwapChain(); static void destroySwapChain();
VkImageView createImageView(VkImage image, VkFormat format, VkImageAspectFlags flags); static VkImageView createImageView(VkImage image, VkFormat format, VkImageAspectFlags flags);
void createImageViews(); static void createImageViews();
void destroyImageViews(); static void destroyImageViews();
void createCommandPool(); static void createCommandPool();
void destroyCommandPool(); static void destroyCommandPool();
// ---------- Getters & Setters ----------- // // ---------- Getters & Setters ----------- //
VkFormat getImageFormat(); static VkFormat getImageFormat();
std::vector<VkImageView> getSwapChainImageViews(); static std::vector<VkImageView> getSwapChainImageViews();
VkExtent2D getSwapChainExtent(); static VkExtent2D getSwapChainExtent();
std::vector<VkFramebuffer> getSwapChainFramebuffers(); static std::vector<VkFramebuffer> getSwapChainFramebuffers();
}; };
} }

View File

@ -1,14 +1,6 @@
#include "entrypoint.h" #include "entrypoint.h"
DeviceControl::devicelibrary deviceLibs;
Debug::vulkandebuglibs debugController;
Graphics::graphicspipeline graphicsPipeline;
RenderPresent::render renderPresentation;
BuffersLibraries::buffers buffers;
TextureLibraries::texture texture;
ModelLib::model model;
VkInstance vulkaninstance;
//TODO: add global instances? VkInstance vulkaninstance;
// Getters and Setters! // Getters and Setters!
void EntryApp::setFramebufferResized(bool setter) { void EntryApp::setFramebufferResized(bool setter) {
@ -21,8 +13,9 @@ static void framebufferResizeCallback(GLFWwindow* window, int width, int height)
auto app = reinterpret_cast<EntryApp*>(glfwGetWindowUserPointer(window)); auto app = reinterpret_cast<EntryApp*>(glfwGetWindowUserPointer(window));
app->setFramebufferResized(true); app->setFramebufferResized(true);
} }
// Initialize GLFW Window. First, Initialize GLFW lib, disable resizing for
// now, and create window. // Initialize GLFW Window. First, Initialize GLFW lib, disable resizing for
// now, and create window.
void initWindow() { void initWindow() {
glfwInit(); glfwInit();
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
@ -33,7 +26,7 @@ void initWindow() {
} }
void createInstance() { void createInstance() {
debugController.checkUnavailableValidationLayers(); // Check if there is a mistake with our Validation Layers. debug_libs::Debug::checkUnavailableValidationLayers(); // Check if there is a mistake with our Validation Layers.
// Set application info for the vulkan instance! // Set application info for the vulkan instance!
VkApplicationInfo appInfo{}; VkApplicationInfo appInfo{};
@ -49,67 +42,69 @@ void createInstance() {
createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; // Tell vulkan this is a info structure 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. 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!) debug_libs::Debug::vulkanDebugSetup(createInfo, vulkaninstance); // Handoff to the debug library to wrap the validation libs in! (And set the window up!)
} }
void initVulkan() { void initVulkan() {
// Initialize vulkan and set up pipeline.
createInstance(); createInstance();
debugController.setupDebugMessenger(vulkaninstance); // The debug messenger is out holy grail, it gives us Vulkan related debug info when built with the -DDEBUG flag (as per the makefile) debug_libs::Debug::setupDebugMessenger(vulkaninstance);
deviceLibs.createSurface(vulkaninstance, Global::window); device_libs::DeviceControl::createSurface(vulkaninstance, Global::window);
deviceLibs.pickPhysicalDevice(vulkaninstance); device_libs::DeviceControl::pickPhysicalDevice(vulkaninstance);
deviceLibs.createLogicalDevice(); device_libs::DeviceControl::createLogicalDevice();
deviceLibs.createSwapChain(Global::window); device_libs::DeviceControl::createSwapChain(Global::window);
deviceLibs.createImageViews(); device_libs::DeviceControl::createImageViews();
graphicsPipeline.createRenderPass(); graphics_pipeline::Graphics::createRenderPass();
buffers.createDescriptorSetLayout(); buffers_libs::Buffers::createDescriptorSetLayout();
graphicsPipeline.createGraphicsPipeline(); graphics_pipeline::Graphics::createGraphicsPipeline();
graphicsPipeline.createCommandPool(); graphics_pipeline::Graphics::createCommandPool();
texture.createDepthResources(); texture_libs::Texture::createDepthResources();
graphicsPipeline.createFramebuffers(); graphics_pipeline::Graphics::createFramebuffers();
texture.createTextureImage(); texture_libs::Texture::createTextureImage();
texture.createTextureImageView(); texture_libs::Texture::createTextureImageView();
texture.createTextureSampler(); texture_libs::Texture::createTextureSampler();
model.loadModel(); modellib::Model::loadModel();
buffers.createVertexBuffer(); buffers_libs::Buffers::createVertexBuffer();
buffers.createIndexBuffer(); buffers_libs::Buffers::createIndexBuffer();
buffers.createUniformBuffers(); buffers_libs::Buffers::createUniformBuffers();
buffers.createDescriptorPool(); buffers_libs::Buffers::createDescriptorPool();
buffers.createDescriptorSets(); buffers_libs::Buffers::createDescriptorSets();
graphicsPipeline.createCommandBuffer(); graphics_pipeline::Graphics::createCommandBuffer();
renderPresentation.createSyncObject(); render_present::Render::createSyncObject();
} }
void mainLoop() { // This loop just updates the GLFW window. void mainLoop() {
while (!glfwWindowShouldClose(Global::window)) { while (!glfwWindowShouldClose(Global::window)) {
glfwPollEvents(); glfwPollEvents();
renderPresentation.drawFrame(); render_present::Render::drawFrame();
} }
vkDeviceWaitIdle(Global::device); vkDeviceWaitIdle(Global::device);
} }
void cleanup() { // Similar to the last handoff, destroy the utils in a safe manner in the library! void cleanup() {
renderPresentation.cleanupSwapChain(); render_present::Render::cleanupSwapChain();
texture.createTextureSampler(); texture_libs::Texture::createTextureSampler();
texture.destroyTextureImage(); texture_libs::Texture::destroyTextureImage();
buffers.destroyUniformBuffer(); buffers_libs::Buffers::destroyUniformBuffer();
buffers.destroyDescriptorPool(); buffers_libs::Buffers::destroyDescriptorPool();
vkDestroyDescriptorSetLayout(Global::device, Global::descriptorSetLayout, nullptr); vkDestroyDescriptorSetLayout(Global::device, Global::descriptorSetLayout, nullptr);
graphicsPipeline.destroyGraphicsPipeline(); graphics_pipeline::Graphics::destroyGraphicsPipeline();
graphicsPipeline.destroyRenderPass(); graphics_pipeline::Graphics::destroyRenderPass();
buffers.destroyBuffers(); buffers_libs::Buffers::destroyBuffers();
renderPresentation.destroyFenceSemaphores(); render_present::Render::destroyFenceSemaphores();
graphicsPipeline.destroyCommandPool(); graphics_pipeline::Graphics::destroyCommandPool();
vkDestroyDevice(Global::device, nullptr); vkDestroyDevice(Global::device, nullptr);
if(Global::enableValidationLayers) { if(Global::enableValidationLayers) {
debugController.DestroyDebugUtilsMessengerEXT(vulkaninstance, nullptr); debug_libs::Debug::DestroyDebugUtilsMessengerEXT(vulkaninstance, nullptr);
} }
deviceLibs.destroySurface(vulkaninstance); device_libs::DeviceControl::destroySurface(vulkaninstance);
vkDestroyInstance(vulkaninstance, nullptr); vkDestroyInstance(vulkaninstance, nullptr);
glfwDestroyWindow(Global::window); glfwDestroyWindow(Global::window);
glfwTerminate(); glfwTerminate();
} }
// External Functions // External Functions
EntryApp& EntryApp::getInstance() { EntryApp& EntryApp::getInstance() {
static EntryApp instance; static EntryApp instance;

View File

@ -1,11 +1,10 @@
#include <cstdlib>
#include "devicelibrary.h" // Device Library includes global, redundant to include with it here
#include "debug/vulkandebuglibs.h" #include "debug/vulkandebuglibs.h"
#include "graphics/graphicspipeline.h" #include "graphics/graphicspipeline.h"
#include "graphics/render.h" #include "graphics/render.h"
#include "graphics/texture.h"
#include "global.h" #include "global.h"
#include "graphics/model.h" #include "graphics/model.h"
#include "graphics/texture.h"
class EntryApp { class EntryApp {
public: public:
static EntryApp& getInstance(); static EntryApp& getInstance();

View File

@ -1,6 +1,5 @@
#include "global.h" #include "global.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 = {
@ -33,13 +32,13 @@ namespace Global {
std::vector<Vertex> vertices; std::vector<Vertex> vertices;
// Index buffer definition, showing which points to reuse. // Index buffer definition, showing which points to reuse.
std::vector<uint32_t> indices; std::vector<uint32_t> indices;
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.
// Next, we check the flags of the queueFamily item, use a bitwise and to see if they match, i.e. support graphical operations, then return that to notify that we have at least one family that supports VK_QUEUE_GRAPHICS_BIT. // Next, we check the flags of the queueFamily item, use a bitwise and to see if they match, i.e. support graphical operations, then return that to notify that we have at least one family that supports VK_QUEUE_GRAPHICS_BIT.
// Which means this device supports graphical operations! // Which means this device supports graphical operations!
// We also do the same thing for window presentation, just check to see if its supported. // We also do the same thing for window presentation, just check to see if its supported.
DeviceControl::devicelibrary deviceLibs;
Global::QueueFamilyIndices indices; Global::QueueFamilyIndices indices;
uint32_t queueFamilyCount = 0; uint32_t queueFamilyCount = 0;
@ -67,5 +66,4 @@ namespace Global {
} }
return indices; return indices;
} }
} }

View File

@ -1,24 +1,27 @@
#pragma once #pragma once
#include "graphics/texture.h" #include <vulkan/vulkan_core.h>
#include <cstdint>
#define GLM_FORCE_DEPTH_ZERO_TO_ONE
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/detail/qualifier.hpp> #include <glm/detail/qualifier.hpp>
#include <glm/ext/vector_float2.hpp> #include <glm/ext/vector_float2.hpp>
#include <glm/ext/vector_float3.hpp> #include <glm/ext/vector_float3.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/fwd.hpp> #include <glm/fwd.hpp>
#define GLFW_INCLUDE_VULKAN
#include <GLFW/glfw3.h>
#include <cstdint>
#include <iostream> #include <iostream>
#include <ostream> #include <ostream>
#include <vector> #include <vector>
#include <optional> #include <optional>
#include <vulkan/vulkan_core.h>
#include <glm/gtc/matrix_transform.hpp>
#include <array> #include <array>
#define GLM_FORCE_DEPTH_ZERO_TO_ONE
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#define GLFW_INCLUDE_VULKAN
#include <GLFW/glfw3.h>
namespace Global { namespace Global {
// Global variables and includes we are going to use almost everywhere, validation layers hook into everything, and you need to check if they are enabled first, // Global variables and includes we are going to use almost everywhere, validation layers hook into everything, and you need to check if they are enabled first,

View File

@ -1,25 +1,17 @@
#include "buffers.h" #include "buffers.h"
#include <chrono>
#include <cstring>
#include "../devicelibrary.h"
VkBuffer vertexBuffer; VkBuffer vertexBuffer;
VkDeviceMemory vertexBufferMemory; VkDeviceMemory vertexBufferMemory;
VkBuffer indexBuffer; VkBuffer indexBuffer;
VkDeviceMemory indexBufferMemory; VkDeviceMemory indexBufferMemory;
VkDescriptorPool descriptorPool; VkDescriptorPool descriptorPool;
DeviceControl::devicelibrary deviceLibrary;
std::vector<VkBuffer> uniformBuffers; std::vector<VkBuffer> uniformBuffers;
std::vector<VkDeviceMemory> uniformBuffersMemory; std::vector<VkDeviceMemory> uniformBuffersMemory;
std::vector<void*> uniformBuffersMapped; std::vector<void*> uniformBuffersMapped;
namespace buffers_libs {
namespace BuffersLibraries { uint32_t Buffers::findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties) {
uint32_t buffers::findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties) {
// Graphics cards offer different types of memory to allocate from, here we query to find the right type of memory for our needs. // Graphics cards offer different types of memory to allocate from, here we query to find the right type of memory for our needs.
// Query the available types of memory to iterate over. // Query the available types of memory to iterate over.
VkPhysicalDeviceMemoryProperties memProperties; VkPhysicalDeviceMemoryProperties memProperties;
@ -66,7 +58,7 @@ namespace BuffersLibraries {
vkFreeCommandBuffers(Global::device, Global::commandPool, 1, &commandBuffer); vkFreeCommandBuffers(Global::device, Global::commandPool, 1, &commandBuffer);
} }
void buffers::createBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VkBuffer& buffer, VkDeviceMemory& bufferMemory) { void Buffers::createBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VkBuffer& buffer, VkDeviceMemory& bufferMemory) {
VkBufferCreateInfo bufferInfo{}; VkBufferCreateInfo bufferInfo{};
bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
bufferInfo.size = size; bufferInfo.size = size;
@ -92,7 +84,7 @@ namespace BuffersLibraries {
vkBindBufferMemory(Global::device, buffer, bufferMemory, 0); vkBindBufferMemory(Global::device, buffer, bufferMemory, 0);
} }
void buffers::createIndexBuffer() { void Buffers::createIndexBuffer() {
VkDeviceSize bufferSize = sizeof(Global::indices[0]) * Global::indices.size(); VkDeviceSize bufferSize = sizeof(Global::indices[0]) * Global::indices.size();
VkBuffer stagingBuffer; VkBuffer stagingBuffer;
@ -113,7 +105,7 @@ namespace BuffersLibraries {
vkDestroyBuffer(Global::device, stagingBuffer, nullptr); vkDestroyBuffer(Global::device, stagingBuffer, nullptr);
vkFreeMemory(Global::device, stagingBufferMemory, nullptr); vkFreeMemory(Global::device, stagingBufferMemory, nullptr);
} }
void buffers::createVertexBuffer() { void Buffers::createVertexBuffer() {
// Create a Vertex Buffer to hold the vertex information in memory so it doesn't have to be hardcoded! // Create a Vertex Buffer to hold the vertex information in memory so it doesn't have to be hardcoded!
// Size denotes the size of the buffer in bytes, usage in this case is the buffer behaviour, using a bitwise OR. // Size denotes the size of the buffer in bytes, usage in this case is the buffer behaviour, using a bitwise OR.
// Sharing mode denostes the same as the images in the swap chain! in this case, only the graphics queue uses this buffer, so we make it exclusive. // Sharing mode denostes the same as the images in the swap chain! in this case, only the graphics queue uses this buffer, so we make it exclusive.
@ -136,22 +128,22 @@ namespace BuffersLibraries {
vkFreeMemory(Global::device, stagingBufferMemory, nullptr); vkFreeMemory(Global::device, stagingBufferMemory, nullptr);
} }
void buffers::destroyBuffers() { void Buffers::destroyBuffers() {
vkDestroyBuffer(Global::device, indexBuffer, nullptr); vkDestroyBuffer(Global::device, indexBuffer, nullptr);
vkFreeMemory(Global::device, indexBufferMemory, nullptr); vkFreeMemory(Global::device, indexBufferMemory, nullptr);
vkDestroyBuffer(Global::device, vertexBuffer, nullptr); vkDestroyBuffer(Global::device, vertexBuffer, nullptr);
vkFreeMemory(Global::device, vertexBufferMemory, nullptr); vkFreeMemory(Global::device, vertexBufferMemory, nullptr);
} }
VkBuffer buffers::getVertexBuffer() { VkBuffer Buffers::getVertexBuffer() {
return vertexBuffer; return vertexBuffer;
} }
VkBuffer buffers::getIndexBuffer() { VkBuffer Buffers::getIndexBuffer() {
return indexBuffer; return indexBuffer;
} }
// ------------------------------ Uniform Buffer Setup -------------------------------- // // ------------------------------ Uniform Buffer Setup -------------------------------- //
void buffers::createDescriptorSetLayout() { void Buffers::createDescriptorSetLayout() {
// Create a table of pointers to data, a Descriptor Set! // Create a table of pointers to data, a Descriptor Set!
// --------------------- UBO Layout --------------------- // // --------------------- UBO Layout --------------------- //
VkDescriptorSetLayoutBinding uboLayoutBinding{}; VkDescriptorSetLayoutBinding uboLayoutBinding{};
@ -182,7 +174,7 @@ namespace BuffersLibraries {
throw std::runtime_error("Failed to create descriptor set layout!"); throw std::runtime_error("Failed to create descriptor set layout!");
} }
} }
void buffers::createUniformBuffers() { void Buffers::createUniformBuffers() {
// Map the uniform buffer to memory as a pointer we can use to write data to later. This stays mapped to memory for the applications lifetime. // Map the uniform buffer to memory as a pointer we can use to write data to later. This stays mapped to memory for the applications lifetime.
// This technique is called "persistent mapping", not having to map the buffer every time we need to update it increases performance, though not free // This technique is called "persistent mapping", not having to map the buffer every time we need to update it increases performance, though not free
VkDeviceSize bufferSize = sizeof(Global::UniformBufferObject); VkDeviceSize bufferSize = sizeof(Global::UniformBufferObject);
@ -196,7 +188,7 @@ namespace BuffersLibraries {
vkMapMemory(Global::device, uniformBuffersMemory[i], 0, bufferSize, 0, &uniformBuffersMapped[i]); vkMapMemory(Global::device, uniformBuffersMemory[i], 0, bufferSize, 0, &uniformBuffersMapped[i]);
} }
} }
void buffers::updateUniformBuffer(uint32_t currentImage) { void Buffers::updateUniformBuffer(uint32_t currentImage) {
// Update the uniform buffer every frame to change the position, but notably, use chrono to know exactly how much to move // Update the uniform buffer every frame to change the position, but notably, use chrono to know exactly how much to move
// so we aren't locked to the framerate as the world time. // so we aren't locked to the framerate as the world time.
@ -208,25 +200,25 @@ namespace BuffersLibraries {
Global::UniformBufferObject ubo{}; Global::UniformBufferObject ubo{};
ubo.time = time; ubo.time = time;
// Modify the model projection transformation to rotate around the Z over time. // Modify the model projection transformation to rotate around the Z over time.
ubo.model = glm::rotate(glm::mat4(1.0f), glm::radians(180.0f), glm::vec3(0.0f, 0.0f, 1.0f)); ubo.model = glm::rotate(glm::mat4(1.0f), glm::radians(30.0f), glm::vec3(0.0f, 0.0f, 1.0f));
// Modify the view transformation to look at the object from above at a 45 degree angle. // Modify the view transformation to look at the object from above at a 45 degree angle.
// This takes the eye position, center position, and the up direction. // This takes the eye position, center position, and the up direction.
ubo.view = glm::lookAt(glm::vec3(4.0f, 4.0f, 3.0f), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 0.0f, 1.0f)); ubo.view = glm::lookAt(glm::vec3(2.0f, 2.0f, 2.0f), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 0.0f, 1.0f));
// 45 degree field of view, set aspect ratio, and near and far clipping range. // 45 degree field of view, set aspect ratio, and near and far clipping range.
ubo.proj = glm::perspective(glm::radians(45.0f), deviceLibrary.getSwapChainExtent().width / (float) deviceLibrary.getSwapChainExtent().height, 0.1f, 10.0f); ubo.proj = glm::perspective(glm::radians(45.0f), device_libs::DeviceControl::getSwapChainExtent().width / (float) device_libs::DeviceControl::getSwapChainExtent().height, 0.1f, 10.0f);
// GLM was created for OpenGL, where the Y coordinate was inverted. This simply flips the sign. // GLM was created for OpenGL, where the Y coordinate was inverted. This simply flips the sign.
ubo.proj[1][1] *= -1; ubo.proj[1][1] *= -1;
memcpy(uniformBuffersMapped[currentImage], &ubo, sizeof(ubo)); memcpy(uniformBuffersMapped[currentImage], &ubo, sizeof(ubo));
} }
void buffers::destroyUniformBuffer() { void Buffers::destroyUniformBuffer() {
for(size_t i = 0; i < Global::MAX_FRAMES_IN_FLIGHT; i++) { for(size_t i = 0; i < Global::MAX_FRAMES_IN_FLIGHT; i++) {
vkDestroyBuffer(Global::device, uniformBuffers[i],nullptr); vkDestroyBuffer(Global::device, uniformBuffers[i],nullptr);
vkFreeMemory(Global::device, uniformBuffersMemory[i], nullptr); vkFreeMemory(Global::device, uniformBuffersMemory[i], nullptr);
} }
} }
void buffers::createDescriptorPool() { void Buffers::createDescriptorPool() {
// Create a pool to be used to allocate descriptor sets. // Create a pool to be used to allocate descriptor sets.
std::array<VkDescriptorPoolSize, 2> poolSizes{}; std::array<VkDescriptorPoolSize, 2> poolSizes{};
poolSizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; poolSizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
@ -244,7 +236,7 @@ namespace BuffersLibraries {
throw std::runtime_error("failed to create descriptor pool!"); throw std::runtime_error("failed to create descriptor pool!");
} }
} }
void buffers::createDescriptorSets() { void Buffers::createDescriptorSets() {
std::vector<VkDescriptorSetLayout> layouts(Global::MAX_FRAMES_IN_FLIGHT, Global::descriptorSetLayout); std::vector<VkDescriptorSetLayout> layouts(Global::MAX_FRAMES_IN_FLIGHT, Global::descriptorSetLayout);
VkDescriptorSetAllocateInfo allocInfo{}; VkDescriptorSetAllocateInfo allocInfo{};
allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
@ -289,7 +281,7 @@ namespace BuffersLibraries {
vkUpdateDescriptorSets(Global::device, static_cast<uint32_t>(descriptorWrites.size()), descriptorWrites.data(), 0, nullptr); vkUpdateDescriptorSets(Global::device, static_cast<uint32_t>(descriptorWrites.size()), descriptorWrites.data(), 0, nullptr);
} }
} }
void buffers::destroyDescriptorPool() { void Buffers::destroyDescriptorPool() {
vkDestroyDescriptorPool(Global::device, descriptorPool, nullptr); vkDestroyDescriptorPool(Global::device, descriptorPool, nullptr);
} }
} }

View File

@ -1,22 +1,24 @@
#pragma once #pragma once
#include "../global.h" #include <chrono>
#include <cstring>
#include "../devicelibrary.h"
namespace BuffersLibraries { namespace buffers_libs {
class buffers { class Buffers {
public: public:
void createBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags props, VkBuffer& buffer, VkDeviceMemory& bufferMemory); static void createBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags props, VkBuffer& buffer, VkDeviceMemory& bufferMemory);
uint32_t findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags flags); static uint32_t findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags flags);
void createIndexBuffer(); static void createIndexBuffer();
void createVertexBuffer(); static void createVertexBuffer();
void destroyBuffers(); static void destroyBuffers();
VkBuffer getVertexBuffer(); static VkBuffer getVertexBuffer();
VkBuffer getIndexBuffer(); static VkBuffer getIndexBuffer();
void createDescriptorSetLayout(); static void createDescriptorSetLayout();
void createUniformBuffers(); static void createUniformBuffers();
void updateUniformBuffer(uint32_t currentImage); static void updateUniformBuffer(uint32_t currentImage);
void destroyUniformBuffer(); static void destroyUniformBuffer();
void createDescriptorPool(); static void createDescriptorPool();
void createDescriptorSets(); static void createDescriptorSets();
void destroyDescriptorPool(); static void destroyDescriptorPool();
}; };
} }

View File

@ -1,23 +1,15 @@
#include "graphicspipeline.h" #include "graphicspipeline.h"
#include "buffers.h"
#include "texture.h" namespace graphics_pipeline {
#include <cstdint>
#include <vector>
#include <vulkan/vulkan_core.h>
namespace Graphics {
std::vector<VkDynamicState> dynamicStates = { std::vector<VkDynamicState> dynamicStates = {
VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_VIEWPORT,
VK_DYNAMIC_STATE_SCISSOR VK_DYNAMIC_STATE_SCISSOR
}; };
VkRenderPass renderPass; VkRenderPass renderPass;
VkPipelineLayout pipelineLayout; VkPipelineLayout pipelineLayout;
VkPipeline graphicsPipeline; VkPipeline graphicsPipeline;
DeviceControl::devicelibrary deviceLibs;
BuffersLibraries::buffers buffers;
TextureLibraries::texture textureLibs;
std::vector<VkFramebuffer> swapChainFramebuffers; std::vector<VkFramebuffer> swapChainFramebuffers;
@ -50,7 +42,7 @@ namespace Graphics {
return shaderModule; return shaderModule;
} }
void graphicspipeline::destroyGraphicsPipeline() { void Graphics::destroyGraphicsPipeline() {
vkDestroyPipeline(Global::device, graphicsPipeline, nullptr); vkDestroyPipeline(Global::device, graphicsPipeline, nullptr);
if(Global::enableValidationLayers) std::cout << "Destroyed Graphics Pipeline safely\n" << std::endl; if(Global::enableValidationLayers) std::cout << "Destroyed Graphics Pipeline safely\n" << std::endl;
vkDestroyPipelineLayout(Global::device, pipelineLayout, nullptr); vkDestroyPipelineLayout(Global::device, pipelineLayout, nullptr);
@ -58,13 +50,12 @@ namespace Graphics {
} }
void graphicspipeline::createGraphicsPipeline() { void Graphics::createGraphicsPipeline() {
// Note to self, for some reason the working directory is not where a read file is called from, but the project folder! // Note to self, for some reason the working directory is not where a read file is called from, but the project folder!
auto vertShaderCode = readFile("src/shaders/vertex.spv"); auto vertShaderCode = readFile("src/shaders/vertex.spv");
auto fragShaderCode = readFile("src/shaders/fragment.spv"); auto fragShaderCode = readFile("src/shaders/fragment.spv");
VkShaderModule vertShaderModule = createShaderModule(vertShaderCode, Global::device); VkShaderModule vertShaderModule = createShaderModule(vertShaderCode, Global::device);
VkShaderModule fragShaderModule = createShaderModule(fragShaderCode, Global::device); VkShaderModule fragShaderModule = createShaderModule(fragShaderCode, Global::device);
// ------------------ STAGE 1 - INPUT ASSEMBLER ---------------- // // ------------------ STAGE 1 - INPUT ASSEMBLER ---------------- //
// This can get a little complicated, normally, vertices are loaded in sequential order, with an element buffer however, you can specify the indices yourself! // This can get a little complicated, normally, vertices are loaded in sequential order, with an element buffer however, you can specify the indices yourself!
// Using an element buffer means you can reuse vertices, which can lead to optimizations. If you set PrimRestart to TRUE, you can utilize the _STRIP modes with special indices // Using an element buffer means you can reuse vertices, which can lead to optimizations. If you set PrimRestart to TRUE, you can utilize the _STRIP modes with special indices
@ -191,9 +182,9 @@ namespace Graphics {
if(Global::enableValidationLayers) std::cout << "Pipeline Layout created successfully\n" << std::endl; if(Global::enableValidationLayers) std::cout << "Pipeline Layout created successfully\n" << std::endl;
} }
void graphicspipeline::createRenderPass() { void Graphics::createRenderPass() {
VkAttachmentDescription colorAttachment{}; VkAttachmentDescription colorAttachment{};
colorAttachment.format = deviceLibs.getImageFormat(); colorAttachment.format = device_libs::DeviceControl::getImageFormat();
colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT; colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT;
colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
@ -207,7 +198,7 @@ namespace Graphics {
colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
VkAttachmentDescription depthAttachment{}; VkAttachmentDescription depthAttachment{};
depthAttachment.format = textureLibs.findDepthFormat(); depthAttachment.format = texture_libs::Texture::findDepthFormat();
depthAttachment.samples = VK_SAMPLE_COUNT_1_BIT; depthAttachment.samples = VK_SAMPLE_COUNT_1_BIT;
depthAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; depthAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
depthAttachment.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; depthAttachment.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
@ -250,18 +241,18 @@ namespace Graphics {
} }
if(Global::enableValidationLayers) std::cout << "Render pass created successfully\n" << std::endl; if(Global::enableValidationLayers) std::cout << "Render pass created successfully\n" << std::endl;
} }
void graphicspipeline::destroyRenderPass() { void Graphics::destroyRenderPass() {
vkDestroyRenderPass(Global::device, renderPass, nullptr); vkDestroyRenderPass(Global::device, renderPass, nullptr);
if(Global::enableValidationLayers) std::cout << "Destroyed Render Pass Safely\n" << std::endl; if(Global::enableValidationLayers) std::cout << "Destroyed Render Pass Safely\n" << std::endl;
} }
void graphicspipeline::createFramebuffers() { void Graphics::createFramebuffers() {
// Resize the container to hold all the framebuffers. // Resize the container to hold all the framebuffers.
int framebuffersSize = deviceLibs.getSwapChainImageViews().size(); int framebuffersSize = device_libs::DeviceControl::getSwapChainImageViews().size();
swapChainFramebuffers.resize(framebuffersSize); swapChainFramebuffers.resize(framebuffersSize);
for(size_t i = 0; i < framebuffersSize; i++) { for(size_t i = 0; i < framebuffersSize; i++) {
std::array<VkImageView, 2> attachments = { std::array<VkImageView, 2> attachments = {
deviceLibs.getSwapChainImageViews()[i], device_libs::DeviceControl::getSwapChainImageViews()[i],
Global::depthImageView Global::depthImageView
}; };
@ -270,8 +261,8 @@ namespace Graphics {
framebufferInfo.renderPass = renderPass; framebufferInfo.renderPass = renderPass;
framebufferInfo.attachmentCount = static_cast<uint32_t>(attachments.size()); framebufferInfo.attachmentCount = static_cast<uint32_t>(attachments.size());
framebufferInfo.pAttachments = attachments.data(); framebufferInfo.pAttachments = attachments.data();
framebufferInfo.width = deviceLibs.getSwapChainExtent().width; framebufferInfo.width = device_libs::DeviceControl::getSwapChainExtent().width;
framebufferInfo.height = deviceLibs.getSwapChainExtent().height; framebufferInfo.height = device_libs::DeviceControl::getSwapChainExtent().height;
framebufferInfo.layers = 1; framebufferInfo.layers = 1;
if(vkCreateFramebuffer(Global::device, &framebufferInfo, nullptr, &swapChainFramebuffers[i]) != VK_SUCCESS) { if(vkCreateFramebuffer(Global::device, &framebufferInfo, nullptr, &swapChainFramebuffers[i]) != VK_SUCCESS) {
@ -279,7 +270,7 @@ namespace Graphics {
} }
} }
} }
void graphicspipeline::createCommandPool() { void Graphics::createCommandPool() {
// Commands in Vulkan are not executed using function calls, you have to record the ops you wish to perform // Commands in Vulkan are not executed using function calls, you have to record the ops you wish to perform
// to command buffers, pools manage the memory used by the buffer! // to command buffers, pools manage the memory used by the buffer!
Global::QueueFamilyIndices queueFamilyIndices = Global::findQueueFamilies(Global::physicalDevice); Global::QueueFamilyIndices queueFamilyIndices = Global::findQueueFamilies(Global::physicalDevice);
@ -294,10 +285,10 @@ namespace Graphics {
} }
if(Global::enableValidationLayers) std::cout << "Command pool created successfully\n" << std::endl; if(Global::enableValidationLayers) std::cout << "Command pool created successfully\n" << std::endl;
} }
void graphicspipeline::destroyCommandPool() { void Graphics::destroyCommandPool() {
vkDestroyCommandPool(Global::device, Global::commandPool, nullptr); vkDestroyCommandPool(Global::device, Global::commandPool, nullptr);
} }
void graphicspipeline::createCommandBuffer() { void Graphics::createCommandBuffer() {
Global::commandBuffers.resize(Global::MAX_FRAMES_IN_FLIGHT); Global::commandBuffers.resize(Global::MAX_FRAMES_IN_FLIGHT);
VkCommandBufferAllocateInfo allocInfo{}; VkCommandBufferAllocateInfo allocInfo{};
@ -312,7 +303,7 @@ namespace Graphics {
if(Global::enableValidationLayers) std::cout << "Allocated command buffers successfully\n" << std::endl; if(Global::enableValidationLayers) std::cout << "Allocated command buffers successfully\n" << std::endl;
} }
void graphicspipeline::recordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t imageIndex) { void Graphics::recordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t imageIndex) {
VkCommandBufferBeginInfo beginInfo{}; VkCommandBufferBeginInfo beginInfo{};
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
@ -325,7 +316,7 @@ namespace Graphics {
renderPassInfo.renderPass = renderPass; renderPassInfo.renderPass = renderPass;
renderPassInfo.framebuffer = swapChainFramebuffers[imageIndex]; renderPassInfo.framebuffer = swapChainFramebuffers[imageIndex];
renderPassInfo.renderArea.offset = {0, 0}; renderPassInfo.renderArea.offset = {0, 0};
renderPassInfo.renderArea.extent = deviceLibs.getSwapChainExtent(); renderPassInfo.renderArea.extent = device_libs::DeviceControl::getSwapChainExtent();
std::array<VkClearValue, 2> clearValues{}; std::array<VkClearValue, 2> clearValues{};
clearValues[0].color = {{0.0f, 0.0f, 0.0f, 1.0f}}; clearValues[0].color = {{0.0f, 0.0f, 0.0f, 1.0f}};
@ -340,21 +331,21 @@ namespace Graphics {
VkViewport viewport{}; VkViewport viewport{};
viewport.x = 0.0f; viewport.x = 0.0f;
viewport.y = 0.0f; viewport.y = 0.0f;
viewport.width = (float) deviceLibs.getSwapChainExtent().width; viewport.width = (float) device_libs::DeviceControl::getSwapChainExtent().width;
viewport.height = (float) deviceLibs.getSwapChainExtent().height; viewport.height = (float) device_libs::DeviceControl::getSwapChainExtent().height;
viewport.minDepth = 0.0f; viewport.minDepth = 0.0f;
viewport.maxDepth = 1.0f; viewport.maxDepth = 1.0f;
vkCmdSetViewport(commandBuffer, 0, 1, &viewport); vkCmdSetViewport(commandBuffer, 0, 1, &viewport);
VkRect2D scissor{}; VkRect2D scissor{};
scissor.offset = {0, 0}; scissor.offset = {0, 0};
scissor.extent = deviceLibs.getSwapChainExtent(); scissor.extent = device_libs::DeviceControl::getSwapChainExtent();
vkCmdSetScissor(commandBuffer, 0, 1, &scissor); vkCmdSetScissor(commandBuffer, 0, 1, &scissor);
VkBuffer vertexBuffers[] = {buffers.getVertexBuffer()}; VkBuffer vertexBuffers[] = {buffers_libs::Buffers::getVertexBuffer()};
VkDeviceSize offsets[] = {0}; VkDeviceSize offsets[] = {0};
vkCmdBindVertexBuffers(commandBuffer, 0, 1, vertexBuffers, offsets); vkCmdBindVertexBuffers(commandBuffer, 0, 1, vertexBuffers, offsets);
vkCmdBindIndexBuffer(commandBuffer, buffers.getIndexBuffer(), 0, VK_INDEX_TYPE_UINT32); vkCmdBindIndexBuffer(commandBuffer, buffers_libs::Buffers::getIndexBuffer(), 0, VK_INDEX_TYPE_UINT32);
vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &Global::descriptorSets[Global::currentFrame], 0, nullptr); vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &Global::descriptorSets[Global::currentFrame], 0, nullptr);
@ -365,7 +356,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() { std::vector<VkFramebuffer> Graphics::getSwapChainFramebuffers() {
return swapChainFramebuffers; return swapChainFramebuffers;
} }
} }

View File

@ -2,20 +2,22 @@
#include "../global.h" #include "../global.h"
#include "../devicelibrary.h" #include "../devicelibrary.h"
#include "buffers.h" #include "buffers.h"
#include "texture.h"
#include <fstream> #include <fstream>
namespace Graphics {
class graphicspipeline { namespace graphics_pipeline {
class Graphics {
public: public:
void createGraphicsPipeline(); static void createGraphicsPipeline();
void destroyGraphicsPipeline(); static void destroyGraphicsPipeline();
void createRenderPass(); static void createRenderPass();
void destroyRenderPass(); static void destroyRenderPass();
void createFramebuffers(); static void createFramebuffers();
void destroyFramebuffers(); static void destroyFramebuffers();
void createCommandPool(); static void createCommandPool();
void destroyCommandPool(); static void destroyCommandPool();
void createCommandBuffer(); static void createCommandBuffer();
void recordCommandBuffer(VkCommandBuffer cmndBuffer, uint32_t imageIndex); static void recordCommandBuffer(VkCommandBuffer cmndBuffer, uint32_t imageIndex);
std::vector<VkFramebuffer> getSwapChainFramebuffers(); static std::vector<VkFramebuffer> getSwapChainFramebuffers();
}; };
} }

View File

@ -1,9 +1,4 @@
#define TINY_OBJ_IMPLEMENTATION
#include <tiny_obj_loader.h>
#include "model.h" #include "model.h"
#include <unordered_map>
#define GLM_ENABLE_EXPERIMENTAL
#include <glm/gtx/hash.hpp>
namespace std { namespace std {
template<> struct hash<Global::Vertex> { template<> struct hash<Global::Vertex> {
@ -15,11 +10,11 @@ namespace std {
}; };
} }
namespace ModelLib { namespace modellib {
std::unordered_map<Global::Vertex, uint32_t> uniqueVertices{}; std::unordered_map<Global::Vertex, uint32_t> uniqueVertices{};
void model::loadModel() { void Model::loadModel() {
tinyobj::ObjReaderConfig readerConfig; tinyobj::ObjReaderConfig readerConfig;
tinyobj::ObjReader reader; tinyobj::ObjReader reader;

View File

@ -1,8 +1,14 @@
#include "../global.h" #include "../global.h"
namespace ModelLib { #define TINY_OBJ_IMPLEMENTATION
class model { #include <tiny_obj_loader.h>
#define GLM_ENABLE_EXPERIMENTAL
#include <glm/gtx/hash.hpp>
namespace modellib {
class Model {
public: public:
void loadModel(); static void loadModel();
}; };
} }

View File

@ -3,16 +3,11 @@
#include "../devicelibrary.h" #include "../devicelibrary.h"
#include "../entrypoint.h" #include "../entrypoint.h"
#include "texture.h" #include "texture.h"
#include <vulkan/vulkan_core.h> namespace render_present {
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;
DeviceControl::devicelibrary deviceLibs;
BuffersLibraries::buffers buffers;
TextureLibraries::texture tex;
void recreateSwapChain() { void recreateSwapChain() {
int width = 0, height = 0; int width = 0, height = 0;
@ -23,24 +18,24 @@ namespace RenderPresent {
} }
vkDeviceWaitIdle(Global::device); 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. // 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()) { for(auto framebuffer : graphics_pipeline::Graphics::getSwapChainFramebuffers()) {
vkDestroyFramebuffer(Global::device, framebuffer, nullptr); vkDestroyFramebuffer(Global::device, framebuffer, nullptr);
} }
for(auto imageView : deviceLibs.getSwapChainImageViews()) { for(auto imageView : device_libs::DeviceControl::getSwapChainImageViews()) {
vkDestroyImageView(Global::device, imageView, nullptr); vkDestroyImageView(Global::device, imageView, nullptr);
} }
vkDestroySwapchainKHR(Global::device, Global::swapChain, nullptr); vkDestroySwapchainKHR(Global::device, Global::swapChain, nullptr);
deviceLibs.createSwapChain(Global::window); device_libs::DeviceControl::createSwapChain(Global::window);
deviceLibs.createImageViews(); device_libs::DeviceControl::createImageViews();
tex.createDepthResources(); texture_libs::Texture::createDepthResources();
pipeline.createFramebuffers(); graphics_pipeline::Graphics::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
// submit the recorded command buffer and present the image! // submit the recorded command buffer and present the image!
void render::drawFrame() { void Render::drawFrame() {
vkWaitForFences(Global::device, 1, &inFlightFences[Global::currentFrame], VK_TRUE, UINT64_MAX); vkWaitForFences(Global::device, 1, &inFlightFences[Global::currentFrame], VK_TRUE, UINT64_MAX);
vkResetFences(Global::device, 1, &inFlightFences[Global::currentFrame]); vkResetFences(Global::device, 1, &inFlightFences[Global::currentFrame]);
@ -54,12 +49,12 @@ namespace RenderPresent {
throw std::runtime_error("failed to acquire swap chain image!"); throw std::runtime_error("failed to acquire swap chain image!");
} }
buffers.updateUniformBuffer(Global::currentFrame); buffers_libs::Buffers::updateUniformBuffer(Global::currentFrame);
vkResetFences(Global::device, 1, &inFlightFences[Global::currentFrame]); vkResetFences(Global::device, 1, &inFlightFences[Global::currentFrame]);
vkResetCommandBuffer(Global::commandBuffers[Global::currentFrame], /*VkCommandBufferResetFlagBits*/ 0); vkResetCommandBuffer(Global::commandBuffers[Global::currentFrame], /*VkCommandBufferResetFlagBits*/ 0);
pipeline.recordCommandBuffer(Global::commandBuffers[Global::currentFrame], imageIndex); graphics_pipeline::Graphics::recordCommandBuffer(Global::commandBuffers[Global::currentFrame], imageIndex);
VkSubmitInfo submitInfo{}; VkSubmitInfo submitInfo{};
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
@ -127,7 +122,7 @@ namespace RenderPresent {
// doStuffOnceFenceDone() // doStuffOnceFenceDone()
#pragma endinfo #pragma endinfo
void render::createSyncObject() { void Render::createSyncObject() {
imageAvailableSemaphores.resize(Global::MAX_FRAMES_IN_FLIGHT); imageAvailableSemaphores.resize(Global::MAX_FRAMES_IN_FLIGHT);
renderFinishedSemaphores.resize(Global::MAX_FRAMES_IN_FLIGHT); renderFinishedSemaphores.resize(Global::MAX_FRAMES_IN_FLIGHT);
inFlightFences.resize(Global::MAX_FRAMES_IN_FLIGHT); inFlightFences.resize(Global::MAX_FRAMES_IN_FLIGHT);
@ -149,21 +144,21 @@ namespace RenderPresent {
} }
void render::destroyFenceSemaphores() { 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, renderFinishedSemaphores[i], nullptr); vkDestroySemaphore(Global::device, renderFinishedSemaphores[i], nullptr);
vkDestroySemaphore(Global::device, imageAvailableSemaphores[i], nullptr); vkDestroySemaphore(Global::device, imageAvailableSemaphores[i], nullptr);
vkDestroyFence(Global::device, inFlightFences[i], nullptr); vkDestroyFence(Global::device, inFlightFences[i], nullptr);
} }
} }
void render::cleanupSwapChain() { void Render::cleanupSwapChain() {
vkDestroyImageView(Global::device, Global::depthImageView, nullptr); vkDestroyImageView(Global::device, Global::depthImageView, nullptr);
vkDestroyImage(Global::device, Global::depthImage, nullptr); vkDestroyImage(Global::device, Global::depthImage, nullptr);
vkFreeMemory(Global::device, Global::depthImageMemory, nullptr); vkFreeMemory(Global::device, Global::depthImageMemory, nullptr);
for(auto framebuffer : pipeline.getSwapChainFramebuffers()) { for(auto framebuffer : graphics_pipeline::Graphics::getSwapChainFramebuffers()) {
vkDestroyFramebuffer(Global::device, framebuffer, nullptr); vkDestroyFramebuffer(Global::device, framebuffer, nullptr);
} }
for(auto imageView : deviceLibs.getSwapChainImageViews()) { for(auto imageView : device_libs::DeviceControl::getSwapChainImageViews()) {
vkDestroyImageView(Global::device, imageView, nullptr); vkDestroyImageView(Global::device, imageView, nullptr);
} }
vkDestroySwapchainKHR(Global::device, Global::swapChain, nullptr); vkDestroySwapchainKHR(Global::device, Global::swapChain, nullptr);

View File

@ -2,12 +2,12 @@
#include "../global.h" #include "../global.h"
namespace RenderPresent { namespace render_present {
class render { class Render {
public: public:
void drawFrame(); static void drawFrame();
void createSyncObject(); static void createSyncObject();
void destroyFenceSemaphores(); static void destroyFenceSemaphores();
void cleanupSwapChain(); static void cleanupSwapChain();
}; };
} }

View File

@ -1,20 +1,14 @@
#include <vulkan/vulkan_core.h>
#define STB_IMAGE_IMPLEMENTATION #define STB_IMAGE_IMPLEMENTATION
#include <stb/stb_image.h> #include <stb/stb_image.h>
#include "texture.h" #include "texture.h"
#include "buffers.h"
#include "../devicelibrary.h"
BuffersLibraries::buffers buffer;
DeviceControl::devicelibrary deviceLibraries;
VkImage textureImage; VkImage textureImage;
VkDeviceMemory textureImageMemory; VkDeviceMemory textureImageMemory;
VkPipelineStageFlags sourceStage; VkPipelineStageFlags sourceStage;
VkPipelineStageFlags destinationStage; VkPipelineStageFlags destinationStage;
namespace texture_libs {
namespace TextureLibraries {
void createImage(uint32_t width, uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags properties, VkImage& image, VkDeviceMemory& imageMemory) { void createImage(uint32_t width, uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags properties, VkImage& image, VkDeviceMemory& imageMemory) {
// This function specifies all the data in an image object, this is called directly after the creation of an image object. // This function specifies all the data in an image object, this is called directly after the creation of an image object.
VkImageCreateInfo imageInfo{}; VkImageCreateInfo imageInfo{};
@ -42,7 +36,7 @@ namespace TextureLibraries {
VkMemoryAllocateInfo allocInfo{}; VkMemoryAllocateInfo allocInfo{};
allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
allocInfo.allocationSize = memRequirements.size; allocInfo.allocationSize = memRequirements.size;
allocInfo.memoryTypeIndex = buffer.findMemoryType(memRequirements.memoryTypeBits, properties); allocInfo.memoryTypeIndex = buffers_libs::Buffers::findMemoryType(memRequirements.memoryTypeBits, properties);
if (vkAllocateMemory(Global::device, &allocInfo, nullptr, &imageMemory) != VK_SUCCESS) { if (vkAllocateMemory(Global::device, &allocInfo, nullptr, &imageMemory) != VK_SUCCESS) {
throw std::runtime_error("failed to allocate image memory!"); throw std::runtime_error("failed to allocate image memory!");
@ -186,7 +180,7 @@ void copyBufferToImage(VkBuffer buffer, VkImage image, uint32_t width, uint32_t
return format == VK_FORMAT_D32_SFLOAT_S8_UINT || format == VK_FORMAT_D24_UNORM_S8_UINT; return format == VK_FORMAT_D32_SFLOAT_S8_UINT || format == VK_FORMAT_D24_UNORM_S8_UINT;
} }
// -------------------------------- Image Libraries ------------------------------- // // -------------------------------- Image Libraries ------------------------------- //
void texture::createTextureImage() { void Texture::createTextureImage() {
// Import pixels from image with data on color channels, width and height, and colorspace! // Import pixels from image with data on color channels, width and height, and colorspace!
// Its a lot of kind of complicated memory calls to bring it from a file -> to a buffer -> to a image object. // Its a lot of kind of complicated memory calls to bring it from a file -> to a buffer -> to a image object.
int textureWidth, textureHeight, textureChannels; int textureWidth, textureHeight, textureChannels;
@ -199,7 +193,7 @@ void copyBufferToImage(VkBuffer buffer, VkImage image, uint32_t width, uint32_t
} }
VkBuffer stagingBuffer; VkBuffer stagingBuffer;
VkDeviceMemory stagingBufferMemory; VkDeviceMemory stagingBufferMemory;
buffer.createBuffer(imageSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, stagingBuffer, stagingBufferMemory); buffers_libs::Buffers::createBuffer(imageSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, stagingBuffer, stagingBufferMemory);
void* data; void* data;
vkMapMemory(Global::device, stagingBufferMemory, 0, imageSize, 0, &data); vkMapMemory(Global::device, stagingBufferMemory, 0, imageSize, 0, &data);
@ -217,11 +211,11 @@ void copyBufferToImage(VkBuffer buffer, VkImage image, uint32_t width, uint32_t
vkDestroyBuffer(Global::device, stagingBuffer, nullptr); vkDestroyBuffer(Global::device, stagingBuffer, nullptr);
vkFreeMemory(Global::device, stagingBufferMemory, nullptr); vkFreeMemory(Global::device, stagingBufferMemory, nullptr);
} }
void texture::createTextureImageView() { void Texture::createTextureImageView() {
// Create a texture image view, which is a struct of information about the image. // Create a texture image view, which is a struct of information about the image.
Global::textureImageView = deviceLibraries.createImageView(textureImage, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_ASPECT_COLOR_BIT); Global::textureImageView = device_libs::DeviceControl::createImageView(textureImage, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_ASPECT_COLOR_BIT);
} }
void texture::createTextureSampler() { void Texture::createTextureSampler() {
// Create a sampler to access and parse the texture object. // Create a sampler to access and parse the texture object.
VkSamplerCreateInfo samplerInfo{}; VkSamplerCreateInfo samplerInfo{};
samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
@ -263,26 +257,26 @@ void copyBufferToImage(VkBuffer buffer, VkImage image, uint32_t width, uint32_t
throw std::runtime_error("failed to create texture sampler!"); throw std::runtime_error("failed to create texture sampler!");
} }
} }
void texture::destroyTextureSampler() { void Texture::destroyTextureSampler() {
vkDestroySampler(Global::device, Global::textureSampler, nullptr); vkDestroySampler(Global::device, Global::textureSampler, nullptr);
vkDestroyImageView(Global::device, Global::textureImageView, nullptr); vkDestroyImageView(Global::device, Global::textureImageView, nullptr);
} }
void texture::destroyTextureImage() { void Texture::destroyTextureImage() {
vkDestroyImage(Global::device, textureImage, nullptr); vkDestroyImage(Global::device, textureImage, nullptr);
vkFreeMemory(Global::device, textureImageMemory, nullptr); vkFreeMemory(Global::device, textureImageMemory, nullptr);
} }
VkFormat texture::findDepthFormat() { VkFormat Texture::findDepthFormat() {
return findSupportedFormat( return findSupportedFormat(
{VK_FORMAT_D32_SFLOAT, VK_FORMAT_D32_SFLOAT_S8_UINT, VK_FORMAT_D24_UNORM_S8_UINT}, {VK_FORMAT_D32_SFLOAT, VK_FORMAT_D32_SFLOAT_S8_UINT, VK_FORMAT_D24_UNORM_S8_UINT},
VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_TILING_OPTIMAL,
VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT
); );
} }
void texture::createDepthResources() { void Texture::createDepthResources() {
VkFormat depthFormat = findDepthFormat(); VkFormat depthFormat = findDepthFormat();
VkExtent2D swapChainExtent = deviceLibraries.getSwapChainExtent(); VkExtent2D swapChainExtent = device_libs::DeviceControl::getSwapChainExtent();
createImage(swapChainExtent.width, swapChainExtent.height, depthFormat, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, Global::depthImage, Global::depthImageMemory); createImage(swapChainExtent.width, swapChainExtent.height, depthFormat, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, Global::depthImage, Global::depthImageMemory);
Global::depthImageView = deviceLibraries.createImageView(Global::depthImage, depthFormat, VK_IMAGE_ASPECT_DEPTH_BIT); Global::depthImageView = device_libs::DeviceControl::createImageView(Global::depthImage, depthFormat, VK_IMAGE_ASPECT_DEPTH_BIT);
// Explicit transition from the layout of the image to the depth attachment is unnecessary here, since that will be handled in the render pass! // Explicit transition from the layout of the image to the depth attachment is unnecessary here, since that will be handled in the render pass!

View File

@ -1,16 +1,17 @@
#pragma once #pragma once
#include "../global.h" #include "../global.h"
#include <vulkan/vulkan_core.h> #include "buffers.h"
#include "../devicelibrary.h"
namespace TextureLibraries { namespace texture_libs {
class texture { class Texture {
public: public:
void createTextureImage(); static void createTextureImage();
void createTextureImageView(); static void createTextureImageView();
void createTextureSampler(); static void createTextureSampler();
void destroyTextureImage(); static void destroyTextureImage();
void destroyTextureSampler(); static void destroyTextureSampler();
VkFormat findDepthFormat(); static VkFormat findDepthFormat();
void createDepthResources(); static void createDepthResources();
}; };
} }