Implemented image view system for.. viewing images

This commit is contained in:
Lillian Salehi 2024-10-07 05:09:46 -05:00
parent 3bb747bfae
commit fa14b3fd8f
8 changed files with 93 additions and 44 deletions

View File

@ -1,6 +1,7 @@
CPPFLAGS=-g CPPFLAGS=-g
LDFLAGS=-lglfw -lvulkan -ldl -lpthread -lX11 -lXxf86vm -lXrandr -lXi LDFLAGS=-lglfw -lvulkan -ldl -lpthread -lX11 -lXxf86vm -lXrandr -lXi
DEBUGFLAGS=-DDEBUG -fsanitize=address DEBUGFLAGS=-DDEBUG -fsanitize=address
GDBFLAGS=
SRC=$(shell find . -name *.cpp) SRC=$(shell find . -name *.cpp)
OBJ=$(SRC:%.cpp=%.o) OBJ=$(SRC:%.cpp=%.o)
@ -13,13 +14,19 @@ all: $(BIN)
.PHONY: run .PHONY: run
run: $(BIN) run: $(BIN)
./$(BIN) ./$(BIN)
.PHONY: gdb
gdb: LDFLAGS+=$(GDBFLAGS)
gdb: $(BIN)
gdb -q $(BIN)
.PHONY: debug .PHONY: debug
debug: LDFLAGS+=$(DEBUGFLAGS) debug: LDFLAGS+=$(DEBUGFLAGS)
debug: $(BIN) debug: $(BIN)
./$(BIN) ./$(BIN)
.PHONY: dep .PHONY: dep
dep: dep:
sudo pacman -S gcc glfw glm shaderc libxi libxxf86vm sudo pacman -S gcc glfw glm shaderc libxi libxxf86vm gdb
.PHONY: info .PHONY: info
info: info:
@echo "make: Build executable" @echo "make: Build executable"
@ -33,7 +40,7 @@ $(BIN): $(OBJ)
g++ $(CPPFLAGS) -o $(BIN) $(OBJ) $(LDFLAGS) g++ $(CPPFLAGS) -o $(BIN) $(OBJ) $(LDFLAGS)
%.o: %.cpp %.o: %.cpp
g++ -c $< -o $@ $(LDFLAGS) g++ -c -g $< -o $@ $(LDFLAGS)
.PHONY: clean .PHONY: clean
clean: clean:

View File

@ -8,5 +8,5 @@
- Implement features for maximum fidelity/performance ratio - Implement features for maximum fidelity/performance ratio
- Implement custom Raytracing and Raymarching protocols - Implement custom Raytracing and Raymarching protocols
- Mess with cutting edge design, VDB's, 3D Guassian Splatting, - Mess with cutting edge design, VDB's, 3D Guassian Splatting,
- 1000000+ FPS on Potato GPUs /s - 1000000+ FPS on Potato GPUs

View File

