diff --git a/.clangd b/.clangd index 028d859..0a8dc64 100644 --- a/.clangd +++ b/.clangd @@ -1,5 +1,6 @@ CompileFlags: - Add: + Add: - -I./include - - -I/usr/include/vulkan + - -I./src + - -I./src/public - -std=c++20 diff --git a/Learning Vulkan.vcxproj b/Learning Vulkan.vcxproj index 0a4340b..c1d6ef7 100644 --- a/Learning Vulkan.vcxproj +++ b/Learning Vulkan.vcxproj @@ -140,11 +140,11 @@ - + - + @@ -157,4 +157,4 @@ - \ No newline at end of file + diff --git a/Learning Vulkan.vcxproj.filters b/Learning Vulkan.vcxproj.filters index 888d47a..03a207b 100644 --- a/Learning Vulkan.vcxproj.filters +++ b/Learning Vulkan.vcxproj.filters @@ -1,4 +1,4 @@ - + @@ -41,7 +41,7 @@ - + Header Files @@ -59,7 +59,7 @@ Header Files - + Header Files @@ -75,4 +75,4 @@ Shaders - \ No newline at end of file + diff --git a/LearningVulkan b/LearningVulkan new file mode 100755 index 0000000..5cc0525 Binary files /dev/null and b/LearningVulkan differ diff --git a/Makefile b/Makefile index 0f42e59..7b1cb31 100644 --- a/Makefile +++ b/Makefile @@ -1,13 +1,27 @@ CXX = g++ -CFLAGS = -std=c++20 -O2 -Wall -Wextra -I./include +CXXFLAGS = -std=c++20 -O2 -Wall -Wextra -I./include -I./src -I./src/private -I./src/public LDFLAGS = -lglfw -lvulkan -ldl -lpthread -lX11 -lXxf86vm -lXrandr -lXi -TARGET := LearningVulkan +BUILDDIR = build +OBJDIR = $(BUILDDIR)/obj -$(TARGET): ./src/main.cpp - $(CXX) $(CFLAGS) -o $(TARGET) ./src/main.cpp $(LDFLAGS) +SOURCES = $(shell find ./src -name "*.cpp") + +OBJECTS = $(SOURCES:./src/%.cpp=$(OBJDIR)/%.o) + +TARGET = LearningVulkan + +$(OBJDIR): + @mkdir -p $@ + +$(OBJDIR)/%.o: ./src/%.cpp | $(OBJDIR) + @mkdir -p $(@D) + $(CXX) $(CXXFLAGS) -c $< -o $@ + +$(TARGET): $(OBJECTS) + $(CXX) $(OBJECTS) -o $@ $(LDFLAGS) .PHONY: test clean @@ -15,4 +29,4 @@ test: $(TARGET) ./$(TARGET) clean: - rm -f $(TARGET) + rm -rf $(BUILDDIR) diff --git a/Shaders/compile.sh b/Shaders/compile.sh new file mode 100755 index 0000000..5cd654c --- /dev/null +++ b/Shaders/compile.sh @@ -0,0 +1,3 @@ +#!/bin/bash +glslc ./shader.vert -o vert.spv +glslc ./shader.frag -o frag.spv diff --git a/Shaders/shader.vert b/Shaders/shader.vert index 66d6766..fa977f6 100644 --- a/Shaders/shader.vert +++ b/Shaders/shader.vert @@ -1,20 +1,12 @@ #version 450 +layout(location = 0) in vec2 inPosition; +layout(location = 1) in vec3 inColor; + layout(location = 0) out vec3 fragColor; -vec2 positions[3] = vec2[]( - vec2(0.0, -0.5), - vec2(0.5, 0.5), - vec2(-0.5, 0.5) -); - -vec3 colors[3] = vec3[]( - vec3(1.0, 0.0, 0.0), - vec3(0.0, 1.0, 0.0), - vec3(0.0, 0.0, 1.0) -); - void main() { - gl_Position = vec4(positions[gl_VertexIndex], 0.0, 1.0); - fragColor = colors[gl_VertexIndex]; -} \ No newline at end of file + gl_Position = vec4(inPosition, 0.0, 1.0); + fragColor = inColor; +} + diff --git a/Shaders/vert.spv b/Shaders/vert.spv index cf7123f..a8ec1a6 100644 Binary files a/Shaders/vert.spv and b/Shaders/vert.spv differ diff --git a/src/VulkanContext.cpp b/src/VulkanContext.cpp deleted file mode 100644 index e69e7b8..0000000 --- a/src/VulkanContext.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "VulkanContext.h" diff --git a/src/VulkanContext.h b/src/VulkanContext.h deleted file mode 100644 index 3a0976e..0000000 --- a/src/VulkanContext.h +++ /dev/null @@ -1,52 +0,0 @@ -#pragma once -// #include -// #include -// -#include "VulkanInstanceManager.h" -#include "VulkanDebugManager.h" - -#define GLFW_INCLUDE_VULKAN -#include - -const std::vector ValidationLayers = { - "VK_LAYER_KHRONOS_validation" -}; - -struct FVulkanConfig -{ - bool bValidationEnabled = true; - bool bVerboseLogging = false; -}; - -class VulkanContext -{ -public: - VulkanContext(); - ~VulkanContext(); - - void Initialize(FVulkanConfig& Config); - void Cleanup(); - -private: - FVulkanConfig Config = {}; - - VkInstance Instance = VK_NULL_HANDLE; - VkPhysicalDevice PhysicalDevice = VK_NULL_HANDLE; - VkDevice Device = VK_NULL_HANDLE; - VkQueue GraphicsQueue = VK_NULL_HANDLE; - VkSurfaceKHR Surface = VK_NULL_HANDLE; - VkDebugUtilsMessengerEXT debugMessenger = VK_NULL_HANDLE; - -public: - static VulkanDebugManager DebugManager; - -private: - VulkanInstanceManager InstanceManager; - -public: - VkInstance GetInstance() const { return Instance; } - VkPhysicalDevice GetPhysicalDevice() const { return PhysicalDevice; } - VkDevice GetDevice() const { return Device; } - VkQueue GetGraphicsQueue() const { return GraphicsQueue; } - VkSurfaceKHR GetSurface() const { return Surface; } -}; diff --git a/src/VulkanDeviceManager.cpp b/src/VulkanDeviceManager.cpp deleted file mode 100644 index 467bb1b..0000000 --- a/src/VulkanDeviceManager.cpp +++ /dev/null @@ -1,442 +0,0 @@ -#include "VulkanDeviceManager.h" - -#include -#include -#include // Necessary for uint32_t -#include // Necessary for std::numeric_limits -#include // Necessary for std::clamp - -#include "Logger.h" -#include "GlfwWindowManager.h" -#include - -std::vector VulkanDeviceManager::SwapChainImages = {}; - -VulkanDeviceManager::VulkanDeviceManager() -{ -} - -VulkanDeviceManager::~VulkanDeviceManager() -{ - // Cleanup(); -} - -VulkanDeviceManager::VulkanDeviceManager(VulkanDeviceManager&& Other) noexcept - : PhysicalDevice(std::exchange(Other.PhysicalDevice, VK_NULL_HANDLE)) - , Instance(std::exchange(Other.Instance, VK_NULL_HANDLE)) - , Device(std::exchange(Other.Device, VK_NULL_HANDLE)) - , GraphicsQueue(std::exchange(Other.GraphicsQueue, VK_NULL_HANDLE)) - , bEnableValidationLayers(std::exchange(Other.bEnableValidationLayers, false)) - , ValidationLayers(std::move(Other.ValidationLayers)) -{ -} - -VulkanDeviceManager& VulkanDeviceManager::operator=(VulkanDeviceManager&& Other) noexcept -{ - if (this != &Other) - { - Cleanup(); // Clean up current resources - - // Transfer resources from Other - PhysicalDevice = std::exchange(Other.PhysicalDevice, VK_NULL_HANDLE); - Instance = std::exchange(Other.Instance, VK_NULL_HANDLE); - Device = std::exchange(Other.Device, VK_NULL_HANDLE); - GraphicsQueue = std::exchange(Other.GraphicsQueue, VK_NULL_HANDLE); - bEnableValidationLayers = std::exchange(Other.bEnableValidationLayers, false); - ValidationLayers = std::move(Other.ValidationLayers); - } - return *this; -} - -void VulkanDeviceManager::Initialize( - VkInstance Instance, - bool bEnableValidationLayers, - const std::vector& ValidationLayers) -{ - if (IsInitialized()) - { - Log::Warning("Already Initialized."); - return; - } - - this->Instance = Instance; - this->bEnableValidationLayers = bEnableValidationLayers; - this->ValidationLayers = &ValidationLayers; - - PickPhysicalDevice(); - CreateLogicalDevice(); - CreateSwapChain(); - CreateImageViews(); -} - -void VulkanDeviceManager::Cleanup() -{ - if (!IsInitialized()) - { - Log::Warning("Not Initialized."); - return; - } - for (auto ImageView : SwapChainImageViews) - { - vkDestroyImageView(Device, ImageView, nullptr); - } - vkDestroySwapchainKHR(Device, SwapChain, nullptr); - - vkDestroySurfaceKHR(Instance, GlfwWindowManager::Surface, nullptr); - vkDestroyDevice(Device, nullptr); -} - -void VulkanDeviceManager::PickPhysicalDevice() -{ - uint32_t DeviceCount = 0; - vkEnumeratePhysicalDevices(Instance, &DeviceCount, nullptr); - - if (DeviceCount == 0) - { - Log::Error("Failed to find GPU with Vulkan Support."); - } - - std::vector Devices(DeviceCount); - vkEnumeratePhysicalDevices(Instance, &DeviceCount, Devices.data()); - - std::multimap Candidates; - - for (const auto& Device : Devices) - { - if (IsDeviceSuitable(Device)) - { - int Score = RateDeviceSuitability(Device); - Candidates.insert(std::make_pair(Score, Device)); - } - } - - if (Candidates.rbegin()->first > 0) - { - PhysicalDevice = Candidates.rbegin()->second; - Log::Info("Suitable GPU found."); - } - else - { - Log::Error("Failed to find a suitable GPU."); - } -} - -bool VulkanDeviceManager::IsDeviceSuitable(VkPhysicalDevice Device) -{ - QueueFamilyIndices Indices = FindQueueFamilies(Device); - - bool bExtensionsSupported = CheckDeviceExtensionSupport(Device); - - bool bSwapChainAdequate = false; - if (bExtensionsSupported) - { - SwapChainSupportDetails SwapChainSupport = QuerySwapChainSupport(Device); - bSwapChainAdequate = !SwapChainSupport.Formats.empty() && !SwapChainSupport.PresentModes.empty(); - } - - return Indices.IsComplete() && bExtensionsSupported && bSwapChainAdequate; -} - -int VulkanDeviceManager::RateDeviceSuitability(VkPhysicalDevice Device) -{ - VkPhysicalDeviceProperties DeviceProperties; - vkGetPhysicalDeviceProperties(Device, &DeviceProperties); - - VkPhysicalDeviceFeatures DeviceFeatures; - vkGetPhysicalDeviceFeatures(Device, &DeviceFeatures); - - int Score = 0; - - if (DeviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) - { - Score += 100; - } - - Score += DeviceProperties.limits.maxImageDimension2D; - - if (!DeviceFeatures.geometryShader) - { - return 0; - } - - return Score; -} - -bool VulkanDeviceManager::CheckDeviceExtensionSupport(VkPhysicalDevice Device) -{ - uint32_t ExtensionCount; - vkEnumerateDeviceExtensionProperties(Device, nullptr, &ExtensionCount, nullptr); - - std::vector AvailableExtensions(ExtensionCount); - vkEnumerateDeviceExtensionProperties(Device, nullptr, &ExtensionCount, AvailableExtensions.data()); - - std::set RequiredExtensions(DeviceExtensions.begin(), DeviceExtensions.end()); - - for (const auto& Extension : AvailableExtensions) - { - RequiredExtensions.erase(Extension.extensionName); - } - - return RequiredExtensions.empty(); -} - -QueueFamilyIndices VulkanDeviceManager::FindQueueFamilies(VkPhysicalDevice Device) -{ - QueueFamilyIndices Indices; - - uint32_t QueueFamilyCount = 0; - vkGetPhysicalDeviceQueueFamilyProperties(Device, &QueueFamilyCount, nullptr); - - std::vector QueueFamilies(QueueFamilyCount); - vkGetPhysicalDeviceQueueFamilyProperties(Device, &QueueFamilyCount, QueueFamilies.data()); - - int i = 0; - for (const auto& QueueFamily : QueueFamilies) - { - if (QueueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT) - { - Indices.GraphicsFamily = i; - } - - VkBool32 PresentSupport = false; - vkGetPhysicalDeviceSurfaceSupportKHR(Device, i, GlfwWindowManager::Surface, &PresentSupport); - - if (PresentSupport) - { - Indices.PresentFamily = i; - } - if (Indices.IsComplete()) - { - break; - } - - i++; - } - - return Indices; -} - -void VulkanDeviceManager::CreateLogicalDevice() -{ - QueueFamilyIndices Indices = FindQueueFamilies(PhysicalDevice); - - std::vector QueueCreateInfos; - std::set UniqueQueueFamilies = { Indices.GraphicsFamily.value(), Indices.PresentFamily.value() }; - - float QueuePriority = 1.0f; - for (uint32_t QueueFamily : UniqueQueueFamilies) - { - VkDeviceQueueCreateInfo QueueCreateInfo{}; - QueueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; - QueueCreateInfo.queueFamilyIndex = Indices.GraphicsFamily.value(); - QueueCreateInfo.queueCount = 1; - QueueCreateInfo.pQueuePriorities = &QueuePriority; - QueueCreateInfos.push_back(QueueCreateInfo); - } - - VkPhysicalDeviceFeatures DeviceFeatures{}; - - VkDeviceCreateInfo CreateInfo{}; - CreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; - CreateInfo.queueCreateInfoCount = static_cast(QueueCreateInfos.size()); - CreateInfo.pQueueCreateInfos = QueueCreateInfos.data(); - CreateInfo.pEnabledFeatures = &DeviceFeatures; - - CreateInfo.enabledExtensionCount = static_cast(DeviceExtensions.size()); - CreateInfo.ppEnabledExtensionNames = DeviceExtensions.data(); - - if (bEnableValidationLayers) - { - CreateInfo.enabledLayerCount = static_cast(ValidationLayers->size()); - CreateInfo.ppEnabledLayerNames = ValidationLayers->data(); - } - else - { - CreateInfo.enabledLayerCount = 0; - } - - if (vkCreateDevice(PhysicalDevice, &CreateInfo, nullptr, &Device) != VK_SUCCESS) - { - Log::Error("Failed to create logical device!"); - } - - vkGetDeviceQueue(Device, Indices.GraphicsFamily.value(), 0, &GraphicsQueue); - vkGetDeviceQueue(Device, Indices.PresentFamily.value(), 0, &PresentQueue); -} - -SwapChainSupportDetails VulkanDeviceManager::QuerySwapChainSupport(VkPhysicalDevice Device) -{ - SwapChainSupportDetails Details; - - vkGetPhysicalDeviceSurfaceCapabilitiesKHR(Device, GlfwWindowManager::Surface, &Details.Capabilities); - - uint32_t FormatCount; - vkGetPhysicalDeviceSurfaceFormatsKHR(Device, GlfwWindowManager::Surface, &FormatCount, nullptr); - - if (FormatCount != 0) - { - Details.Formats.resize(FormatCount); - vkGetPhysicalDeviceSurfaceFormatsKHR(Device, GlfwWindowManager::Surface, &FormatCount, Details.Formats.data()); - } - - uint32_t PresentModeCount; - vkGetPhysicalDeviceSurfacePresentModesKHR(Device, GlfwWindowManager::Surface, &PresentModeCount, nullptr); - - if (PresentModeCount != 0) - { - Details.PresentModes.resize(PresentModeCount); - vkGetPhysicalDeviceSurfacePresentModesKHR(Device, GlfwWindowManager::Surface, &PresentModeCount, Details.PresentModes.data()); - } - - return Details; -} - -VkSurfaceFormatKHR VulkanDeviceManager::ChooseSwapSurfaceFormat(const std::vector& AvailableFormats) -{ - for (const auto& AvailableFormat : AvailableFormats) - { - if (AvailableFormat.format == VK_FORMAT_B8G8R8A8_SRGB && AvailableFormat.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) - { - return AvailableFormat; - } - } - return AvailableFormats[0]; -} - -VkPresentModeKHR VulkanDeviceManager::ChooseSwapPresentMode(const std::vector& AvailablePresentModes) -{ - for (const auto& AvailablePresentMode : AvailablePresentModes) - { - if (AvailablePresentMode == VK_PRESENT_MODE_MAILBOX_KHR) - { - return AvailablePresentMode; - } - } - return VK_PRESENT_MODE_FIFO_KHR; -} - -VkExtent2D VulkanDeviceManager::ChooseSwapExtent(const VkSurfaceCapabilitiesKHR& Capabilities) -{ - if (Capabilities.currentExtent.width != (std::numeric_limits::max)()) - { - return Capabilities.currentExtent; - } - else - { - int Width, Height; - glfwGetFramebufferSize(GlfwWindowManager::Window, &Width, &Height); - - VkExtent2D ActualExtent = { - static_cast(Width), - static_cast(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; - } -} - -void VulkanDeviceManager::CreateSwapChain() -{ - SwapChainSupportDetails SwapChainSupport = QuerySwapChainSupport(PhysicalDevice); - - VkSurfaceFormatKHR SurfaceFormat = ChooseSwapSurfaceFormat(SwapChainSupport.Formats); - VkPresentModeKHR PresentMode = ChooseSwapPresentMode(SwapChainSupport.PresentModes); - VkExtent2D Extent = ChooseSwapExtent(SwapChainSupport.Capabilities); - - uint32_t ImageCount = SwapChainSupport.Capabilities.minImageCount + 1; - - if (SwapChainSupport.Capabilities.maxImageCount > 0 && ImageCount > SwapChainSupport.Capabilities.maxImageCount) - { - ImageCount = SwapChainSupport.Capabilities.maxImageCount; - } - - VkSwapchainCreateInfoKHR CreateInfo{}; - CreateInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; - CreateInfo.surface = GlfwWindowManager::Surface; - - CreateInfo.minImageCount = ImageCount; - CreateInfo.imageFormat = SurfaceFormat.format; - CreateInfo.imageColorSpace = SurfaceFormat.colorSpace; - CreateInfo.imageExtent = Extent; - CreateInfo.imageArrayLayers = 1; - CreateInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; // may need VK_IMAGE_USAGE_TRANSFER_DST_BIT for post processing https://vulkan-tutorial.com/Drawing_a_triangle/Presentation/Swap_chain#:~:text=VK%5FIMAGE%5FUSAGE%5FTRANSFER%5FDST%5FBIT - - QueueFamilyIndices Indices = FindQueueFamilies(PhysicalDevice); - uint32_t QueueFamilyIndices[] = { Indices.GraphicsFamily.value(), - Indices.PresentFamily.value() }; - - if (Indices.GraphicsFamily != Indices.PresentFamily) - { - CreateInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT; - CreateInfo.queueFamilyIndexCount = 2; - CreateInfo.pQueueFamilyIndices = QueueFamilyIndices; - } - else - { - CreateInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; - CreateInfo.queueFamilyIndexCount = 0; - CreateInfo.pQueueFamilyIndices = nullptr; - } - - CreateInfo.preTransform = SwapChainSupport.Capabilities.currentTransform; - CreateInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; - CreateInfo.presentMode = PresentMode; - CreateInfo.clipped = VK_TRUE; - CreateInfo.oldSwapchain = VK_NULL_HANDLE; - - if (vkCreateSwapchainKHR(Device, &CreateInfo, nullptr, &SwapChain) != VK_SUCCESS) - { - Log::Error("Failed to create swap chain."); - } - else - { - Log::Info("Successfully created swap chain."); - } - - vkGetSwapchainImagesKHR(Device, SwapChain, &ImageCount, nullptr); - SwapChainImages.resize(ImageCount); - vkGetSwapchainImagesKHR(Device, SwapChain, &ImageCount, SwapChainImages.data()); - - SwapChainImageFormat = SurfaceFormat.format; - SwapChainExtent = Extent; -} - -void VulkanDeviceManager::CreateImageViews() -{ - SwapChainImageViews.resize(SwapChainImages.size()); - - int CreatedViews = 0; - for (size_t i = 0; i < SwapChainImages.size(); i++) - { - VkImageViewCreateInfo CreateInfo{}; - CreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - CreateInfo.image = SwapChainImages[i]; - - CreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; - CreateInfo.format = SwapChainImageFormat; - CreateInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY; - CreateInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY; - CreateInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY; - CreateInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY; - - CreateInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - CreateInfo.subresourceRange.baseMipLevel = 0; - CreateInfo.subresourceRange.levelCount = 1; - CreateInfo.subresourceRange.baseArrayLayer = 0; - CreateInfo.subresourceRange.layerCount = 1; - - if (vkCreateImageView(Device, &CreateInfo, nullptr, &SwapChainImageViews[i]) != VK_SUCCESS) - { - Log::Error("Failed to create image views."); - } - else - { - CreatedViews++; - } - } - - Log::Info("Successfully created " + std::to_string(CreatedViews) + " image views."); -} \ No newline at end of file diff --git a/src/VulkanDeviceManager.h b/src/VulkanDeviceManager.h deleted file mode 100644 index c47ac5a..0000000 --- a/src/VulkanDeviceManager.h +++ /dev/null @@ -1,101 +0,0 @@ -#pragma once - -#include -#include -#include - -#include "Logger.h" - -#define GLFW_INCLUDE_VULKAN -#include - -const std::vector DeviceExtensions = { - VK_KHR_SWAPCHAIN_EXTENSION_NAME -}; - -struct QueueFamilyIndices -{ - std::optional GraphicsFamily; - std::optional PresentFamily; - - bool IsComplete() - { - return GraphicsFamily.has_value() && PresentFamily.has_value(); - } -}; - -struct SwapChainSupportDetails -{ - VkSurfaceCapabilitiesKHR Capabilities; - std::vector Formats; - std::vector PresentModes; -}; - -class VulkanDeviceManager -{ -public: - VulkanDeviceManager(); - ~VulkanDeviceManager(); - - VulkanDeviceManager(const VulkanDeviceManager&) = delete; - VulkanDeviceManager& operator=(const VulkanDeviceManager&) = delete; - - VulkanDeviceManager(VulkanDeviceManager&& Other) noexcept; - VulkanDeviceManager& operator=(VulkanDeviceManager&& Other) noexcept; - - void Initialize( - VkInstance Instance, - bool EnableValidationLayers, - const std::vector& ValidationLayers); - - void Cleanup(); - - bool IsInitialized() const - { - bool bInitialized = PhysicalDevice && Device && Instance && GraphicsQueue; - return bInitialized; - } - - static std::vector SwapChainImages; - -private: - VkPhysicalDevice PhysicalDevice = VK_NULL_HANDLE; - VkInstance Instance = VK_NULL_HANDLE; - VkDevice Device = VK_NULL_HANDLE; - VkQueue GraphicsQueue = VK_NULL_HANDLE; - VkQueue PresentQueue = VK_NULL_HANDLE; - - VkSwapchainKHR SwapChain = VK_NULL_HANDLE; - VkFormat SwapChainImageFormat; - VkExtent2D SwapChainExtent; - - std::vector SwapChainImageViews; - - bool bEnableValidationLayers = false; - - const std::vector* ValidationLayers = nullptr; - - void PickPhysicalDevice(); - - bool IsDeviceSuitable(VkPhysicalDevice Device); - - int RateDeviceSuitability(VkPhysicalDevice Device); - - bool CheckDeviceExtensionSupport(VkPhysicalDevice Device); - - QueueFamilyIndices FindQueueFamilies(VkPhysicalDevice Device); - - void CreateLogicalDevice(); - - SwapChainSupportDetails QuerySwapChainSupport(VkPhysicalDevice Device); - - VkSurfaceFormatKHR ChooseSwapSurfaceFormat(const std::vector& AvailableFormats); - - VkPresentModeKHR ChooseSwapPresentMode(const std::vector& AvailablePresentModes); - - VkExtent2D ChooseSwapExtent(const VkSurfaceCapabilitiesKHR& Capabilities); - - void CreateSwapChain(); - - void CreateImageViews(); -}; diff --git a/src/VulkanGraphicsPipeline.h b/src/VulkanGraphicsPipeline.h deleted file mode 100644 index c98e9e7..0000000 --- a/src/VulkanGraphicsPipeline.h +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once - -#include "FileReader.h" -#include "vulkan_core.h" - -class VulkanGraphicsPipeline -{ -public: - void CreateGraphicsPipeline() - { - auto VertShaderCode = ReadFile("Shaders/vert.spv"); - auto FragShaderCode = ReadFile("Shaders/frag.spv"); - - Log::Info("Vert buffer size: " + std::to_string(VertShaderCode.size())); - Log::Info("Frag buffer size: " + std::to_string(FragShaderCode.size())); - } - - VkShaderModule CreateShaderModule(const std::vector& Code) - { - VkShaderModuleCreateInfo CreateInfo{}; - CreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; - CreateInfo.codeSize = Code.size(); - CreateInfo.pCode = reinterpret_cast(Code.data()); - - VkShaderModule ShaderModule; - // if (vkCreateShaderModule(Device)) - return ShaderModule; - } - }; diff --git a/src/VulkanInstanceManager.h b/src/VulkanInstanceManager.h deleted file mode 100644 index 5aa9cc4..0000000 --- a/src/VulkanInstanceManager.h +++ /dev/null @@ -1,67 +0,0 @@ -#pragma once - -#include -#include - -#include "Logger.h" -#include "VulkanDebugManager.h" -#include "VulkanDeviceManager.h" -#include "GlfwWindowManager.h" - -#define GLFW_INCLUDE_VULKAN -#include - -const std::vector ValidationLayers = { - "VK_LAYER_KHRONOS_validation" -}; - -struct FVulkanConfig -{ - bool bValidationEnabled = true; - bool bVerboseLogging = false; -}; - -class VulkanInstanceManager -{ -public: - VulkanInstanceManager(); - ~VulkanInstanceManager(); - - VulkanInstanceManager(const VulkanInstanceManager&) = delete; - VulkanInstanceManager& operator=(const VulkanInstanceManager&) = delete; - - VulkanInstanceManager(VulkanInstanceManager&& Other) noexcept; - VulkanInstanceManager& operator=(VulkanInstanceManager&& Other) noexcept; - - // void Initialize(const FVulkanConfig& Config); - void Initialize(bool bEnableValidationLayers); - void SetupDebug(); - void SetupDevice(); - - // void Initialize(VulkanDebugManager& inDebugManager, bool inValidationEnabled); - void Cleanup(); - - bool IsInitialized() const { return Instance != VK_NULL_HANDLE; } - - const std::vector& GetValidationLayers() const - { - return ValidationLayers; - } - - const VkInstance GetInstance() const { return Instance; } - -private: - std::unique_ptr VkDebugManager = nullptr; - std::unique_ptr VkDeviceManager = nullptr; - - bool bValidationEnabled = false; - bool bVerboseLogging = false; - - VkInstance Instance = VK_NULL_HANDLE; - - std::vector GetRequiredExtensions(); - - bool CheckValidationLayerSupport(); - - void CreateInstance(); -}; diff --git a/src/main.cpp b/src/main.cpp old mode 100644 new mode 100755 index 326f4eb..f70db02 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,27 +1,27 @@ -#include "Logger.h" -#include "VulkanInstanceManager.h" -#include "VulkanDeviceManager.h" -#include "VulkanDebugManager.h" +#include +#include + +#include "utilities/Logger.h" #include "GlfwWindowManager.h" -#include "VulkanGraphicsPipeline.h" -// #include "VulkanContext.h" +#include "VulkanContext.h" struct AppConfig { std::string Title = "Learning Vulkan"; uint32_t Width = 800; uint32_t Height = 600; - bool bResizable = false; + bool bResizable = true; bool bFullscreen = false; - bool bValidationEnabled = true; + bool bValidationEnabled = false; bool bVerboseLogging = false; }; -void test () { - if (true) return; - -} +const std::vector TriangleVertices = { + { { 0.0f, -0.5f }, { 1.0f, 1.0f, 1.0f } }, + { { 0.5f, 0.5f }, { 0.0f, 1.0f, 0.0f } }, + { { -0.5f, 0.5f }, { 0.0f, 0.0f, 1.0f } } +}; class HelloTriangleApplication { @@ -29,6 +29,7 @@ public: void Run() { Initialization(); + Log::Info("Initialization finished..."); MainLoop(); Cleanup(); } @@ -36,25 +37,24 @@ public: private: AppConfig Settings = {}; - VulkanInstanceManager InstanceManager; - GlfwWindowManager WindowManager; + GlfwWindowManager WindowManager; + VulkanContext VkContext; void Initialization() { InitGlfw(); InitVulkan(); - InstanceManager.SetupDebug(); - WindowManager.CreateSurface(InstanceManager.GetInstance()); - InstanceManager.SetupDevice(); } void InitVulkan() { FVulkanConfig Config = { Settings.bValidationEnabled, - Settings.bVerboseLogging + Settings.bVerboseLogging, + WindowManager.GetWindow(), + TriangleVertices }; - InstanceManager.Initialize(Config); + VkContext.Initialize(Config); } void InitGlfw() @@ -67,6 +67,20 @@ private: Settings.bFullscreen }; WindowManager.Initialize(Config); + + glfwSetWindowUserPointer(WindowManager.GetWindow(), this); + glfwSetFramebufferSizeCallback(WindowManager.GetWindow(), FramebufferResizeCallback); + } + + static void FramebufferResizeCallback(GLFWwindow* Window, int Width, int Height) + { + auto App = reinterpret_cast(glfwGetWindowUserPointer(Window)); + App->VkContext.SetFramebufferResized(true); + } + + void DrawFrame() + { + VkContext.DrawFrame(); } void MainLoop() @@ -74,13 +88,15 @@ private: while (!WindowManager.ShouldClose()) { WindowManager.PollEvents(); + DrawFrame(); } } void Cleanup() { - WindowManager.Cleanup(InstanceManager.GetInstance()); - InstanceManager.Cleanup(); + Log::Info("Cleaning up..."); + VkContext.Cleanup(); + WindowManager.Cleanup(); } }; diff --git a/src/GlfwWindowManager.cpp b/src/private/GlfwWindowManager.cpp old mode 100644 new mode 100755 similarity index 55% rename from src/GlfwWindowManager.cpp rename to src/private/GlfwWindowManager.cpp index d4c1a26..b84b642 --- a/src/GlfwWindowManager.cpp +++ b/src/private/GlfwWindowManager.cpp @@ -1,41 +1,15 @@ #include "GlfwWindowManager.h" -#include +#include "utilities/Logger.h" -#include "Logger.h" - -VkSurfaceKHR GlfwWindowManager::Surface = VK_NULL_HANDLE; -GLFWwindow* GlfwWindowManager::Window = nullptr; - -GlfwWindowManager::GlfwWindowManager() = default; +GlfwWindowManager::GlfwWindowManager() +{ +} GlfwWindowManager::~GlfwWindowManager() { - // Cleanup(); } -// GlfwWindowManager::GlfwWindowManager(GlfwWindowManager&& Other) noexcept -// : Window(Other.Window), Config(Other.Config), Surface(Other.Surface) -//{ -// Other.Window = nullptr; -// } -// -// GlfwWindowManager& GlfwWindowManager::operator=(GlfwWindowManager&& Other) noexcept -//{ -// if (this != &Other) -// { -// Cleanup(); -// -// Window = Other.Window; -// Config = Other.Config; -// Surface = Other.Surface; -// -// Other.Window = nullptr; -// } -// -// return *this; -// } - void GlfwWindowManager::Initialize(const FWindowConfig& Config) { if (IsInitialized()) @@ -48,7 +22,7 @@ void GlfwWindowManager::Initialize(const FWindowConfig& Config) InitializeGlfw(); } -void GlfwWindowManager::Cleanup(VkInstance Instance) +void GlfwWindowManager::Cleanup() { if (!IsInitialized()) { @@ -92,46 +66,6 @@ void GlfwWindowManager::SetTitle(const std::string& Title) } } -void GlfwWindowManager::CreateSurface(VkInstance Instance) -{ - if (!Window) - { - Log::Error("Window not initialized."); - } - - if (!Instance) - { - Log::Error("Instance is null."); - } - - VkResult result = glfwCreateWindowSurface(Instance, Window, nullptr, &Surface); - if (result != VK_SUCCESS) - { - std::string errorMsg; - switch (result) - { - case VK_ERROR_EXTENSION_NOT_PRESENT: - errorMsg = "VK_ERROR_EXTENSION_NOT_PRESENT - Required extension not present"; - break; - case VK_ERROR_INITIALIZATION_FAILED: - errorMsg = "VK_ERROR_INITIALIZATION_FAILED - Initialization failed"; - break; - case VK_ERROR_NATIVE_WINDOW_IN_USE_KHR: - errorMsg = "VK_ERROR_NATIVE_WINDOW_IN_USE_KHR - Native window already in use"; - break; - default: - errorMsg = "Unknown error code: " + std::to_string(result); - break; - } - - Log::Error("Failed to create window surface: " + errorMsg); - } - else - { - Log::Info("Window surface created successfully."); - } -} - void GlfwWindowManager::SetResizeCallback(GLFWwindowsizefun Callback) { if (Window) @@ -191,8 +125,16 @@ void GlfwWindowManager::InitializeGlfw() } } + glfwWindowHint(GLFW_CONTEXT_CREATION_API, GLFW_NATIVE_CONTEXT_API); glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_RESIZABLE, Config.bResizable ? GLFW_TRUE : GLFW_FALSE); + glfwWindowHint(GLFW_VISIBLE, GLFW_TRUE); + glfwWindowHint(GLFW_DECORATED, GLFW_TRUE); + glfwWindowHint(GLFW_FOCUSED, GLFW_TRUE); + glfwWindowHint(GLFW_AUTO_ICONIFY, GLFW_FALSE); + glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); + + glfwWindowHintString(GLFW_WAYLAND_APP_ID, Config.Title.c_str()); Window = glfwCreateWindow( Config.Width, @@ -209,4 +151,13 @@ void GlfwWindowManager::InitializeGlfw() { Log::Info("Created GLFW window successfully."); } + + glfwSetWindowSize(Window, Config.Width, Config.Height); + const GLFWvidmode* mode = glfwGetVideoMode(glfwGetPrimaryMonitor()); + if (mode) + { + int xPos = (mode->width - Config.Width) / 2; + int yPos = (mode->height - Config.Height) / 2; + glfwSetWindowPos(Window, xPos, yPos); + } } diff --git a/src/private/VulkanCommandBuffers.cpp b/src/private/VulkanCommandBuffers.cpp new file mode 100644 index 0000000..9368bca --- /dev/null +++ b/src/private/VulkanCommandBuffers.cpp @@ -0,0 +1,125 @@ +#include "VulkanCommandBuffers.h" + +#include "utilities/Logger.h" +#include +#include + +void VulkanCommandBuffers::Initialize( + VkDevice InDevice, + VkRenderPass InRenderPass) +{ + Device = InDevice; + RenderPass = InRenderPass; +} + +void VulkanCommandBuffers::Cleanup() +{ + vkDestroyCommandPool(Device, CommandPool, nullptr); +} + +void VulkanCommandBuffers::CreateCommandPool(std::optional GraphicsFamily) +{ + VkCommandPoolCreateInfo PoolInfo{}; + PoolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; + PoolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; + PoolInfo.queueFamilyIndex = GraphicsFamily.value(); + + if (vkCreateCommandPool(Device, &PoolInfo, nullptr, &CommandPool) != VK_SUCCESS) + { + Log::Error("Failed to create command pool!"); + } + else + { + Log::Info("Successfully created command pool"); + } +} + +void VulkanCommandBuffers::CreateCommandBuffers(int FramesInFlight) +{ + CommandBuffers.resize(FramesInFlight); + VkCommandBufferAllocateInfo AllocateInfo{}; + AllocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + AllocateInfo.commandPool = CommandPool; + AllocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + AllocateInfo.commandBufferCount = (uint32_t)CommandBuffers.size(); + + if (vkAllocateCommandBuffers(Device, &AllocateInfo, CommandBuffers.data()) != VK_SUCCESS) + { + Log::Error("Failed to allocate command buffers!"); + } + else + { + Log::Info("Successfully allocated command buffers."); + } +} + +void VulkanCommandBuffers::RecordCommandBuffer( + VkCommandBuffer InCommandBuffer, + uint32_t ImageIndex, + VkBuffer InVertexBuffer, + std::vector InVertices, + VkRenderPass RenderPass, + VkExtent2D SwapChainExtent, + VkPipeline GraphicsPipeline, + std::vector SwapChainFramebuffers) +{ + VkCommandBufferBeginInfo BeginInfo{}; + BeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + BeginInfo.flags = 0; + BeginInfo.pInheritanceInfo = nullptr; + + if (vkBeginCommandBuffer(InCommandBuffer, &BeginInfo) != VK_SUCCESS) + { + Log::Error("Failed to begin recording command buffer!"); + } + else + { + // Log::Info("Successfully began recording command buffers."); + } + + VkRenderPassBeginInfo RenderPassInfo{}; + RenderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; + RenderPassInfo.renderPass = RenderPass; + RenderPassInfo.framebuffer = SwapChainFramebuffers[ImageIndex]; + RenderPassInfo.renderArea.offset = { 0, 0 }; + RenderPassInfo.renderArea.extent = { SwapChainExtent }; + + VkClearValue ClearColor = { { { 0.0f, 0.0f, 0.0f, 1.0f } } }; + RenderPassInfo.clearValueCount = 1; + RenderPassInfo.pClearValues = &ClearColor; + + vkCmdBeginRenderPass(InCommandBuffer, &RenderPassInfo, VK_SUBPASS_CONTENTS_INLINE); + + vkCmdBindPipeline(InCommandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, GraphicsPipeline); + + VkViewport Viewport{}; + Viewport.x = 0.0f; + Viewport.y = 0.0f; + Viewport.width = static_cast(SwapChainExtent.width); + Viewport.height = static_cast(SwapChainExtent.height); + Viewport.minDepth = 0.0f; + Viewport.maxDepth = 1.0f; + vkCmdSetViewport(InCommandBuffer, 0, 1, &Viewport); + + VkRect2D Scissor{}; + Scissor.offset = { 0, 0 }; + Scissor.extent = SwapChainExtent; + vkCmdSetScissor(InCommandBuffer, 0, 1, &Scissor); + + VkBuffer VertexBuffers[] = { InVertexBuffer }; + VkDeviceSize Offsets[] = { 0 }; + vkCmdBindVertexBuffers(InCommandBuffer, 0, 1, VertexBuffers, Offsets); + + vkCmdDraw(InCommandBuffer, static_cast(InVertices.size()), 1, 0, 0); + + vkCmdEndRenderPass(InCommandBuffer); + + if (vkEndCommandBuffer(InCommandBuffer) != VK_SUCCESS) + { + Log::Error("Failed to record command buffer!"); + } + else + { + // Log::Info("Successfully recorded command buffer."); + } +} diff --git a/src/private/VulkanContext.cpp b/src/private/VulkanContext.cpp new file mode 100755 index 0000000..fa73a86 --- /dev/null +++ b/src/private/VulkanContext.cpp @@ -0,0 +1,287 @@ +#include "VulkanContext.h" +#include "VulkanDeviceManager.h" +#include "VulkanFramebuffers.h" +#include "VulkanSwapChain.h" +#include "VulkanVertexBuffer.h" +#include "utilities/Logger.h" +#include +#include +#include + +VulkanContext::VulkanContext() +{ +} + +VulkanContext::~VulkanContext() +{ +} + +void VulkanContext::Initialize(FVulkanConfig& InConfig) +{ + Config = InConfig; + + if (Config.bValidationEnabled) + { + InstanceManager.CreateInstance(&DebugManager); + DebugManager.Initialize(InstanceManager.GetInstance()); + } + else + { + InstanceManager.CreateInstance(); + } + + CreateSurface(InConfig.Window); + + DeviceManager.Initialize(FDeviceConfig( + InstanceManager.GetInstance(), + Config.bValidationEnabled, + Surface, + InConfig.Window)); + DeviceManager.PickPhysicalDevice(); + DeviceManager.CreateLogicalDevice(); + + SwapChain.Initialize(FSwapConfig( + DeviceManager.GetDevice(), + Surface, + Config.Window, + DeviceManager.GetPhysicalQueueFamilies().GraphicsFamily, + DeviceManager.GetPhysicalQueueFamilies().PresentFamily, + DeviceManager.GetSwapChainSupport().Capabilities, + DeviceManager.GetSwapChainSupport().Formats, + DeviceManager.GetSwapChainSupport().PresentModes)); + SwapChain.CreateSwapChain(); + SwapChain.CreateImageViews(); + + RenderPass.Initialize(DeviceManager.GetDevice()); + RenderPass.CreateRenderPass(SwapChain.GetSwapChainImageFormat()); + + GraphicsPipeline.Initialize(DeviceManager.GetDevice()); + GraphicsPipeline.CreateGraphicsPipeline(SwapChain.GetSwapChainExtent(), RenderPass.GetRenderPass()); + + Framebuffers.Initialize(FFramebufferConfig( + DeviceManager.GetDevice(), + RenderPass.GetRenderPass(), + SwapChain.GetSwapChainImageViews(), + SwapChain.GetSwapChainExtent())); + Framebuffers.CreateFramebuffers(); + + CommandBuffers.Initialize(DeviceManager.GetDevice(), RenderPass.GetRenderPass()); + CommandBuffers.CreateCommandPool(DeviceManager.GetPhysicalQueueFamilies().GraphicsFamily); + + VertexBuffer.Initialize(FVertexBufferConfig(DeviceManager.GetDevice(), DeviceManager.GetPhysicalDevice())); + VertexBuffer.CreateVertexBuffer(Config.Vertices); + + CommandBuffers.CreateCommandBuffers(MAX_FRAMES_IN_FLIGHT); + + CreateSyncObjects(); +} + +void VulkanContext::Cleanup() +{ + CleanupSwapChain(); + + VertexBuffer.Cleanup(); + + GraphicsPipeline.Cleanup(); + RenderPass.Cleanup(); + + for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) + { + vkDestroySemaphore(DeviceManager.GetDevice(), ImageAvailableSemaphores[i], nullptr); + vkDestroySemaphore(DeviceManager.GetDevice(), RenderFinishedSemaphores[i], nullptr); + vkDestroyFence(DeviceManager.GetDevice(), InFlightFences[i], nullptr); + } + + CommandBuffers.Cleanup(); + + DeviceManager.Cleanup(); + + if (Config.bValidationEnabled) + { + DebugManager.Cleanup(); + } + + vkDestroySurfaceKHR(InstanceManager.GetInstance(), Surface, nullptr); + InstanceManager.Cleanup(); +} + +void VulkanContext::CreateSurface(GLFWwindow* Window) +{ + if (!Window) + { + Log::Error("Window not initialized."); + } + + if (!InstanceManager.GetInstance()) + { + Log::Error("Instance is null."); + } + + VkResult result = glfwCreateWindowSurface(InstanceManager.GetInstance(), Window, nullptr, &Surface); + if (result != VK_SUCCESS) + { + std::string errorMsg; + switch (result) + { + case VK_ERROR_EXTENSION_NOT_PRESENT: + errorMsg = "VK_ERROR_EXTENSION_NOT_PRESENT - Required extension not present"; + break; + case VK_ERROR_INITIALIZATION_FAILED: + errorMsg = "VK_ERROR_INITIALIZATION_FAILED - Initialization failed"; + break; + case VK_ERROR_NATIVE_WINDOW_IN_USE_KHR: + errorMsg = "VK_ERROR_NATIVE_WINDOW_IN_USE_KHR - Native window already in use"; + break; + default: + errorMsg = "Unknown error code: " + std::to_string(result); + break; + } + + Log::Error("Failed to create window surface: " + errorMsg); + } + else + { + Log::Info("Window surface created successfully."); + } +} + +void VulkanContext::CreateSyncObjects() +{ + ImageAvailableSemaphores.resize(MAX_FRAMES_IN_FLIGHT); + RenderFinishedSemaphores.resize(MAX_FRAMES_IN_FLIGHT); + InFlightFences.resize(MAX_FRAMES_IN_FLIGHT); + + VkSemaphoreCreateInfo SemaphoreInfo{}; + SemaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; + + VkFenceCreateInfo FenceInfo{}; + FenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; + FenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT; + + for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) + { + if (vkCreateSemaphore(DeviceManager.GetDevice(), &SemaphoreInfo, nullptr, &ImageAvailableSemaphores[i]) != VK_SUCCESS + || vkCreateSemaphore(DeviceManager.GetDevice(), &SemaphoreInfo, nullptr, &RenderFinishedSemaphores[i]) != VK_SUCCESS + || vkCreateFence(DeviceManager.GetDevice(), &FenceInfo, nullptr, &InFlightFences[i]) != VK_SUCCESS) + { + Log::Error("Failed to create semaphores!"); + } + else + { + Log::Info("Successfully created semaphores"); + } + } +} + +void VulkanContext::DrawFrame() +{ + vkWaitForFences(DeviceManager.GetDevice(), 1, &InFlightFences[CurrentFrame], VK_TRUE, UINT64_MAX); + + uint32_t ImageIndex; + VkResult result = vkAcquireNextImageKHR( + DeviceManager.GetDevice(), + SwapChain.GetSwapChain(), + UINT64_MAX, + ImageAvailableSemaphores[CurrentFrame], + VK_NULL_HANDLE, + &ImageIndex); + + if (result == VK_ERROR_OUT_OF_DATE_KHR) + { + RecreateSwapChain(); + return; + } + else if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR) + { + Log::Error("Failed to acquire swap chain images!"); + } + + vkResetFences(DeviceManager.GetDevice(), 1, &InFlightFences[CurrentFrame]); + + vkAcquireNextImageKHR(DeviceManager.GetDevice(), SwapChain.GetSwapChain(), UINT64_MAX, ImageAvailableSemaphores[CurrentFrame], VK_NULL_HANDLE, &ImageIndex); + + vkResetCommandBuffer(CommandBuffers.GetCommandBuffer(CurrentFrame), 0); + CommandBuffers.RecordCommandBuffer( + CommandBuffers.GetCommandBuffer(CurrentFrame), + ImageIndex, + VertexBuffer.GetVertexBuffer(), + Config.Vertices, + RenderPass.GetRenderPass(), + SwapChain.GetSwapChainExtent(), + GraphicsPipeline.GetGraphicsPipeline(), + Framebuffers.GetSwapChainFrameBuffers()); + + VkSubmitInfo SubmitInfo{}; + SubmitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + + VkSemaphore WaitSemaphores[] = { ImageAvailableSemaphores[CurrentFrame] }; + VkPipelineStageFlags WaitStages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT }; + SubmitInfo.waitSemaphoreCount = 1; + SubmitInfo.pWaitSemaphores = WaitSemaphores; + SubmitInfo.pWaitDstStageMask = WaitStages; + + SubmitInfo.commandBufferCount = 1; + VkCommandBuffer CommandBuffer = CommandBuffers.GetCommandBuffer(CurrentFrame); + SubmitInfo.pCommandBuffers = &CommandBuffer; + + VkSemaphore SignalSemaphores[] = { RenderFinishedSemaphores[CurrentFrame] }; + SubmitInfo.signalSemaphoreCount = 1; + SubmitInfo.pSignalSemaphores = SignalSemaphores; + + if (vkQueueSubmit(DeviceManager.GetGraphicsQueue(), 1, &SubmitInfo, InFlightFences[CurrentFrame]) != VK_SUCCESS) + { + Log::Error("Failed to submit draw command buffer!"); + } + + VkPresentInfoKHR PresentInfo{}; + PresentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; + PresentInfo.waitSemaphoreCount = 1; + PresentInfo.pWaitSemaphores = SignalSemaphores; + + VkSwapchainKHR SwapChains[] = { SwapChain.GetSwapChain() }; + + PresentInfo.swapchainCount = 1; + PresentInfo.pSwapchains = SwapChains; + PresentInfo.pImageIndices = &ImageIndex; + PresentInfo.pResults = nullptr; + + result = vkQueuePresentKHR(DeviceManager.GetPresentQueue(), &PresentInfo); + + if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || bFramebufferResized) + { + bFramebufferResized = false; + RecreateSwapChain(); + } + else if (result != VK_SUCCESS) + { + Log::Error("Failed to present swap chain image!"); + } + + CurrentFrame = (CurrentFrame + 1) % MAX_FRAMES_IN_FLIGHT; +} + +void VulkanContext::RecreateSwapChain() +{ + int Width = 0, Height = 0; + glfwGetFramebufferSize(Config.Window, &Width, &Height); + while (Width == 0 || Height == 0) + { + glfwGetFramebufferSize(Config.Window, &Width, &Height); + glfwWaitEvents(); + } + + Log::Info("Recreating SwapChain..."); + vkDeviceWaitIdle(DeviceManager.GetDevice()); + + CleanupSwapChain(); + + SwapChain.CreateSwapChain(); + SwapChain.CreateImageViews(); + Framebuffers.CreateFramebuffers(); +} + +void VulkanContext::CleanupSwapChain() +{ + Framebuffers.Cleanup(); + SwapChain.Cleanup(); +} diff --git a/src/VulkanDebugManager.cpp b/src/private/VulkanDebugManager.cpp old mode 100644 new mode 100755 similarity index 70% rename from src/VulkanDebugManager.cpp rename to src/private/VulkanDebugManager.cpp index 4ccd94c..0cfd9ae --- a/src/VulkanDebugManager.cpp +++ b/src/private/VulkanDebugManager.cpp @@ -1,5 +1,5 @@ #include "VulkanDebugManager.h" -#include "Logger.h" +#include "utilities/Logger.h" VulkanDebugManager::VulkanDebugManager() { @@ -7,28 +7,6 @@ VulkanDebugManager::VulkanDebugManager() VulkanDebugManager::~VulkanDebugManager() { - // Cleanup(); -} - -VulkanDebugManager::VulkanDebugManager(VulkanDebugManager&& Other) noexcept - : DebugMessenger(Other.DebugMessenger), Instance(Other.Instance) -{ - Other.DebugMessenger = VK_NULL_HANDLE; - Other.Instance = VK_NULL_HANDLE; -} - -VulkanDebugManager& VulkanDebugManager::operator=(VulkanDebugManager&& Other) noexcept -{ - if (this != &Other) - { - Cleanup(); - DebugMessenger = Other.DebugMessenger; - Instance = Other.Instance; - Other.DebugMessenger = VK_NULL_HANDLE; - Other.Instance = VK_NULL_HANDLE; - } - - return *this; } void VulkanDebugManager::Initialize(VkInstance Instance) @@ -49,12 +27,12 @@ void VulkanDebugManager::Cleanup() return; } - FDestroyDebugUtilsMessengerExtParams Params = { Instance, DebugMessenger, nullptr }; + FDestroyParams Params = { Instance, DebugMessenger, nullptr }; DestroyDebugUtilsMessengerExt(Params); DebugMessenger = VK_NULL_HANDLE; } -VkResult VulkanDebugManager::CreateDebugUtilsMessengerExt(const FCreateDebugUtilsMessengerExtParams& Params) +VkResult VulkanDebugManager::CreateDebugUtilsMessengerExt(const FCreateParams& Params) { auto func = (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(Params.Instance, "vkCreateDebugUtilsMessengerEXT"); if (func != nullptr) @@ -67,7 +45,7 @@ VkResult VulkanDebugManager::CreateDebugUtilsMessengerExt(const FCreateDebugUtil } } -void VulkanDebugManager::DestroyDebugUtilsMessengerExt(const FDestroyDebugUtilsMessengerExtParams& Params) +void VulkanDebugManager::DestroyDebugUtilsMessengerExt(const FDestroyParams& Params) { auto func = (PFN_vkDestroyDebugUtilsMessengerEXT)vkGetInstanceProcAddr( Params.Instance, @@ -86,7 +64,6 @@ VKAPI_ATTR VkBool32 VKAPI_CALL VulkanDebugManager::DebugCallback( void* pUserData) { Log::Validation(pCallbackData->pMessage); - // std::cerr << "[Validation layer] : " << pCallbackData->pMessage << std::endl; if (MessageSeverity >= VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) { @@ -110,11 +87,10 @@ void VulkanDebugManager::SetupDebugMessanger() PopulateDebugMessengerCreateInfo(CreateInfo); - FCreateDebugUtilsMessengerExtParams Params = { Instance, &CreateInfo, nullptr, &DebugMessenger }; + FCreateParams Params = { Instance, &CreateInfo, nullptr, &DebugMessenger }; if (CreateDebugUtilsMessengerExt(Params) != VK_SUCCESS) { Log::Error("Failed to set up debug messenger!"); - // throw std::runtime_error("failed to set up debug messenger!"); } } diff --git a/src/private/VulkanDeviceManager.cpp b/src/private/VulkanDeviceManager.cpp new file mode 100755 index 0000000..e989b81 --- /dev/null +++ b/src/private/VulkanDeviceManager.cpp @@ -0,0 +1,247 @@ +#include "VulkanDeviceManager.h" + +#include +#include +#include // Necessary for uint32_t +#include +#include + +#include "VulkanContext.h" +#include "utilities/Logger.h" + +VulkanDeviceManager::VulkanDeviceManager() +{ +} + +VulkanDeviceManager::~VulkanDeviceManager() +{ + // Cleanup(); +} + +void VulkanDeviceManager::Initialize(FDeviceConfig InConfig) +// VkInstance Instance, +// bool bEnableValidationLayers, +// VkSurfaceKHR Surface, +// GLFWwindow* Window) +{ + DeviceConfig = InConfig; + // this->Instance = Instance; + // this->Surface = Surface; + // this->bEnableValidationLayers = bEnableValidationLayers; + // this->Window = Window; +} + +void VulkanDeviceManager::Cleanup() +{ + vkDestroyDevice(Device, nullptr); +} + +void VulkanDeviceManager::PickPhysicalDevice() +{ + uint32_t DeviceCount = 0; + vkEnumeratePhysicalDevices(DeviceConfig.Instance, &DeviceCount, nullptr); + + if (DeviceCount == 0) + { + Log::Error("Failed to find GPU with Vulkan Support."); + } + + std::vector Devices(DeviceCount); + vkEnumeratePhysicalDevices(DeviceConfig.Instance, &DeviceCount, Devices.data()); + + std::multimap Candidates; + + for (const auto& Device : Devices) + { + if (IsDeviceSuitable(Device)) + { + int Score = RateDeviceSuitability(Device); + Candidates.insert(std::make_pair(Score, Device)); + } + } + + if (Candidates.rbegin()->first > 0) + { + PhysicalDevice = Candidates.rbegin()->second; + SwapChainSupport = QuerySwapChainSupport(PhysicalDevice); + Log::Info("Suitable GPU found."); + } + else + { + Log::Error("Failed to find a suitable GPU."); + } +} + +bool VulkanDeviceManager::IsDeviceSuitable(VkPhysicalDevice Device) +{ + QueueFamilyIndices Indices = FindQueueFamilies(Device); + + bool bExtensionsSupported = CheckDeviceExtensionSupport(Device); + + bool bSwapChainAdequate = false; + if (bExtensionsSupported) + { + SwapChainSupport = QuerySwapChainSupport(Device); + bSwapChainAdequate = !SwapChainSupport.Formats.empty() && !SwapChainSupport.PresentModes.empty(); + } + + return Indices.IsComplete() && bExtensionsSupported && bSwapChainAdequate; +} + +int VulkanDeviceManager::RateDeviceSuitability(VkPhysicalDevice Device) +{ + VkPhysicalDeviceProperties DeviceProperties; + vkGetPhysicalDeviceProperties(Device, &DeviceProperties); + + VkPhysicalDeviceFeatures DeviceFeatures; + vkGetPhysicalDeviceFeatures(Device, &DeviceFeatures); + + int Score = 0; + + if (DeviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) + { + Score += 100; + } + + Score += DeviceProperties.limits.maxImageDimension2D; + + if (!DeviceFeatures.geometryShader) + { + return 0; + } + + return Score; +} + +bool VulkanDeviceManager::CheckDeviceExtensionSupport(VkPhysicalDevice Device) +{ + uint32_t ExtensionCount; + vkEnumerateDeviceExtensionProperties(Device, nullptr, &ExtensionCount, nullptr); + + std::vector AvailableExtensions(ExtensionCount); + vkEnumerateDeviceExtensionProperties(Device, nullptr, &ExtensionCount, AvailableExtensions.data()); + + std::set RequiredExtensions(DeviceExtensions.begin(), DeviceExtensions.end()); + + for (const auto& Extension : AvailableExtensions) + { + RequiredExtensions.erase(Extension.extensionName); + } + + return RequiredExtensions.empty(); +} + +QueueFamilyIndices VulkanDeviceManager::FindQueueFamilies(VkPhysicalDevice Device) +{ + QueueFamilyIndices Indices; + + uint32_t QueueFamilyCount = 0; + vkGetPhysicalDeviceQueueFamilyProperties(Device, &QueueFamilyCount, nullptr); + + std::vector QueueFamilies(QueueFamilyCount); + vkGetPhysicalDeviceQueueFamilyProperties(Device, &QueueFamilyCount, QueueFamilies.data()); + + int i = 0; + for (const auto& QueueFamily : QueueFamilies) + { + if (QueueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT) + { + Indices.GraphicsFamily = i; + } + + VkBool32 PresentSupport = false; + vkGetPhysicalDeviceSurfaceSupportKHR(Device, i, DeviceConfig.Surface, &PresentSupport); + + if (PresentSupport) + { + Indices.PresentFamily = i; + } + if (Indices.IsComplete()) + { + break; + } + + i++; + } + + return Indices; +} + +void VulkanDeviceManager::CreateLogicalDevice() +{ + PhysicalQueueFamilies = FindQueueFamilies(PhysicalDevice); + + std::vector QueueCreateInfos; + std::set UniqueQueueFamilies = { PhysicalQueueFamilies.GraphicsFamily.value(), PhysicalQueueFamilies.PresentFamily.value() }; + + float QueuePriority = 1.0f; + for (uint32_t QueueFamily : UniqueQueueFamilies) + { + VkDeviceQueueCreateInfo QueueCreateInfo{}; + QueueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; + QueueCreateInfo.queueFamilyIndex = PhysicalQueueFamilies.GraphicsFamily.value(); + QueueCreateInfo.queueCount = 1; + QueueCreateInfo.pQueuePriorities = &QueuePriority; + QueueCreateInfos.push_back(QueueCreateInfo); + } + + VkPhysicalDeviceFeatures DeviceFeatures{}; + + VkDeviceCreateInfo CreateInfo{}; + CreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; + CreateInfo.queueCreateInfoCount = static_cast(QueueCreateInfos.size()); + CreateInfo.pQueueCreateInfos = QueueCreateInfos.data(); + CreateInfo.pEnabledFeatures = &DeviceFeatures; + + CreateInfo.enabledExtensionCount = static_cast(DeviceExtensions.size()); + CreateInfo.ppEnabledExtensionNames = DeviceExtensions.data(); + + if (DeviceConfig.bEnableValidationLayers) + { + CreateInfo.enabledLayerCount = static_cast(ValidationLayers.size()); + CreateInfo.ppEnabledLayerNames = ValidationLayers.data(); + } + else + { + CreateInfo.enabledLayerCount = 0; + } + + if (vkCreateDevice(PhysicalDevice, &CreateInfo, nullptr, &Device) != VK_SUCCESS) + { + Log::Error("Failed to create logical device!"); + } + else + { + Log::Info("Created logical device."); + } + + vkGetDeviceQueue(Device, PhysicalQueueFamilies.GraphicsFamily.value(), 0, &GraphicsQueue); + vkGetDeviceQueue(Device, PhysicalQueueFamilies.PresentFamily.value(), 0, &PresentQueue); +} + +SwapChainSupportDetails VulkanDeviceManager::QuerySwapChainSupport(VkPhysicalDevice Device) +{ + SwapChainSupportDetails Details; + + vkGetPhysicalDeviceSurfaceCapabilitiesKHR(Device, DeviceConfig.Surface, &Details.Capabilities); + + uint32_t FormatCount; + vkGetPhysicalDeviceSurfaceFormatsKHR(Device, DeviceConfig.Surface, &FormatCount, nullptr); + + if (FormatCount != 0) + { + Details.Formats.resize(FormatCount); + vkGetPhysicalDeviceSurfaceFormatsKHR(Device, DeviceConfig.Surface, &FormatCount, Details.Formats.data()); + } + + uint32_t PresentModeCount; + vkGetPhysicalDeviceSurfacePresentModesKHR(Device, DeviceConfig.Surface, &PresentModeCount, nullptr); + + if (PresentModeCount != 0) + { + Details.PresentModes.resize(PresentModeCount); + vkGetPhysicalDeviceSurfacePresentModesKHR(Device, DeviceConfig.Surface, &PresentModeCount, Details.PresentModes.data()); + } + + return Details; +} diff --git a/src/private/VulkanFramebuffers.cpp b/src/private/VulkanFramebuffers.cpp new file mode 100644 index 0000000..24c4efe --- /dev/null +++ b/src/private/VulkanFramebuffers.cpp @@ -0,0 +1,48 @@ +#include "VulkanFramebuffers.h" + +#include "utilities/Logger.h" +#include + +void VulkanFramebuffers::Initialize(FFramebufferConfig InConfig) +{ + FramebufferConfig = InConfig; +} + +void VulkanFramebuffers::Cleanup() +{ + for (auto Framebuffer : SwapChainFramebuffers) + { + vkDestroyFramebuffer(FramebufferConfig.Device, Framebuffer, nullptr); + } +} + +// void VulkanFramebuffers::CreateFramebuffers(VkRenderPass RenderPass, std::vector SwapChainImageViews, VkExtent2D SwapChainExtent) +void VulkanFramebuffers::CreateFramebuffers() +{ + SwapChainFramebuffers.resize(FramebufferConfig.SwapChainImageViews.size()); + + for (size_t i = 0; i < FramebufferConfig.SwapChainImageViews.size(); i++) + { + VkImageView Attachments[] = { + FramebufferConfig.SwapChainImageViews[i] + }; + + VkFramebufferCreateInfo FramebufferInfo{}; + FramebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; + FramebufferInfo.renderPass = FramebufferConfig.RenderPass; + FramebufferInfo.attachmentCount = 1; + FramebufferInfo.pAttachments = Attachments; + FramebufferInfo.width = FramebufferConfig.SwapChainExtent.width; + FramebufferInfo.height = FramebufferConfig.SwapChainExtent.height; + FramebufferInfo.layers = 1; + + if (vkCreateFramebuffer(FramebufferConfig.Device, &FramebufferInfo, nullptr, &SwapChainFramebuffers[i]) != VK_SUCCESS) + { + Log::Error("Failed to create frame buffer!"); + } + else + { + Log::Info("Successfully created framebuffers."); + } + } +} diff --git a/src/VulkanInstanceManager.cpp b/src/private/VulkanInstanceManager.cpp old mode 100644 new mode 100755 similarity index 51% rename from src/VulkanInstanceManager.cpp rename to src/private/VulkanInstanceManager.cpp index 1413094..c47ba16 --- a/src/VulkanInstanceManager.cpp +++ b/src/private/VulkanInstanceManager.cpp @@ -1,6 +1,8 @@ #include "VulkanInstanceManager.h" -#include "Logger.h" +#include "VulkanContext.h" +#include "utilities/Logger.h" +#include VulkanInstanceManager::VulkanInstanceManager() { @@ -8,107 +10,14 @@ VulkanInstanceManager::VulkanInstanceManager() VulkanInstanceManager::~VulkanInstanceManager() { - // Cleanup(); -} - -VulkanInstanceManager::VulkanInstanceManager(VulkanInstanceManager&& Other) noexcept - : Instance(Other.Instance) /*, bValidationEnabled(Other.bValidationEnabled), bVerboseLogging(Other.bVerboseLogging), VkDebugManager(std::move(Other.VkDebugManager))*/ -{ - Other.Instance = VK_NULL_HANDLE; - Other.bValidationEnabled = false; - Other.bVerboseLogging = false; -} - -VulkanInstanceManager& VulkanInstanceManager::operator=(VulkanInstanceManager&& Other) noexcept -{ - if (this != &Other) - { - Cleanup(); - Instance = Other.Instance; - bValidationEnabled = Other.bValidationEnabled; - bVerboseLogging = Other.bVerboseLogging; - VkDebugManager = std::move(Other.VkDebugManager); - - Other.Instance = VK_NULL_HANDLE; - } - - return *this; -} - -// void VulkanInstanceManager::Initialize(const FVulkanConfig& Config) -//{ -// if (IsInitialized()) -// { -// Log::Warning("Already Initialized."); -// return; -// } -// -// bValidationEnabled = Config.bValidationEnabled; -// bVerboseLogging = Config.bVerboseLogging; -// -// if (bValidationEnabled) -// { -// Log::Info("DebugManager created with validation enabled."); -// VkDebugManager = std::make_unique(); -// } -// -// CreateInstance(); -// } - -void VulkanInstanceManager::Initialize(bool bEnableValidationLayers) -{ - if (IsInitialized()) - { - Log::Warning("Already Initialized."); - return; - } - - if (bEnableValidationLayers) - { - Log::Info("DebugManager created with validation enabled."); - VkDebugManager = std::make_unique(); - } - - CreateInstance(); -} - -void VulkanInstanceManager::SetupDebug() -{ - if (bValidationEnabled) - { - VkDebugManager->Initialize(Instance); - } -} - -void VulkanInstanceManager::SetupDevice() -{ - VkDeviceManager = std::make_unique(); - VkDeviceManager->Initialize(Instance, bValidationEnabled, ValidationLayers); } void VulkanInstanceManager::Cleanup() { - if (!IsInitialized()) - { - Log::Warning("Not initialized."); - return; - } - - if (VkDeviceManager) - { - VkDeviceManager->Cleanup(); - } - - if (VkDebugManager) - { - VkDebugManager->Cleanup(); - } - vkDestroyInstance(Instance, nullptr); - Instance = VK_NULL_HANDLE; } -std::vector VulkanInstanceManager::GetRequiredExtensions() +std::vector VulkanInstanceManager::GetRequiredExtensions(bool bEnableValidationLayers) { uint32_t GlfwExtensionCount = 0; const char** GlfwExtensions; @@ -116,7 +25,7 @@ std::vector VulkanInstanceManager::GetRequiredExtensions() std::vector Extensions(GlfwExtensions, GlfwExtensions + GlfwExtensionCount); - if (VkDebugManager) + if (bEnableValidationLayers) { Extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); } @@ -154,11 +63,11 @@ bool VulkanInstanceManager::CheckValidationLayerSupport() return true; } -void VulkanInstanceManager::CreateInstance() +void VulkanInstanceManager::CreateInstance(VulkanDebugManager* DebugManager) { Log::Info("Creating Vulkan instance."); - if (bValidationEnabled && !CheckValidationLayerSupport()) + if (DebugManager && !CheckValidationLayerSupport()) { Log::Error("Validation layers requested, but not available!"); } @@ -175,17 +84,17 @@ void VulkanInstanceManager::CreateInstance() CreateInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; CreateInfo.pApplicationInfo = &AppInfo; - auto Extensions = GetRequiredExtensions(); + auto Extensions = GetRequiredExtensions(DebugManager != nullptr); CreateInfo.enabledExtensionCount = static_cast(Extensions.size()); CreateInfo.ppEnabledExtensionNames = Extensions.data(); - if (VkDebugManager) + if (DebugManager) { VkDebugUtilsMessengerCreateInfoEXT debugCreateInfo{}; CreateInfo.enabledLayerCount = static_cast(ValidationLayers.size()); CreateInfo.ppEnabledLayerNames = ValidationLayers.data(); - VkDebugManager->PopulateDebugMessengerCreateInfo(debugCreateInfo); + DebugManager->PopulateDebugMessengerCreateInfo(debugCreateInfo); CreateInfo.pNext = (VkDebugUtilsMessengerCreateInfoEXT*)&debugCreateInfo; } else diff --git a/src/private/VulkanPipeline.cpp b/src/private/VulkanPipeline.cpp new file mode 100755 index 0000000..a957711 --- /dev/null +++ b/src/private/VulkanPipeline.cpp @@ -0,0 +1,275 @@ +#include "VulkanPipeline.h" + +#include + +#include "utilities/FileReader.h" +#include "utilities/Logger.h" +#include "Primitives.h" + +void VulkanPipeline::Initialize(VkDevice InDevice) +{ + Device = InDevice; +} + +void VulkanPipeline::Cleanup() +{ + // for (auto Framebuffer : SwapChainFrameBuffers) + // { + // vkDestroyFramebuffer(Device, Framebuffer, nullptr); + // } + + vkDestroyPipeline(Device, GraphicsPipeline, nullptr); + vkDestroyPipelineLayout(Device, PipelineLayout, nullptr); +} + +void VulkanPipeline::CreateGraphicsPipeline(VkExtent2D SwapChainExtent, VkRenderPass RenderPass) +{ + auto VertShaderCode = ReadFile("Shaders/vert.spv"); + auto FragShaderCode = ReadFile("Shaders/frag.spv"); + + Log::Info("Vert buffer size: " + std::to_string(VertShaderCode.size())); + Log::Info("Frag buffer size: " + std::to_string(FragShaderCode.size())); + + VkShaderModule VertShaderModule = CreateShaderModule(VertShaderCode); + VkShaderModule FragShaderModule = CreateShaderModule(FragShaderCode); + + VkPipelineShaderStageCreateInfo VertShaderStageInfo{}; + VertShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + VertShaderStageInfo.stage = VK_SHADER_STAGE_VERTEX_BIT; + VertShaderStageInfo.module = VertShaderModule; + VertShaderStageInfo.pName = "main"; + + VkPipelineShaderStageCreateInfo FragShaderStageInfo{}; + FragShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + FragShaderStageInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT; + FragShaderStageInfo.module = FragShaderModule; + FragShaderStageInfo.pName = "main"; + + VkPipelineShaderStageCreateInfo ShaderStages[] = { VertShaderStageInfo, FragShaderStageInfo }; + + VkPipelineVertexInputStateCreateInfo VertexInputInfo{}; + VertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; + + auto BindingDescription = Vertex::GetBindingDescription(); + auto AttributeDescriptions = Vertex::GetAttributeDescriptions(); + + VertexInputInfo.vertexBindingDescriptionCount = 1; + VertexInputInfo.pVertexBindingDescriptions = &BindingDescription; + VertexInputInfo.vertexAttributeDescriptionCount = static_cast(AttributeDescriptions.size()); + VertexInputInfo.pVertexAttributeDescriptions = AttributeDescriptions.data(); + + VkPipelineInputAssemblyStateCreateInfo InputAssembly{}; + InputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; + InputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + InputAssembly.primitiveRestartEnable = VK_FALSE; + + // VkViewport Viewport{}; + // Viewport.x = 0.0f; + // Viewport.x = 0.0f; + // Viewport.width = SwapChainExtent.width; + // Viewport.height = SwapChainExtent.height; + // Viewport.minDepth = 0.0f; + // Viewport.maxDepth = 1.0f; + + VkRect2D Scissor{}; + Scissor.offset = { 0, 0 }; + Scissor.extent = SwapChainExtent; + + std::vector DynamicStates = { + VK_DYNAMIC_STATE_VIEWPORT, + VK_DYNAMIC_STATE_SCISSOR + }; + + VkPipelineDynamicStateCreateInfo DynamicState{}; + DynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; + DynamicState.dynamicStateCount = static_cast(DynamicStates.size()); + DynamicState.pDynamicStates = DynamicStates.data(); + + VkPipelineViewportStateCreateInfo ViewportState{}; + ViewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; + ViewportState.viewportCount = 1; + ViewportState.scissorCount = 1; + + VkPipelineRasterizationStateCreateInfo Rasterizer{}; + Rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; + Rasterizer.depthClampEnable = VK_FALSE; + Rasterizer.rasterizerDiscardEnable = VK_FALSE; + Rasterizer.polygonMode = VK_POLYGON_MODE_FILL; + Rasterizer.lineWidth = 1.0f; + Rasterizer.cullMode = VK_CULL_MODE_BACK_BIT; + Rasterizer.frontFace = VK_FRONT_FACE_CLOCKWISE; + Rasterizer.depthBiasEnable = VK_FALSE; + Rasterizer.depthBiasConstantFactor = 0.0f; + Rasterizer.depthBiasClamp = 0.0f; + Rasterizer.depthBiasSlopeFactor = 0.0f; + + VkPipelineMultisampleStateCreateInfo Multisampling{}; + Multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; + Multisampling.sampleShadingEnable = VK_FALSE; + Multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; + Multisampling.minSampleShading = 1.0f; + Multisampling.pSampleMask = nullptr; + Multisampling.alphaToCoverageEnable = VK_FALSE; + Multisampling.alphaToOneEnable = VK_FALSE; + + VkPipelineColorBlendAttachmentState ColorBlendAttachement{}; + ColorBlendAttachement.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; + ColorBlendAttachement.blendEnable = VK_FALSE; + ColorBlendAttachement.srcColorBlendFactor = VK_BLEND_FACTOR_ONE; + ColorBlendAttachement.dstColorBlendFactor = VK_BLEND_FACTOR_ZERO; + ColorBlendAttachement.colorBlendOp = VK_BLEND_OP_ADD; + ColorBlendAttachement.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; + ColorBlendAttachement.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; + ColorBlendAttachement.alphaBlendOp = VK_BLEND_OP_ADD; + + VkPipelineColorBlendStateCreateInfo ColorBlending{}; + ColorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; + ColorBlending.logicOpEnable = VK_FALSE; + ColorBlending.logicOp = VK_LOGIC_OP_COPY; + ColorBlending.attachmentCount = 1; + ColorBlending.pAttachments = &ColorBlendAttachement; + ColorBlending.blendConstants[0] = 0.0f; + ColorBlending.blendConstants[1] = 0.0f; + ColorBlending.blendConstants[2] = 0.0f; + ColorBlending.blendConstants[3] = 0.0f; + + VkPipelineLayoutCreateInfo PipelineLayoutInfo{}; + PipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + PipelineLayoutInfo.setLayoutCount = 0; + PipelineLayoutInfo.pSetLayouts = nullptr; + PipelineLayoutInfo.pushConstantRangeCount = 0; + PipelineLayoutInfo.pPushConstantRanges = nullptr; + + if (vkCreatePipelineLayout(Device, &PipelineLayoutInfo, nullptr, &PipelineLayout) != VK_SUCCESS) + { + Log::Error("Failed to create pipeline layout!"); + } + else + { + Log::Info("Successfully created pipeline layout"); + } + + VkGraphicsPipelineCreateInfo PipelineInfo{}; + PipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; + PipelineInfo.stageCount = 2; + PipelineInfo.pStages = ShaderStages; + PipelineInfo.pVertexInputState = &VertexInputInfo; + PipelineInfo.pInputAssemblyState = &InputAssembly; + PipelineInfo.pViewportState = &ViewportState; + PipelineInfo.pRasterizationState = &Rasterizer; + PipelineInfo.pMultisampleState = &Multisampling; + PipelineInfo.pDepthStencilState = nullptr; + PipelineInfo.pColorBlendState = &ColorBlending; + PipelineInfo.pDynamicState = &DynamicState; + PipelineInfo.layout = PipelineLayout; + PipelineInfo.renderPass = RenderPass; + PipelineInfo.subpass = 0; + PipelineInfo.basePipelineHandle = VK_NULL_HANDLE; + PipelineInfo.basePipelineIndex = -1; + + if (vkCreateGraphicsPipelines(Device, VK_NULL_HANDLE, 1, &PipelineInfo, nullptr, &GraphicsPipeline) != VK_SUCCESS) + { + Log::Error("Failed to create graphics pipeline!"); + } + else + { + Log::Info("Successfully created graphics pipeline."); + } + + vkDestroyShaderModule(Device, FragShaderModule, nullptr); + vkDestroyShaderModule(Device, VertShaderModule, nullptr); +} + +VkShaderModule VulkanPipeline::CreateShaderModule(const std::vector& Code) +{ + VkShaderModuleCreateInfo CreateInfo{}; + CreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; + CreateInfo.codeSize = Code.size(); + CreateInfo.pCode = reinterpret_cast(Code.data()); + + VkShaderModule ShaderModule; + if (vkCreateShaderModule(Device, &CreateInfo, nullptr, &ShaderModule) != VK_SUCCESS) + { + Log::Error("Failed to create shader module."); + } + else + { + Log::Info("Successfully created shader module."); + } + + return ShaderModule; +} + +// void VulkanPipeline::CreateRenderPass(VkFormat SwapChainImageFormat) +// { +// VkAttachmentDescription ColorAttachment{}; +// ColorAttachment.format = SwapChainImageFormat; +// ColorAttachment.samples = VK_SAMPLE_COUNT_1_BIT; +// ColorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; +// ColorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; +// ColorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; +// ColorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; +// ColorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; +// ColorAttachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; +// +// VkAttachmentReference ColorAttachmentRef{}; +// ColorAttachmentRef.attachment = 0; +// ColorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; +// +// VkSubpassDescription Subpass{}; +// Subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; +// Subpass.colorAttachmentCount = 1; +// Subpass.pColorAttachments = &ColorAttachmentRef; +// +// VkRenderPassCreateInfo RenderPassInfo{}; +// RenderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; +// RenderPassInfo.attachmentCount = 1; +// RenderPassInfo.pAttachments = &ColorAttachment; +// RenderPassInfo.subpassCount = 1; +// RenderPassInfo.pSubpasses = &Subpass; +// +// VkSubpassDependency Dependency{}; +// Dependency.srcSubpass = VK_SUBPASS_EXTERNAL; +// Dependency.dstSubpass = 0; +// Dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; +// Dependency.srcAccessMask = 0; +// Dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; +// Dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; +// RenderPassInfo.dependencyCount = 1; +// RenderPassInfo.pDependencies = &Dependency; +// +// if (vkCreateRenderPass(Device, &RenderPassInfo, nullptr, &RenderPass) != VK_SUCCESS) +// { +// Log::Error("Failed to create render pass!"); +// } +// else +// { +// Log::Info("Successfully created render pass."); +// } +// } + +// void VulkanPipeline::CreateFramebuffers(std::vector SwapChainImageViews, VkExtent2D SwapChainExtent) +// { +// SwapChainFrameBuffers.resize(SwapChainImageViews.size()); +// +// for (size_t i = 0; i < SwapChainImageViews.size(); i++) +// { +// VkImageView Attachments[] = { +// SwapChainImageViews[i] +// }; +// +// VkFramebufferCreateInfo FramebufferInfo{}; +// FramebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; +// FramebufferInfo.renderPass = RenderPass; +// FramebufferInfo.attachmentCount = 1; +// FramebufferInfo.pAttachments = Attachments; +// FramebufferInfo.width = SwapChainExtent.width; +// FramebufferInfo.height = SwapChainExtent.height; +// FramebufferInfo.layers = 1; +// +// if (vkCreateFramebuffer(Device, &FramebufferInfo, nullptr, &SwapChainFrameBuffers[i]) != VK_SUCCESS) +// { +// Log::Error("Failed to create frame buffer!"); +// } +// } +// } diff --git a/src/private/VulkanRenderPass.cpp b/src/private/VulkanRenderPass.cpp new file mode 100644 index 0000000..34482d2 --- /dev/null +++ b/src/private/VulkanRenderPass.cpp @@ -0,0 +1,60 @@ +#include "VulkanRenderPass.h" +#include "utilities/Logger.h" + +void VulkanRenderPass::Initialize(VkDevice InDevice) +{ + Device = InDevice; +} + +void VulkanRenderPass::Cleanup() +{ + vkDestroyRenderPass(Device, RenderPass, nullptr); +} + +void VulkanRenderPass::CreateRenderPass(VkFormat SwapChainImageFormat) +{ + VkAttachmentDescription ColorAttachment{}; + ColorAttachment.format = SwapChainImageFormat; + ColorAttachment.samples = VK_SAMPLE_COUNT_1_BIT; + ColorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + ColorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; + ColorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + ColorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + ColorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + ColorAttachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; + + VkAttachmentReference ColorAttachmentRef{}; + ColorAttachmentRef.attachment = 0; + ColorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + + VkSubpassDescription Subpass{}; + Subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + Subpass.colorAttachmentCount = 1; + Subpass.pColorAttachments = &ColorAttachmentRef; + + VkRenderPassCreateInfo RenderPassInfo{}; + RenderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; + RenderPassInfo.attachmentCount = 1; + RenderPassInfo.pAttachments = &ColorAttachment; + RenderPassInfo.subpassCount = 1; + RenderPassInfo.pSubpasses = &Subpass; + + VkSubpassDependency Dependency{}; + Dependency.srcSubpass = VK_SUBPASS_EXTERNAL; + Dependency.dstSubpass = 0; + Dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + Dependency.srcAccessMask = 0; + Dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + Dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + RenderPassInfo.dependencyCount = 1; + RenderPassInfo.pDependencies = &Dependency; + + if (vkCreateRenderPass(Device, &RenderPassInfo, nullptr, &RenderPass) != VK_SUCCESS) + { + Log::Error("Failed to create render pass!"); + } + else + { + Log::Info("Successfully created render pass."); + } +} diff --git a/src/private/VulkanSwapChain.cpp b/src/private/VulkanSwapChain.cpp new file mode 100644 index 0000000..c0ef310 --- /dev/null +++ b/src/private/VulkanSwapChain.cpp @@ -0,0 +1,203 @@ +#include "VulkanSwapChain.h" + +#include +#include // Necessary for uint32_t +#include // Necessary for std::numeric_limits +#include // Necessary for std::clamp +#include +#include + +#include "utilities/Logger.h" + +VulkanSwapChain::VulkanSwapChain() +{ +} + +VulkanSwapChain::~VulkanSwapChain() +{ + // Cleanup(); +} + +void VulkanSwapChain::Initialize(FSwapConfig InSwapConfig) +{ + SwapConfig = InSwapConfig; +} + +// void VulkanSwapChain::Initialize( +// VkDevice InDevice, +// VkSurfaceKHR InSurface, +// GLFWwindow* InWindow) +// { +// Device = InDevice; +// Surface = InSurface; +// Window = InWindow; +// } + +void VulkanSwapChain::Cleanup() +{ + for (auto ImageView : SwapChainImageViews) + { + vkDestroyImageView(SwapConfig.Device, ImageView, nullptr); + } + vkDestroySwapchainKHR(SwapConfig.Device, SwapChain, nullptr); +} + +VkSurfaceFormatKHR VulkanSwapChain::ChooseSwapSurfaceFormat(const std::vector& AvailableFormats) +{ + for (const auto& AvailableFormat : AvailableFormats) + { + if (AvailableFormat.format == VK_FORMAT_B8G8R8A8_SRGB && AvailableFormat.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) + { + return AvailableFormat; + } + } + return AvailableFormats[0]; +} + +VkPresentModeKHR VulkanSwapChain::ChooseSwapPresentMode(const std::vector& AvailablePresentModes) +{ + for (const auto& AvailablePresentMode : AvailablePresentModes) + { + if (AvailablePresentMode == VK_PRESENT_MODE_MAILBOX_KHR) + { + return AvailablePresentMode; + } + } + return VK_PRESENT_MODE_FIFO_KHR; +} + +VkExtent2D VulkanSwapChain::ChooseSwapExtent(const VkSurfaceCapabilitiesKHR& Capabilities) +{ + if (Capabilities.currentExtent.width != (std::numeric_limits::max)()) + { + return Capabilities.currentExtent; + } + else + { + if (SwapConfig.Window == nullptr) + { + Log::Error("GLFW window is null in CreateSwapChain!"); + } + int Width, Height; + glfwGetFramebufferSize(SwapConfig.Window, &Width, &Height); + + VkExtent2D ActualExtent = { + static_cast(Width), + static_cast(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; + } +} + +void VulkanSwapChain::CreateSwapChain() +{ + VkSurfaceFormatKHR SurfaceFormat = ChooseSwapSurfaceFormat(SwapConfig.Formats); + VkPresentModeKHR PresentMode = ChooseSwapPresentMode(SwapConfig.PresentModes); + VkExtent2D Extent = ChooseSwapExtent(SwapConfig.Capabilities); + + uint32_t ImageCount = SwapConfig.Capabilities.minImageCount + 1; + + if (SwapConfig.Capabilities.maxImageCount > 0 && ImageCount > SwapConfig.Capabilities.maxImageCount) + { + ImageCount = SwapConfig.Capabilities.maxImageCount; + } + + VkSwapchainCreateInfoKHR CreateInfo{}; + CreateInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; + CreateInfo.surface = SwapConfig.Surface; + + CreateInfo.minImageCount = ImageCount; + CreateInfo.imageFormat = SurfaceFormat.format; + CreateInfo.imageColorSpace = SurfaceFormat.colorSpace; + CreateInfo.imageExtent = Extent; + CreateInfo.imageArrayLayers = 1; + CreateInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; // may need VK_IMAGE_USAGE_TRANSFER_DST_BIT for post processing https://vulkan-tutorial.com/Drawing_a_triangle/Presentation/Swap_chain#:~:text=VK%5FIMAGE%5FUSAGE%5FTRANSFER%5FDST%5FBIT + + uint32_t QueueFamilyIndices[] = { SwapConfig.GraphicsFamily.value(), + SwapConfig.PresentFamily.value() }; + + if (SwapConfig.GraphicsFamily != SwapConfig.PresentFamily) + { + CreateInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT; + CreateInfo.queueFamilyIndexCount = 2; + CreateInfo.pQueueFamilyIndices = QueueFamilyIndices; + } + else + { + CreateInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; + CreateInfo.queueFamilyIndexCount = 0; + CreateInfo.pQueueFamilyIndices = nullptr; + } + + CreateInfo.preTransform = SwapConfig.Capabilities.currentTransform; + CreateInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; + CreateInfo.presentMode = PresentMode; + CreateInfo.clipped = VK_TRUE; + CreateInfo.oldSwapchain = VK_NULL_HANDLE; + + Log::Info("ChooseSwapExtent 3"); + if (vkCreateSwapchainKHR(SwapConfig.Device, &CreateInfo, nullptr, &SwapChain) != VK_SUCCESS) + { + Log::Error("Failed to create swap chain."); + } + else + { + Log::Info("Successfully created swap chain."); + } + + vkGetSwapchainImagesKHR(SwapConfig.Device, SwapChain, &ImageCount, nullptr); + SwapChainImages.resize(ImageCount); + vkGetSwapchainImagesKHR(SwapConfig.Device, SwapChain, &ImageCount, SwapChainImages.data()); + + SwapChainImageFormat = SurfaceFormat.format; + SwapChainExtent = Extent; +} + +void VulkanSwapChain::CreateImageViews() +{ + SwapChainImageViews.resize(SwapChainImages.size()); + + int CreatedViews = 0; + for (size_t i = 0; i < SwapChainImages.size(); i++) + { + VkImageViewCreateInfo CreateInfo{}; + CreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + CreateInfo.image = SwapChainImages[i]; + + CreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; + CreateInfo.format = SwapChainImageFormat; + CreateInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY; + CreateInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY; + CreateInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY; + CreateInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY; + + CreateInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + CreateInfo.subresourceRange.baseMipLevel = 0; + CreateInfo.subresourceRange.levelCount = 1; + CreateInfo.subresourceRange.baseArrayLayer = 0; + CreateInfo.subresourceRange.layerCount = 1; + + if (vkCreateImageView(SwapConfig.Device, &CreateInfo, nullptr, &SwapChainImageViews[i]) != VK_SUCCESS) + { + Log::Error("Failed to create image views."); + } + else + { + CreatedViews++; + } + } + + Log::Info("Successfully created " + std::to_string(CreatedViews) + " image views."); +} + +// void VulkanSwapChain::RecreateSwapChain() +// { +// vkDeviceWaitIdle(SwapConfig.Device); +// +// CreateSwapChain(); +// CreateImageViews(); +// } diff --git a/src/private/VulkanVertexBuffer.cpp b/src/private/VulkanVertexBuffer.cpp new file mode 100644 index 0000000..96e37b4 --- /dev/null +++ b/src/private/VulkanVertexBuffer.cpp @@ -0,0 +1,74 @@ +#include "VulkanVertexBuffer.h" +#include "utilities/Logger.h" +#include +#include +#include + +void VulkanVertexBuffer::Initialize(FVertexBufferConfig InConfig) +{ + Config = InConfig; +} + +void VulkanVertexBuffer::Cleanup() +{ + vkDestroyBuffer(Config.Device, VertexBuffer, nullptr); + vkFreeMemory(Config.Device, VertexBufferMemory, nullptr); +} + +void VulkanVertexBuffer::CreateVertexBuffer(std::vector InVertices) +{ + VkBufferCreateInfo BufferInfo{}; + BufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + BufferInfo.size = sizeof(InVertices[0]) * InVertices.size(); + BufferInfo.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; + BufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + + if (vkCreateBuffer(Config.Device, &BufferInfo, nullptr, &VertexBuffer) != VK_SUCCESS) + { + Log::Error("Failed to create vertex buffer!"); + } + else + { + Log::Info("Successfully created vertex buffer."); + } + + VkMemoryRequirements MemoryRequirements; + vkGetBufferMemoryRequirements(Config.Device, VertexBuffer, &MemoryRequirements); + + VkMemoryAllocateInfo AllocateInfo{}; + AllocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + AllocateInfo.allocationSize = MemoryRequirements.size; + AllocateInfo.memoryTypeIndex = FindMemoryType(MemoryRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); + + if (vkAllocateMemory(Config.Device, &AllocateInfo, nullptr, &VertexBufferMemory) != VK_SUCCESS) + { + Log::Error("Failed to allocate vertex buffer memory!"); + } + else + { + Log::Info("Successfully allocated vertex buffer memory."); + } + + vkBindBufferMemory(Config.Device, VertexBuffer, VertexBufferMemory, 0); + + void* Data; + vkMapMemory(Config.Device, VertexBufferMemory, 0, BufferInfo.size, 0, &Data); + memcpy(Data, InVertices.data(), (size_t)BufferInfo.size); + vkUnmapMemory(Config.Device, VertexBufferMemory); +} + +uint32_t VulkanVertexBuffer::FindMemoryType(uint32_t TypeFilter, VkMemoryPropertyFlags Properties) +{ + VkPhysicalDeviceMemoryProperties MemoryProperties; + vkGetPhysicalDeviceMemoryProperties(Config.PhysicalDevice, &MemoryProperties); + + for (uint32_t i = 0; i < MemoryProperties.memoryTypeCount; i++) + { + if ((TypeFilter & (1 << i)) && (MemoryProperties.memoryTypes[i].propertyFlags & Properties) == Properties) + { + return i; + } + } + + Log::Error("Failed to find suitable memory type!"); +} diff --git a/src/GlfwWindowManager.h b/src/public/GlfwWindowManager.h old mode 100644 new mode 100755 similarity index 66% rename from src/GlfwWindowManager.h rename to src/public/GlfwWindowManager.h index 3361f49..362315f --- a/src/GlfwWindowManager.h +++ b/src/public/GlfwWindowManager.h @@ -2,11 +2,11 @@ #include -#define GLFW_INCLUDE_VULKAN +#include +#define GLFW_INCLUDE_VULKAN #include #include -#include struct FWindowConfig { @@ -23,26 +23,19 @@ public: GlfwWindowManager(); ~GlfwWindowManager(); - // GlfwWindowManager(const GlfwWindowManager&) = delete; - // GlfwWindowManager& operator=(const GlfwWindowManager&) = delete; - - // GlfwWindowManager(GlfwWindowManager&& Other) noexcept; - // GlfwWindowManager& operator=(GlfwWindowManager&& Other) noexcept; - void Initialize(const FWindowConfig& Config); - void Cleanup(VkInstance Instance); + void Cleanup(); bool ShouldClose() const; void PollEvents(); void WaitEvents() const; void SetTitle(const std::string& Title); - GLFWwindow* GetHandle() const { return Window; } uint32_t GetWidth() const { return Config.Width; } uint32_t GetHeight() const { return Config.Height; } const std::string& GetTitle() const { return Config.Title; } - bool IsInitialized() const { return Window && Surface; } + bool IsInitialized() const { return Window; } void SetResizeCallback(GLFWwindowsizefun Callback); void SetKeyCallback(GLFWkeyfun Callback); @@ -50,16 +43,11 @@ public: void SetCursorPositionCallback(GLFWcursorposfun Callback); void SetScrollCallback(GLFWscrollfun Callback); - void CreateSurface(VkInstance Instance); - - static VkSurfaceKHR Surface; - - static GLFWwindow* Window; + GLFWwindow* GetWindow() const { return Window; } private: FWindowConfig Config; - - // VkSurfaceKHR Surface = VK_NULL_HANDLE; + GLFWwindow* Window; void InitializeGlfw(); diff --git a/src/public/Primitives.h b/src/public/Primitives.h new file mode 100644 index 0000000..7398001 --- /dev/null +++ b/src/public/Primitives.h @@ -0,0 +1,36 @@ +#include +#include + +#include + +struct Vertex +{ + glm::vec2 Position; + glm::vec3 Color; + + static VkVertexInputBindingDescription GetBindingDescription() + { + VkVertexInputBindingDescription BindingDescription{}; + BindingDescription.binding = 0; + BindingDescription.stride = sizeof(Vertex); + BindingDescription.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; + + return BindingDescription; + } + + static std::array GetAttributeDescriptions() + { + std::array AttributeDescriptions{}; + AttributeDescriptions[0].binding = 0; + AttributeDescriptions[0].location = 0; + AttributeDescriptions[0].format = VK_FORMAT_R32G32_SFLOAT; + AttributeDescriptions[0].offset = offsetof(Vertex, Position); + + AttributeDescriptions[1].binding = 0; + AttributeDescriptions[1].location = 1; + AttributeDescriptions[1].format = VK_FORMAT_R32G32B32_SFLOAT; + AttributeDescriptions[1].offset = offsetof(Vertex, Color); + + return AttributeDescriptions; + } +}; diff --git a/src/public/VulkanCommandBuffers.h b/src/public/VulkanCommandBuffers.h new file mode 100644 index 0000000..1d6d84e --- /dev/null +++ b/src/public/VulkanCommandBuffers.h @@ -0,0 +1,45 @@ + +#pragma once + +#include "VulkanVertexBuffer.h" +#include +#define GLFW_INCLUDE_VULKAN +#include + +#include +#include + +class VulkanCommandBuffers +{ +public: + void Initialize( + VkDevice InDevice, + VkRenderPass InRenderPass); + + void Cleanup(); + + void CreateCommandPool(std::optional GraphicsFamily); + + void CreateCommandBuffers(int FramesInFlight); + + void RecordCommandBuffer( + VkCommandBuffer InCommandBuffer, + uint32_t ImageIndex, + VkBuffer InVertexBuffer, + std::vector InVertices, + VkRenderPass RenderPass, + VkExtent2D SwapChainExtent, + VkPipeline GraphicsPipeline, + std::vector SwapChainFramebuffers); + + std::vector GetCommandBuffers() { return CommandBuffers; } + VkCommandBuffer GetCommandBuffer(int i) { return CommandBuffers[i]; } + +private: + VkDevice Device; + VkRenderPass RenderPass; + VkQueue GraphicsQueue; + + std::vector CommandBuffers; + VkCommandPool CommandPool; +}; diff --git a/src/public/VulkanContext.h b/src/public/VulkanContext.h new file mode 100755 index 0000000..e91cb79 --- /dev/null +++ b/src/public/VulkanContext.h @@ -0,0 +1,77 @@ +#pragma once + +#include "VulkanCommandBuffers.h" +#include "VulkanFramebuffers.h" +#include "VulkanInstanceManager.h" +#include "VulkanDeviceManager.h" +#include "VulkanDebugManager.h" +#include "VulkanPipeline.h" +#include "VulkanRenderPass.h" +#include "VulkanSwapChain.h" +#include "VulkanVertexBuffer.h" + +#include +#include + +#define GLFW_INCLUDE_VULKAN +#include + +static const std::vector ValidationLayers = { + "VK_LAYER_KHRONOS_validation" +}; + +struct FVulkanConfig +{ + bool bValidationEnabled = true; + bool bVerboseLogging = false; + GLFWwindow* Window = nullptr; + std::vector Vertices; +}; + +static FVulkanConfig Config = {}; + +class VulkanContext +{ +public: + VulkanContext(); + ~VulkanContext(); + + void Initialize(FVulkanConfig& InConfig); + void Cleanup(); + + void CreateSurface(GLFWwindow* Window); + void CreateSyncObjects(); + void DrawFrame(); + void RecreateSwapChain(); + void CleanupSwapChain(); + + VkSurfaceKHR GetSurface() { return Surface; }; + + void SetFramebufferResized(bool bResized) { bFramebufferResized = bResized; } + +private: + VkSurfaceKHR Surface = VK_NULL_HANDLE; + + VulkanInstanceManager InstanceManager; + VulkanDebugManager DebugManager; + VulkanDeviceManager DeviceManager; + VulkanSwapChain SwapChain; + VulkanPipeline GraphicsPipeline; + VulkanRenderPass RenderPass; + VulkanFramebuffers Framebuffers; + VulkanVertexBuffer VertexBuffer; + VulkanCommandBuffers CommandBuffers; + + // VkDevice Device; + // VkPhysicalDevice PhysicalDevice; + // VkQueue GraphicsQueue; + + std::vector ImageAvailableSemaphores; + std::vector RenderFinishedSemaphores; + std::vector InFlightFences; + + bool bFramebufferResized = false; + + const int MAX_FRAMES_IN_FLIGHT = 2; + uint32_t CurrentFrame = 0; +}; diff --git a/src/VulkanDebugManager.h b/src/public/VulkanDebugManager.h old mode 100644 new mode 100755 similarity index 67% rename from src/VulkanDebugManager.h rename to src/public/VulkanDebugManager.h index fa50127..60b3991 --- a/src/VulkanDebugManager.h +++ b/src/public/VulkanDebugManager.h @@ -3,7 +3,7 @@ #define GLFW_INCLUDE_VULKAN #include -struct FCreateDebugUtilsMessengerExtParams +struct FCreateParams { VkInstance Instance; const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo; @@ -11,7 +11,7 @@ struct FCreateDebugUtilsMessengerExtParams VkDebugUtilsMessengerEXT* pDebugMessenger; }; -struct FDestroyDebugUtilsMessengerExtParams +struct FDestroyParams { VkInstance Instance; VkDebugUtilsMessengerEXT DebugMessenger; @@ -24,12 +24,6 @@ public: VulkanDebugManager(); ~VulkanDebugManager(); - VulkanDebugManager(const VulkanDebugManager&) = delete; - VulkanDebugManager& operator=(const VulkanDebugManager&) = delete; - - VulkanDebugManager(VulkanDebugManager&& Other) noexcept; - VulkanDebugManager& operator=(VulkanDebugManager&& Other) noexcept; - void Initialize(VkInstance Instance); void Cleanup(); @@ -44,9 +38,9 @@ private: VkDebugUtilsMessengerEXT DebugMessenger = VK_NULL_HANDLE; - VkResult CreateDebugUtilsMessengerExt(const FCreateDebugUtilsMessengerExtParams& Params); + VkResult CreateDebugUtilsMessengerExt(const FCreateParams& Params); - void DestroyDebugUtilsMessengerExt(const FDestroyDebugUtilsMessengerExtParams& Params); + void DestroyDebugUtilsMessengerExt(const FDestroyParams& Params); static VKAPI_ATTR VkBool32 VKAPI_CALL DebugCallback( VkDebugUtilsMessageSeverityFlagBitsEXT MessageSeverity, diff --git a/src/public/VulkanDeviceManager.h b/src/public/VulkanDeviceManager.h new file mode 100755 index 0000000..49d15e7 --- /dev/null +++ b/src/public/VulkanDeviceManager.h @@ -0,0 +1,86 @@ +#pragma once + +#include +#include +#include + +#define GLFW_INCLUDE_VULKAN +#include + +struct FDeviceConfig +{ + VkInstance Instance; + bool bEnableValidationLayers; + VkSurfaceKHR Surface; + GLFWwindow* Window; +}; + +struct QueueFamilyIndices +{ + std::optional GraphicsFamily; + std::optional PresentFamily; + + bool IsComplete() + { + return GraphicsFamily.has_value() && PresentFamily.has_value(); + } +}; + +struct SwapChainSupportDetails +{ + VkSurfaceCapabilitiesKHR Capabilities; + std::vector Formats; + std::vector PresentModes; +}; + +class VulkanDeviceManager +{ +public: + VulkanDeviceManager(); + ~VulkanDeviceManager(); + + void Initialize(FDeviceConfig InConfig); + // VkInstance Instance, + // bool EnableValidationLayers, + // VkSurfaceKHR Surface, + // GLFWwindow* Window); + + void Cleanup(); + + void PickPhysicalDevice(); + void CreateLogicalDevice(); + + VkDevice GetDevice() { return Device; } + VkPhysicalDevice GetPhysicalDevice() { return PhysicalDevice; } + QueueFamilyIndices GetPhysicalQueueFamilies() { return PhysicalQueueFamilies; } + VkQueue GetGraphicsQueue() { return GraphicsQueue; } + VkQueue GetPresentQueue() { return PresentQueue; } + SwapChainSupportDetails GetSwapChainSupport() { return SwapChainSupport; } + +private: + FDeviceConfig DeviceConfig; + + // VkInstance Instance = VK_NULL_HANDLE; + VkDevice Device = VK_NULL_HANDLE; + VkPhysicalDevice PhysicalDevice = VK_NULL_HANDLE; + VkQueue GraphicsQueue = VK_NULL_HANDLE; + VkQueue PresentQueue = VK_NULL_HANDLE; + QueueFamilyIndices PhysicalQueueFamilies; + // VkSurfaceKHR Surface; + + // GLFWwindow* Window = nullptr; + + SwapChainSupportDetails SwapChainSupport; + + // bool bEnableValidationLayers = false; + + bool IsDeviceSuitable(VkPhysicalDevice Device); + + int RateDeviceSuitability(VkPhysicalDevice Device); + + bool CheckDeviceExtensionSupport(VkPhysicalDevice Device); + + QueueFamilyIndices FindQueueFamilies(VkPhysicalDevice Device); + + SwapChainSupportDetails QuerySwapChainSupport(VkPhysicalDevice Device); +}; diff --git a/src/public/VulkanFramebuffers.h b/src/public/VulkanFramebuffers.h new file mode 100644 index 0000000..b9a6045 --- /dev/null +++ b/src/public/VulkanFramebuffers.h @@ -0,0 +1,39 @@ +#pragma once + +#include +#define GLFW_INCLUDE_VULKAN +#include + +#include + +struct FFramebufferConfig +{ + VkDevice Device; + VkRenderPass RenderPass; + std::vector SwapChainImageViews; + VkExtent2D SwapChainExtent; +}; + +class VulkanFramebuffers +{ +public: + void Initialize(FFramebufferConfig InConfig); + + void Cleanup(); + + void CreateFramebuffers(); + // void CreateFramebuffers(VkRenderPass RenderPass, std::vector SwapChainImageViews, VkExtent2D SwapChainExtent); + + std::vector GetSwapChainFrameBuffers() { return SwapChainFramebuffers; } + + // void CreateCommandPool(std::optional GraphicsFamily); + // + // void CreateCommandBuffer(); + // + // void RecordCommandBuffer(VkCommandBuffer CommandBuffer, uint32_t imageIndex, VkRenderPass RenderPass, VkExtent2D SwapChainExtent, VkPipeline GraphicsPipeline); + +private: + FFramebufferConfig FramebufferConfig; + + std::vector SwapChainFramebuffers; +}; diff --git a/src/public/VulkanInstanceManager.h b/src/public/VulkanInstanceManager.h new file mode 100755 index 0000000..18fbf12 --- /dev/null +++ b/src/public/VulkanInstanceManager.h @@ -0,0 +1,27 @@ +#pragma once + +#include + +#define GLFW_INCLUDE_VULKAN +#include + +#include "VulkanDebugManager.h" + +class VulkanInstanceManager +{ +public: + VulkanInstanceManager(); + ~VulkanInstanceManager(); + + void Cleanup(); + + void CreateInstance(VulkanDebugManager* DebugManager = nullptr); + const VkInstance GetInstance() const { return Instance; } + +private: + VkInstance Instance = VK_NULL_HANDLE; + + std::vector GetRequiredExtensions(bool bEnableValidationLayers); + + bool CheckValidationLayerSupport(); +}; diff --git a/src/public/VulkanPipeline.h b/src/public/VulkanPipeline.h new file mode 100755 index 0000000..8cf5067 --- /dev/null +++ b/src/public/VulkanPipeline.h @@ -0,0 +1,33 @@ +#pragma once + +#define GLFW_INCLUDE_VULKAN +#include + +#include + +class VulkanPipeline +{ +public: + void Initialize(VkDevice InDevice); + + void Cleanup(); + + // void CreateRenderPass(VkFormat SwapChainImageFormat); + + // void CreateFramebuffers(std::vector SwapChainImageViews, VkExtent2D SwapChainExtent); + + VkShaderModule CreateShaderModule(const std::vector& Code); + + void CreateGraphicsPipeline(VkExtent2D SwapChainExtent, VkRenderPass RenderPass); + // + // VkRenderPass GetRenderPass() { return RenderPass; } + // + VkPipeline GetGraphicsPipeline() { return GraphicsPipeline; } + +private: + VkDevice Device; + // VkRenderPass RenderPass; + VkPipelineLayout PipelineLayout; + VkPipeline GraphicsPipeline; + // std::vector SwapChainFrameBuffers; +}; diff --git a/src/public/VulkanRenderPass.h b/src/public/VulkanRenderPass.h new file mode 100644 index 0000000..9aa9a87 --- /dev/null +++ b/src/public/VulkanRenderPass.h @@ -0,0 +1,20 @@ +#pragma once + +#define GLFW_INCLUDE_VULKAN +#include + +class VulkanRenderPass +{ +public: + void Initialize(VkDevice InDevice); + + void Cleanup(); + + void CreateRenderPass(VkFormat SwapChainImageFormat); + + VkRenderPass GetRenderPass() { return RenderPass; } + +private: + VkDevice Device; + VkRenderPass RenderPass; +}; diff --git a/src/public/VulkanSwapChain.h b/src/public/VulkanSwapChain.h new file mode 100644 index 0000000..5182e74 --- /dev/null +++ b/src/public/VulkanSwapChain.h @@ -0,0 +1,93 @@ +#pragma once + +#include +#include +#include + +#define GLFW_INCLUDE_VULKAN +#include + +const std::vector DeviceExtensions = { + VK_KHR_SWAPCHAIN_EXTENSION_NAME +}; +// +// struct SwapChainSupportDetails +// { +// VkSurfaceCapabilitiesKHR Capabilities; +// std::vector Formats; +// std::vector PresentModes; +// }; + +struct FSwapConfig +{ + VkDevice Device; + VkSurfaceKHR Surface; + GLFWwindow* Window; + std::optional GraphicsFamily; + std::optional PresentFamily; + VkSurfaceCapabilitiesKHR Capabilities; + std::vector Formats; + std::vector PresentModes; +}; + +class VulkanSwapChain +{ +public: + VulkanSwapChain(); + ~VulkanSwapChain(); + + void Initialize(FSwapConfig InConfig); + + // void Initialize( + // VkDevice InDevice, + // VkSurfaceKHR InSurface, + // GLFWwindow* InWindow); + + void Cleanup(); + + void CreateSwapChain(); + // void CreateSwapChain( + // std::optional GraphicsFamily, + // std::optional PresentFamily, + // VkSurfaceCapabilitiesKHR Capabilities, + // std::vector Formats, + // std::vector PresentModes); + + void CreateImageViews(); + + // void RecreateSwapChain(); + + VkSwapchainKHR GetSwapChain() { return SwapChain; } + VkFormat GetSwapChainImageFormat() { return SwapChainImageFormat; } + VkExtent2D GetSwapChainExtent() { return SwapChainExtent; } + std::vector GetSwapChainImageViews() { return SwapChainImageViews; } + +private: + FSwapConfig SwapConfig; + // VkPhysicalDevice PhysicalDevice; + // VkDevice Device; + // VkSurfaceKHR Surface; + // + // GLFWwindow* Window = nullptr; + + std::vector SwapChainImages; + VkSwapchainKHR SwapChain = VK_NULL_HANDLE; + VkFormat SwapChainImageFormat; + VkExtent2D SwapChainExtent; + + std::vector SwapChainImageViews; + + // bool IsDeviceSuitable(VkPhysicalDevice Device); + // + // int RateDeviceSuitability(VkPhysicalDevice Device); + // + // bool CheckDeviceExtensionSupport(VkPhysicalDevice Device); + + // SwapChainSupportDetails QuerySwapChainSupport(VkPhysicalDevice Device); + + VkSurfaceFormatKHR ChooseSwapSurfaceFormat(const std::vector& AvailableFormats); + + VkPresentModeKHR ChooseSwapPresentMode(const std::vector& AvailablePresentModes); + + VkExtent2D ChooseSwapExtent(const VkSurfaceCapabilitiesKHR& Capabilities); +}; diff --git a/src/public/VulkanVertexBuffer.h b/src/public/VulkanVertexBuffer.h new file mode 100644 index 0000000..f4a7daa --- /dev/null +++ b/src/public/VulkanVertexBuffer.h @@ -0,0 +1,35 @@ +#pragma once + +#include "Primitives.h" + +#include +#include +#include + +#define GLFW_INCLUDE_VULKAN +#include + +struct FVertexBufferConfig +{ + VkDevice Device; + VkPhysicalDevice PhysicalDevice; +}; + +class VulkanVertexBuffer +{ +public: + void Initialize(FVertexBufferConfig InConfig); + + void Cleanup(); + + void CreateVertexBuffer(std::vector InVertices); + + uint32_t FindMemoryType(uint32_t TypeFilter, VkMemoryPropertyFlags Properties); + + VkBuffer GetVertexBuffer() { return VertexBuffer; } + +private: + FVertexBufferConfig Config; + VkBuffer VertexBuffer; + VkDeviceMemory VertexBufferMemory; +}; diff --git a/include/FileReader.h b/src/utilities/FileReader.h old mode 100644 new mode 100755 similarity index 88% rename from include/FileReader.h rename to src/utilities/FileReader.h index 6dd476e..463947b --- a/include/FileReader.h +++ b/src/utilities/FileReader.h @@ -1,26 +1,26 @@ -#pragma once - -#include -#include - -#include "Logger.h" - -static std::vector ReadFile(const std::string& FileName) -{ - std::ifstream File(FileName, std::ios::ate | std::ios::binary); - - if (!File.is_open()) - { - Log::Error("Failed to open file: " + FileName); - } - - size_t FileSize = (size_t)File.tellg(); - std::vector Buffer(FileSize); - - File.seekg(0); - File.read(Buffer.data(), FileSize); - - File.close(); - - return Buffer; -} \ No newline at end of file +#pragma once + +#include +#include + +#include "utilities/Logger.h" + +static std::vector ReadFile(const std::string& FileName) +{ + std::ifstream File(FileName, std::ios::ate | std::ios::binary); + + if (!File.is_open()) + { + Log::Error("Failed to open file: " + FileName); + } + + size_t FileSize = (size_t)File.tellg(); + std::vector Buffer(FileSize); + + File.seekg(0); + File.read(Buffer.data(), FileSize); + + File.close(); + + return Buffer; +} diff --git a/include/Logger.cpp b/src/utilities/Logger.cpp old mode 100644 new mode 100755 similarity index 98% rename from include/Logger.cpp rename to src/utilities/Logger.cpp index 0b8f110..16495b9 --- a/include/Logger.cpp +++ b/src/utilities/Logger.cpp @@ -1,4 +1,4 @@ -#include "Logger.h" +#include "utilities/Logger.h" #include void Log::Message(Level Level, const std::string& Message, const std::source_location& Location) @@ -61,4 +61,4 @@ void Log::Message(Level Level, const std::string& Message, const std::source_loc { throw std::runtime_error(LogMessage); } -} \ No newline at end of file +} diff --git a/include/Logger.h b/src/utilities/Logger.h old mode 100644 new mode 100755 similarity index 100% rename from include/Logger.h rename to src/utilities/Logger.h