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

View File

@ -8,5 +8,5 @@
- Implement features for maximum fidelity/performance ratio
- Implement custom Raytracing and Raymarching protocols
- 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"
using namespace Debug;
@ -53,7 +54,7 @@ void populateDebugMessengerCreateInfo(VkDebugUtilsMessengerCreateInfoEXT& create
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.
// 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.
@ -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.
if(Global::enableValidationLayers && !checkValidationLayerSupport()) {
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.
// 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.
@ -131,7 +132,7 @@ VkResult CreateDebugUtilsMessengerEXT(
}
}
void VulkanDebugLibs::DestroyDebugUtilsMessengerEXT(VkInstance instance,
void vulkandebuglibs::DestroyDebugUtilsMessengerEXT(VkInstance instance,
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.
@ -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,
// and safely create it, covering for runtime errors as per usual, this is the first thing that will be called!
if(!Global::enableValidationLayers) return;

View File

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

View File

@ -1,4 +1,4 @@
#include "DeviceLibrary.h"
#include "devicelibrary.h"
#include "global.h"
#include <algorithm>
@ -10,6 +10,7 @@
#include <stdexcept>
#include <string>
#include <vector>
#include <vulkan/vulkan_core.h>
namespace DeviceControl {
@ -23,6 +24,7 @@ namespace DeviceControl {
std::vector<VkImage> swapChainImages;
VkFormat swapChainImageFormat;
VkExtent2D swapChainExtent;
std::vector<VkImageView> swapChainImageViews;
VkQueue graphicsQueue;
VkQueue presentQueue;
@ -142,7 +144,6 @@ namespace DeviceControl {
return deviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU
&& deviceFeatures.multiViewport
&& deviceFeatures.geometryShader
&& indices.isComplete()
&& extensionSupported
&& swapChainAdequate;
@ -166,9 +167,12 @@ namespace DeviceControl {
// This is most similarly to standard V-Sync.
for(const auto& availablePresentMode : availablePresentModes) {
if(availablePresentMode == VK_PRESENT_MODE_MAILBOX_KHR) {
if(Global::enableValidationLayers) std::cout << "Using Triple Buffering\n" << std::endl;
return availablePresentMode;
}
}
if(Global::enableValidationLayers) std::cout << "Using FIFO (V-Sync)\n" << std::endl;
return VK_PRESENT_MODE_FIFO_KHR;
}
VkExtent2D chooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities, GLFWwindow* window) {
@ -179,22 +183,22 @@ namespace DeviceControl {
if (capabilities.currentExtent.width != std::numeric_limits<uint32_t>::max()) {
return capabilities.currentExtent;
} else {
int width, height;
glfwGetFramebufferSize(window, &width, &height);
int width, height;
glfwGetFramebufferSize(window, &width, &height);
VkExtent2D actualExtent = {
static_cast<uint32_t>(width),
static_cast<uint32_t>(height)
};
VkExtent2D actualExtent = {
static_cast<uint32_t>(width),
static_cast<uint32_t>(height)
};
// 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.height = std::clamp(actualExtent.height, capabilities.minImageExtent.height, capabilities.maxImageExtent.height);
actualExtent.width = std::clamp(actualExtent.width, capabilities.minImageExtent.width, capabilities.maxImageExtent.width);
actualExtent.height = std::clamp(actualExtent.height, capabilities.minImageExtent.height, capabilities.maxImageExtent.height);
return actualExtent;
return actualExtent;
}
}
// --------------------------------------- External Functions -----------------------------------------//
void DeviceLibrary::pickPhysicalDevice(VkInstance& instance) {
void devicelibrary::pickPhysicalDevice(VkInstance& instance) {
uint32_t deviceCount = 0;
vkEnumeratePhysicalDevices(instance, &deviceCount, nullptr);
@ -206,7 +210,7 @@ namespace DeviceControl {
for(const auto& device : devices) {
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?
physicalDevice = device;
break;
@ -216,17 +220,17 @@ namespace DeviceControl {
throw std::runtime_error("Failed to find a suitable GPU!");
}
}
void DeviceLibrary::destroySurface(VkInstance& instance) {
void devicelibrary::destroySurface(VkInstance& instance) {
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) {
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,
// 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!
@ -264,12 +268,12 @@ namespace DeviceControl {
if(vkCreateDevice(physicalDevice, &createDeviceInfo, nullptr, &device) != VK_SUCCESS) {
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.presentFamily.value(), 0, &presentQueue);
}
void DeviceLibrary::createSwapChain(GLFWwindow* window, VkDevice& device) {
void devicelibrary::createSwapChain(GLFWwindow* window, VkDevice& device) {
SwapChainSupportDetails swapChainSupport = querySwapChainSupport(physicalDevice);
VkSurfaceFormatKHR surfaceFormat = chooseSwapSurfaceFormat(swapChainSupport.formats);
@ -326,7 +330,7 @@ namespace DeviceControl {
if(vkCreateSwapchainKHR(device, &createSwapChainInfo, nullptr, &swapChain) != VK_SUCCESS) {
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);
swapChainImages.resize(imageCount);
@ -335,8 +339,42 @@ namespace DeviceControl {
swapChainImageFormat = surfaceFormat.format;
swapChainExtent = extent;
}
void DeviceLibrary::destroySwapChain(VkDevice& device) {
void devicelibrary::destroySwapChain(VkDevice& device) {
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
#include "global.h"
namespace DeviceControl {
class DeviceLibrary {
class devicelibrary {
public:
void pickPhysicalDevice(VkInstance& instance);
@ -10,6 +10,8 @@ namespace DeviceControl {
void destroySurface(VkInstance& instance);
void createSwapChain(GLFWwindow* window, VkDevice& device);
void destroySwapChain(VkDevice& device);
void createImageViews(VkDevice& device);
void destroyImageViews(VkDevice& device);
};
}

View File

@ -1,5 +1,5 @@
#pragma once
#include "debug/VulkanDebugLibs.h"
#include "debug/vulkandebuglibs.h"
#include <iostream>
#include <vector>
#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 "debug/VulkanDebugLibs.h"
#include "devicelibrary.h" // Device Library includes global, redundant to include with it here
#include "debug/vulkandebuglibs.h"
#include <cstdint>
#include <cstring>
@ -22,8 +21,8 @@ public:
}
private:
DeviceControl::DeviceLibrary deviceLibs;
Debug::VulkanDebugLibs debugController;
DeviceControl::devicelibrary deviceLibs;
Debug::vulkandebuglibs debugController;
GLFWwindow* window;
VkInstance instance;
@ -42,15 +41,16 @@ private:
void initVulkan() {
createInstance();
debugController.setupDebugMessenger(instance); // The debug messenger is out holy grail, it gives us Vulkan related debug info when built with the -DNDEBUG flag (as per the makefile)
debugController.setupDebugMessenger(instance); // The debug messenger is out holy grail, it gives us Vulkan related debug info when built with the -DNDEBUG flag (as per the makefile)
deviceLibs.createSurface(instance, window);
deviceLibs.pickPhysicalDevice(instance);
deviceLibs.createLogicalDevice(device);
deviceLibs.createSwapChain(window, device);
deviceLibs.createImageViews(device);
}
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!
VkApplicationInfo appInfo{};
@ -66,7 +66,7 @@ private:
createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; // Tell vulkan this is a info structure
createInfo.pApplicationInfo = &appInfo; // We just created a new appInfo structure, so we pass the pointer to it.
debugController.vulkanDebugSetup(createInfo, instance); // Handoff to the debug library to wrap the validation libs in! (And set the window up!)
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.
@ -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);
vkDestroyDevice(device, nullptr);
if(Global::enableValidationLayers) {