@ -1,3 +1,4 @@
#include "vulkandebuglibs.h"
#include "../global.h" #include "../global.h"
using namespace Debug; using namespace Debug;
@ -53,7 +54,7 @@ void populateDebugMessengerCreateInfo(VkDebugUtilsMessengerCreateInfoEXT& create
createInfo.pUserData = nullptr; // Optional createInfo.pUserData = nullptr; // Optional
} }
void VulkanDebugLibs::vulkanDebugSetup(VkInstanceCreateInfo& createInfo, VkInstance& instance) { 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. // 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, // 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. // and if we set it before the creation of the instance, we cant debug vkCreateInstance or vkDestroyInstance! It's timed perfectly as of now.
@ -79,14 +80,14 @@ void VulkanDebugLibs::vulkanDebugSetup(VkInstanceCreateInfo& createInfo, VkInsta
} }
} }
void VulkanDebugLibs::checkUnavailableValidationLayers() { void vulkandebuglibs::checkUnavailableValidationLayers() {
// Check if we are trying to hook validation layers in without support. // Check if we are trying to hook validation layers in without support.
if(Global::enableValidationLayers && !checkValidationLayerSupport()) { if(Global::enableValidationLayers && !checkValidationLayerSupport()) {
throw std::runtime_error("Validation layers request, but not available! Are your SDK path variables set?"); throw std::runtime_error("Validation layers request, but not available! Are your SDK path variables set?");
} }
} }
bool VulkanDebugLibs::checkValidationLayerSupport() { bool vulkandebuglibs::checkValidationLayerSupport() {
// This function is used to check Validation Layer Support, validation layers are the debug trace tools in the Vulkan SDK. // 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 // 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. // VkLayerProperties is a structure with data on the layername, desc, versions and etc.
@ -131,7 +132,7 @@ VkResult CreateDebugUtilsMessengerEXT(
} }
} }
void VulkanDebugLibs::DestroyDebugUtilsMessengerEXT(VkInstance instance, void vulkandebuglibs::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.
@ -141,7 +142,7 @@ void VulkanDebugLibs::DestroyDebugUtilsMessengerEXT(VkInstance instance,
} }
} }
void VulkanDebugLibs::setupDebugMessenger(VkInstance& vulkanInstance) { 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, // 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! // and safely create it, covering for runtime errors as per usual, this is the first thing that will be called!
if(!Global::enableValidationLayers) return; if(!Global::enableValidationLayers) return;

View File

@ -3,7 +3,7 @@
#include <vulkan/vulkan_core.h> #include <vulkan/vulkan_core.h>
namespace Debug { namespace Debug {
class VulkanDebugLibs { class vulkandebuglibs {
public: public:
void vulkanDebugSetup(VkInstanceCreateInfo& createInfo, VkInstance& instance); void vulkanDebugSetup(VkInstanceCreateInfo& createInfo, VkInstance& instance);

View File

@ -1,4 +1,4 @@
#include "DeviceLibrary.h" #include "devicelibrary.h"
#include "global.h" #include "global.h"
#include <algorithm> #include <algorithm>
@ -10,6 +10,7 @@
#include <stdexcept> #include <stdexcept>
#include <string> #include <string>
#include <vector> #include <vector>
#include <vulkan/vulkan_core.h>
namespace DeviceControl { namespace DeviceControl {
@ -23,6 +24,7 @@ namespace DeviceControl {
std::vector<VkImage> swapChainImages; std::vector<VkImage> swapChainImages;
VkFormat swapChainImageFormat; VkFormat swapChainImageFormat;
VkExtent2D swapChainExtent; VkExtent2D swapChainExtent;
std::vector<VkImageView> swapChainImageViews;
VkQueue graphicsQueue; VkQueue graphicsQueue;
VkQueue presentQueue; VkQueue presentQueue;
@ -142,7 +144,6 @@ namespace DeviceControl {
return deviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU return deviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU
&& deviceFeatures.multiViewport && deviceFeatures.multiViewport
&& deviceFeatures.geometryShader
&& indices.isComplete() && indices.isComplete()
&& extensionSupported && extensionSupported
&& swapChainAdequate; && swapChainAdequate;
@ -166,9 +167,12 @@ namespace DeviceControl {
// This is most similarly to standard V-Sync. // This is most similarly to standard V-Sync.
for(const auto& availablePresentMode : availablePresentModes) { for(const auto& availablePresentMode : availablePresentModes) {
if(availablePresentMode == VK_PRESENT_MODE_MAILBOX_KHR) { if(availablePresentMode == VK_PRESENT_MODE_MAILBOX_KHR) {
if(Global::enableValidationLayers) std::cout << "Using Triple Buffering\n" << std::endl;
return availablePresentMode; return availablePresentMode;
} }
} }
if(Global::enableValidationLayers) std::cout << "Using FIFO (V-Sync)\n" << std::endl;
return VK_PRESENT_MODE_FIFO_KHR; return VK_PRESENT_MODE_FIFO_KHR;
} }
VkExtent2D chooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities, GLFWwindow* window) { VkExtent2D chooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities, GLFWwindow* window) {
@ -179,22 +183,22 @@ namespace DeviceControl {
if (capabilities.currentExtent.width != std::numeric_limits<uint32_t>::max()) { if (capabilities.currentExtent.width != std::numeric_limits<uint32_t>::max()) {
return capabilities.currentExtent; return capabilities.currentExtent;
} else { } else {
int width, height; int width, height;
glfwGetFramebufferSize(window, &width, &height); glfwGetFramebufferSize(window, &width, &height);
VkExtent2D actualExtent = { VkExtent2D actualExtent = {
static_cast<uint32_t>(width), static_cast<uint32_t>(width),
static_cast<uint32_t>(height) static_cast<uint32_t>(height)
}; };
// Clamp the image size to the minimum extent values specified by vulkan for our window manager. // Clamp the image size to the minimum extent values specified by vulkan for our window manager.
actualExtent.width = std::clamp(actualExtent.width, capabilities.minImageExtent.width, capabilities.maxImageExtent.width); actualExtent.width = std::clamp(actualExtent.width, capabilities.minImageExtent.width, capabilities.maxImageExtent.width);
actualExtent.height = std::clamp(actualExtent.height, capabilities.minImageExtent.height, capabilities.maxImageExtent.height); actualExtent.height = std::clamp(actualExtent.height, capabilities.minImageExtent.height, capabilities.maxImageExtent.height);
return actualExtent; return actualExtent;
} }
} }
// --------------------------------------- External Functions -----------------------------------------// // --------------------------------------- External Functions -----------------------------------------//
void DeviceLibrary::pickPhysicalDevice(VkInstance& instance) { void devicelibrary::pickPhysicalDevice(VkInstance& instance) {
uint32_t deviceCount = 0; uint32_t deviceCount = 0;
vkEnumeratePhysicalDevices(instance, &deviceCount, nullptr); vkEnumeratePhysicalDevices(instance, &deviceCount, nullptr);
@ -206,7 +210,7 @@ namespace DeviceControl {
for(const auto& device : devices) { for(const auto& device : devices) {
if(isDeviceSuitable(device)) { if(isDeviceSuitable(device)) {
std::cout << "Using device: " << deviceProperties.deviceName << std::endl; if(Global::enableValidationLayers) std::cout << "Using device: " << deviceProperties.deviceName << std::endl;
//Once we have buttons or such, maybe ask the user or write a config file for which GPU to use? //Once we have buttons or such, maybe ask the user or write a config file for which GPU to use?
physicalDevice = device; physicalDevice = device;
break; break;
@ -216,17 +220,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 devicelibrary::destroySurface(VkInstance& instance) {
vkDestroySurfaceKHR(instance, surface, nullptr); vkDestroySurfaceKHR(instance, surface, nullptr);
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 devicelibrary::createSurface(VkInstance& instance, GLFWwindow* window) {
if(glfwCreateWindowSurface(instance, window, nullptr, &surface) != VK_SUCCESS) { if(glfwCreateWindowSurface(instance, window, nullptr, &surface) != VK_SUCCESS) {
throw std::runtime_error("Failed to create window surface!!"); throw std::runtime_error("Failed to create window surface!!");
} }
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(VkDevice& device) { void devicelibrary::createLogicalDevice(VkDevice& device) {
// 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!
@ -264,12 +268,12 @@ namespace DeviceControl {
if(vkCreateDevice(physicalDevice, &createDeviceInfo, nullptr, &device) != VK_SUCCESS) { if(vkCreateDevice(physicalDevice, &createDeviceInfo, nullptr, &device) != VK_SUCCESS) {
throw std::runtime_error("Failed to create logical device"); throw std::runtime_error("Failed to create logical device");
} }
std::cout << "Created Logical device successfully!\n" << std::endl; if(Global::enableValidationLayers) std::cout << "Created Logical device successfully!\n" << std::endl;
vkGetDeviceQueue(device, indices.graphicsFamily.value(), 0, &graphicsQueue); vkGetDeviceQueue(device, indices.graphicsFamily.value(), 0, &graphicsQueue);
vkGetDeviceQueue(device, indices.presentFamily.value(), 0, &presentQueue); vkGetDeviceQueue(device, indices.presentFamily.value(), 0, &presentQueue);
} }
void DeviceLibrary::createSwapChain(GLFWwindow* window, VkDevice& device) { void devicelibrary::createSwapChain(GLFWwindow* window, VkDevice& device) {
SwapChainSupportDetails swapChainSupport = querySwapChainSupport(physicalDevice); SwapChainSupportDetails swapChainSupport = querySwapChainSupport(physicalDevice);
VkSurfaceFormatKHR surfaceFormat = chooseSwapSurfaceFormat(swapChainSupport.formats); VkSurfaceFormatKHR surfaceFormat = chooseSwapSurfaceFormat(swapChainSupport.formats);
@ -326,7 +330,7 @@ namespace DeviceControl {
if(vkCreateSwapchainKHR(device, &createSwapChainInfo, nullptr, &swapChain) != VK_SUCCESS) { if(vkCreateSwapchainKHR(device, &createSwapChainInfo, nullptr, &swapChain) != VK_SUCCESS) {
throw std::runtime_error("Failed to create the swap chain!!"); throw std::runtime_error("Failed to create the swap chain!!");
} }
std::cout << "Swap Chain created successfully\n" << std::endl; if(Global::enableValidationLayers) std::cout << "Swap Chain created successfully\n" << std::endl;
vkGetSwapchainImagesKHR(device, swapChain, &imageCount, nullptr); vkGetSwapchainImagesKHR(device, swapChain, &imageCount, nullptr);
swapChainImages.resize(imageCount); swapChainImages.resize(imageCount);
@ -335,8 +339,42 @@ namespace DeviceControl {
swapChainImageFormat = surfaceFormat.format; swapChainImageFormat = surfaceFormat.format;
swapChainExtent = extent; swapChainExtent = extent;
} }
void DeviceLibrary::destroySwapChain(VkDevice& device) { void devicelibrary::destroySwapChain(VkDevice& device) {
vkDestroySwapchainKHR(device, swapChain, nullptr); vkDestroySwapchainKHR(device, swapChain, nullptr);
std::cout << "Destroyed Swap Chain safely\n" << std::endl; if(Global::enableValidationLayers) std::cout << "Destroyed Swap Chain safely\n" << std::endl;
}
void devicelibrary::createImageViews(VkDevice& device) {
swapChainImageViews.resize(swapChainImages.size());
for(size_t i = 0; i < swapChainImages.size(); i++) {
VkImageViewCreateInfo createImageViewInfo{};
createImageViewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
createImageViewInfo.image = swapChainImages[i];
// Are we treating images as 1D, 2D or 3D?
createImageViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
createImageViewInfo.format = swapChainImageFormat;
// Allow us to swizzle color channels
createImageViewInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
createImageViewInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
createImageViewInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
createImageViewInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
createImageViewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
createImageViewInfo.subresourceRange.baseMipLevel = 0;
createImageViewInfo.subresourceRange.levelCount = 1;
createImageViewInfo.subresourceRange.baseArrayLayer = 0;
// Yet another setting we would increase for VR applications, and specifically create a swap chain with more layers as well. The other layers would be the eye outputs.
createImageViewInfo.subresourceRange.layerCount = 1;
if(vkCreateImageView(device, &createImageViewInfo, nullptr, &swapChainImageViews[i]) != VK_SUCCESS) {
throw std::runtime_error("failed to create image views!");
}
if(Global::enableValidationLayers) std::cout << "Image views created successfully\n" << std::endl;
}
}
void devicelibrary::destroyImageViews(VkDevice& device) {
for (auto imageView : swapChainImageViews) {
vkDestroyImageView(device, imageView, nullptr);
}
if(Global::enableValidationLayers) std::cout << "Image destroyed safely\n" << std::endl;
} }
} }

View File

@ -1,7 +1,7 @@
#pragma once #pragma once
#include "global.h" #include "global.h"
namespace DeviceControl { namespace DeviceControl {
class DeviceLibrary { class devicelibrary {
public: public:
void pickPhysicalDevice(VkInstance& instance); void pickPhysicalDevice(VkInstance& instance);
@ -10,6 +10,8 @@ namespace DeviceControl {
void destroySurface(VkInstance& instance); void destroySurface(VkInstance& instance);
void createSwapChain(GLFWwindow* window, VkDevice& device); void createSwapChain(GLFWwindow* window, VkDevice& device);
void destroySwapChain(VkDevice& device); void destroySwapChain(VkDevice& device);
void createImageViews(VkDevice& device);
void destroyImageViews(VkDevice& device);
}; };
} }

View File

@ -1,5 +1,5 @@
#pragma once #pragma once
#include "debug/VulkanDebugLibs.h" #include "debug/vulkandebuglibs.h"
#include <iostream> #include <iostream>
#include <vector> #include <vector>
#include <vulkan/vulkan_core.h> #include <vulkan/vulkan_core.h>

View File

@ -1,6 +1,5 @@
#include "devicelibrary.h" // Device Library includes global, redundant to include with it here
#include "DeviceLibrary.h" // Device Library includes global, redundant to include with it here #include "debug/vulkandebuglibs.h"
#include "debug/VulkanDebugLibs.h"
#include <cstdint> #include <cstdint>
#include <cstring> #include <cstring>
@ -22,8 +21,8 @@ public:
} }
private: private:
DeviceControl::DeviceLibrary deviceLibs; DeviceControl::devicelibrary deviceLibs;
Debug::VulkanDebugLibs debugController; Debug::vulkandebuglibs debugController;
GLFWwindow* window; GLFWwindow* window;
VkInstance instance; VkInstance instance;
@ -42,15 +41,16 @@ private:
void initVulkan() { void initVulkan() {
createInstance(); 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) 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.createSurface(instance, window);
deviceLibs.pickPhysicalDevice(instance); deviceLibs.pickPhysicalDevice(instance);
deviceLibs.createLogicalDevice(device); deviceLibs.createLogicalDevice(device);
deviceLibs.createSwapChain(window, device); deviceLibs.createSwapChain(window, device);
deviceLibs.createImageViews(device);
} }
void createInstance() { void createInstance() {
debugController.checkUnavailableValidationLayers(); // Check if there is a mistake with our Validation Layers. debugController.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{};
@ -66,7 +66,7 @@ private:
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, instance); // Handoff to the debug library to wrap the validation libs in! (And set the window up!) 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. void mainLoop() { // This loop just updates the GLFW window.
@ -75,7 +75,8 @@ private:
} }
} }
void cleanup() { // Similar to the last handoff, destroy the debug util in a safe manner in the library! void cleanup() { // Similar to the last handoff, destroy the utils in a safe manner in the library!
deviceLibs.destroyImageViews(device);
deviceLibs.destroySwapChain(device); deviceLibs.destroySwapChain(device);
vkDestroyDevice(device, nullptr); vkDestroyDevice(device, nullptr);
if(Global::enableValidationLayers) { if(Global::enableValidationLayers) {