Triangle posting

https://vulkan-tutorial.com/Vertex_buffers/Staging_buffer

Reached the above part of the tutorial. Adding IMGUI now before
continuing.
This commit is contained in:
2026-02-17 18:37:38 -05:00
parent ab28c22446
commit 11ac560009
41 changed files with 1961 additions and 999 deletions

View File

@@ -1,5 +1,6 @@
CompileFlags:
Add:
Add:
- -I./include
- -I/usr/include/vulkan
- -I./src
- -I./src/public
- -std=c++20

View File

@@ -140,11 +140,11 @@
<ClCompile Include="GlfwWindowManager.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="VulkanGraphicsPipeline.h" />
<ClInclude Include="VulkanPipeline.h" />
<ClInclude Include="Utilities\FileReader.h" />
<ClInclude Include="VulkanContext.h" />
<ClInclude Include="VulkanDebugManager.h" />
<ClInclude Include="Logger.h" />
<ClInclude Include="utlities/Logger.h" />
<ClInclude Include="VulkanDeviceManager.h" />
<ClInclude Include="VulkanInstanceManager.h" />
<ClInclude Include="GlfwWindowManager.h" />
@@ -157,4 +157,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
</Project>

View File

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
@@ -41,7 +41,7 @@
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Logger.h">
<ClInclude Include="utlities/Logger.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="GlfwWindowManager.h">
@@ -59,7 +59,7 @@
<ClInclude Include="VulkanContext.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="VulkanGraphicsPipeline.h">
<ClInclude Include="VulkanPipeline.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Utilities\FileReader.h">
@@ -75,4 +75,4 @@
<Filter>Shaders</Filter>
</None>
</ItemGroup>
</Project>
</Project>

BIN
LearningVulkan Executable file

Binary file not shown.

View File

@@ -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)

3
Shaders/compile.sh Executable file
View File

@@ -0,0 +1,3 @@
#!/bin/bash
glslc ./shader.vert -o vert.spv
glslc ./shader.frag -o frag.spv

View File

@@ -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];
}
gl_Position = vec4(inPosition, 0.0, 1.0);
fragColor = inColor;
}

Binary file not shown.

View File

@@ -1 +0,0 @@
#include "VulkanContext.h"

View File

@@ -1,52 +0,0 @@
#pragma once
// #include <vector>
// #include <memory>
//
#include "VulkanInstanceManager.h"
#include "VulkanDebugManager.h"
#define GLFW_INCLUDE_VULKAN
#include <GLFW/glfw3.h>
const std::vector<const char*> 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; }
};

View File

@@ -1,442 +0,0 @@
#include "VulkanDeviceManager.h"
#include <vector>
#include <map>
#include <cstdint> // Necessary for uint32_t
#include <limits> // Necessary for std::numeric_limits
#include <algorithm> // Necessary for std::clamp
#include "Logger.h"
#include "GlfwWindowManager.h"
#include <set>
std::vector<VkImage> 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<const char*>& 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<VkPhysicalDevice> Devices(DeviceCount);
vkEnumeratePhysicalDevices(Instance, &DeviceCount, Devices.data());
std::multimap<int, VkPhysicalDevice> 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<VkExtensionProperties> AvailableExtensions(ExtensionCount);
vkEnumerateDeviceExtensionProperties(Device, nullptr, &ExtensionCount, AvailableExtensions.data());
std::set<std::string> 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<VkQueueFamilyProperties> 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<VkDeviceQueueCreateInfo> QueueCreateInfos;
std::set<uint32_t> 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<uint32_t>(QueueCreateInfos.size());
CreateInfo.pQueueCreateInfos = QueueCreateInfos.data();
CreateInfo.pEnabledFeatures = &DeviceFeatures;
CreateInfo.enabledExtensionCount = static_cast<uint32_t>(DeviceExtensions.size());
CreateInfo.ppEnabledExtensionNames = DeviceExtensions.data();
if (bEnableValidationLayers)
{
CreateInfo.enabledLayerCount = static_cast<uint32_t>(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<VkSurfaceFormatKHR>& 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<VkPresentModeKHR>& 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<uint32_t>::max)())
{
return Capabilities.currentExtent;
}
else
{
int Width, Height;
glfwGetFramebufferSize(GlfwWindowManager::Window, &Width, &Height);
VkExtent2D ActualExtent = {
static_cast<uint32_t>(Width),
static_cast<uint32_t>(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.");
}

View File

@@ -1,101 +0,0 @@
#pragma once
#include <optional>
#include <vector>
#include <map>
#include "Logger.h"
#define GLFW_INCLUDE_VULKAN
#include <GLFW/glfw3.h>
const std::vector<const char*> DeviceExtensions = {
VK_KHR_SWAPCHAIN_EXTENSION_NAME
};
struct QueueFamilyIndices
{
std::optional<uint32_t> GraphicsFamily;
std::optional<uint32_t> PresentFamily;
bool IsComplete()
{
return GraphicsFamily.has_value() && PresentFamily.has_value();
}
};
struct SwapChainSupportDetails
{
VkSurfaceCapabilitiesKHR Capabilities;
std::vector<VkSurfaceFormatKHR> Formats;
std::vector<VkPresentModeKHR> 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<const char*>& ValidationLayers);
void Cleanup();
bool IsInitialized() const
{
bool bInitialized = PhysicalDevice && Device && Instance && GraphicsQueue;
return bInitialized;
}
static std::vector<VkImage> 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<VkImageView> SwapChainImageViews;
bool bEnableValidationLayers = false;
const std::vector<const char*>* 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<VkSurfaceFormatKHR>& AvailableFormats);
VkPresentModeKHR ChooseSwapPresentMode(const std::vector<VkPresentModeKHR>& AvailablePresentModes);
VkExtent2D ChooseSwapExtent(const VkSurfaceCapabilitiesKHR& Capabilities);
void CreateSwapChain();
void CreateImageViews();
};

View File

@@ -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<char>& Code)
{
VkShaderModuleCreateInfo CreateInfo{};
CreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
CreateInfo.codeSize = Code.size();
CreateInfo.pCode = reinterpret_cast<const uint32_t*>(Code.data());
VkShaderModule ShaderModule;
// if (vkCreateShaderModule(Device))
return ShaderModule;
}
};

View File

@@ -1,67 +0,0 @@
#pragma once
#include <vector>
#include <memory>
#include "Logger.h"
#include "VulkanDebugManager.h"
#include "VulkanDeviceManager.h"
#include "GlfwWindowManager.h"
#define GLFW_INCLUDE_VULKAN
#include <GLFW/glfw3.h>
const std::vector<const char*> 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<const char*>& GetValidationLayers() const
{
return ValidationLayers;
}
const VkInstance GetInstance() const { return Instance; }
private:
std::unique_ptr<VulkanDebugManager> VkDebugManager = nullptr;
std::unique_ptr<VulkanDeviceManager> VkDeviceManager = nullptr;
bool bValidationEnabled = false;
bool bVerboseLogging = false;
VkInstance Instance = VK_NULL_HANDLE;
std::vector<const char*> GetRequiredExtensions();
bool CheckValidationLayerSupport();
void CreateInstance();
};

58
src/main.cpp Normal file → Executable file
View File

@@ -1,27 +1,27 @@
#include "Logger.h"
#include "VulkanInstanceManager.h"
#include "VulkanDeviceManager.h"
#include "VulkanDebugManager.h"
#include <GLFW/glfw3.h>
#include <vulkan/vulkan_core.h>
#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<Vertex> 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<HelloTriangleApplication*>(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();
}
};

View File

@@ -1,41 +1,15 @@
#include "GlfwWindowManager.h"
#include <algorithm>
#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);
}
}

View File

@@ -0,0 +1,125 @@
#include "VulkanCommandBuffers.h"
#include "utilities/Logger.h"
#include <cstdint>
#include <vulkan/vulkan_core.h>
void VulkanCommandBuffers::Initialize(
VkDevice InDevice,
VkRenderPass InRenderPass)
{
Device = InDevice;
RenderPass = InRenderPass;
}
void VulkanCommandBuffers::Cleanup()
{
vkDestroyCommandPool(Device, CommandPool, nullptr);
}
void VulkanCommandBuffers::CreateCommandPool(std::optional<uint32_t> 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<Vertex> InVertices,
VkRenderPass RenderPass,
VkExtent2D SwapChainExtent,
VkPipeline GraphicsPipeline,
std::vector<VkFramebuffer> 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<float>(SwapChainExtent.width);
Viewport.height = static_cast<float>(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<uint32_t>(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.");
}
}

287
src/private/VulkanContext.cpp Executable file
View File

@@ -0,0 +1,287 @@
#include "VulkanContext.h"
#include "VulkanDeviceManager.h"
#include "VulkanFramebuffers.h"
#include "VulkanSwapChain.h"
#include "VulkanVertexBuffer.h"
#include "utilities/Logger.h"
#include <GLFW/glfw3.h>
#include <cstdint>
#include <vulkan/vulkan_core.h>
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();
}

View File

@@ -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!");
}
}

View File

@@ -0,0 +1,247 @@
#include "VulkanDeviceManager.h"
#include <vector>
#include <map>
#include <cstdint> // Necessary for uint32_t
#include <set>
#include <vulkan/vulkan_core.h>
#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<VkPhysicalDevice> Devices(DeviceCount);
vkEnumeratePhysicalDevices(DeviceConfig.Instance, &DeviceCount, Devices.data());
std::multimap<int, VkPhysicalDevice> 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<VkExtensionProperties> AvailableExtensions(ExtensionCount);
vkEnumerateDeviceExtensionProperties(Device, nullptr, &ExtensionCount, AvailableExtensions.data());
std::set<std::string> 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<VkQueueFamilyProperties> 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<VkDeviceQueueCreateInfo> QueueCreateInfos;
std::set<uint32_t> 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<uint32_t>(QueueCreateInfos.size());
CreateInfo.pQueueCreateInfos = QueueCreateInfos.data();
CreateInfo.pEnabledFeatures = &DeviceFeatures;
CreateInfo.enabledExtensionCount = static_cast<uint32_t>(DeviceExtensions.size());
CreateInfo.ppEnabledExtensionNames = DeviceExtensions.data();
if (DeviceConfig.bEnableValidationLayers)
{
CreateInfo.enabledLayerCount = static_cast<uint32_t>(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;
}

View File

@@ -0,0 +1,48 @@
#include "VulkanFramebuffers.h"
#include "utilities/Logger.h"
#include <vulkan/vulkan_core.h>
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<VkImageView> 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.");
}
}
}

View File

@@ -1,6 +1,8 @@
#include "VulkanInstanceManager.h"
#include "Logger.h"
#include "VulkanContext.h"
#include "utilities/Logger.h"
#include <cstring>
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<VulkanDebugManager>();
// }
//
// 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<VulkanDebugManager>();
}
CreateInstance();
}
void VulkanInstanceManager::SetupDebug()
{
if (bValidationEnabled)
{
VkDebugManager->Initialize(Instance);
}
}
void VulkanInstanceManager::SetupDevice()
{
VkDeviceManager = std::make_unique<VulkanDeviceManager>();
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<const char*> VulkanInstanceManager::GetRequiredExtensions()
std::vector<const char*> VulkanInstanceManager::GetRequiredExtensions(bool bEnableValidationLayers)
{
uint32_t GlfwExtensionCount = 0;
const char** GlfwExtensions;
@@ -116,7 +25,7 @@ std::vector<const char*> VulkanInstanceManager::GetRequiredExtensions()
std::vector<const char*> 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<uint32_t>(Extensions.size());
CreateInfo.ppEnabledExtensionNames = Extensions.data();
if (VkDebugManager)
if (DebugManager)
{
VkDebugUtilsMessengerCreateInfoEXT debugCreateInfo{};
CreateInfo.enabledLayerCount = static_cast<uint32_t>(ValidationLayers.size());
CreateInfo.ppEnabledLayerNames = ValidationLayers.data();
VkDebugManager->PopulateDebugMessengerCreateInfo(debugCreateInfo);
DebugManager->PopulateDebugMessengerCreateInfo(debugCreateInfo);
CreateInfo.pNext = (VkDebugUtilsMessengerCreateInfoEXT*)&debugCreateInfo;
}
else

275
src/private/VulkanPipeline.cpp Executable file
View File

@@ -0,0 +1,275 @@
#include "VulkanPipeline.h"
#include <vulkan/vulkan_core.h>
#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<uint32_t>(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<VkDynamicState> 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<uint32_t>(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<char>& Code)
{
VkShaderModuleCreateInfo CreateInfo{};
CreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
CreateInfo.codeSize = Code.size();
CreateInfo.pCode = reinterpret_cast<const uint32_t*>(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<VkImageView> 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!");
// }
// }
// }

View File

@@ -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.");
}
}

View File

@@ -0,0 +1,203 @@
#include "VulkanSwapChain.h"
#include <vector>
#include <cstdint> // Necessary for uint32_t
#include <limits> // Necessary for std::numeric_limits
#include <algorithm> // Necessary for std::clamp
#include <set>
#include <vulkan/vulkan_core.h>
#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<VkSurfaceFormatKHR>& 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<VkPresentModeKHR>& 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<uint32_t>::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<uint32_t>(Width),
static_cast<uint32_t>(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();
// }

View File

@@ -0,0 +1,74 @@
#include "VulkanVertexBuffer.h"
#include "utilities/Logger.h"
#include <cstdint>
#include <vulkan/vulkan_core.h>
#include <cstring>
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<Vertex> 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!");
}

View File

@@ -2,11 +2,11 @@
#include <string>
#define GLFW_INCLUDE_VULKAN
#include <vulkan/vulkan_core.h>
#define GLFW_INCLUDE_VULKAN
#include <GLFW/glfw3.h>
#include <GLFW/glfw3native.h>
#include <vulkan/vulkan_core.h>
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();

36
src/public/Primitives.h Normal file
View File

@@ -0,0 +1,36 @@
#include <glm/glm.hpp>
#include <vulkan/vulkan_core.h>
#include <array>
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<VkVertexInputAttributeDescription, 2> GetAttributeDescriptions()
{
std::array<VkVertexInputAttributeDescription, 2> 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;
}
};

View File

@@ -0,0 +1,45 @@
#pragma once
#include "VulkanVertexBuffer.h"
#include <vulkan/vulkan_core.h>
#define GLFW_INCLUDE_VULKAN
#include <GLFW/glfw3.h>
#include <vector>
#include <optional>
class VulkanCommandBuffers
{
public:
void Initialize(
VkDevice InDevice,
VkRenderPass InRenderPass);
void Cleanup();
void CreateCommandPool(std::optional<uint32_t> GraphicsFamily);
void CreateCommandBuffers(int FramesInFlight);
void RecordCommandBuffer(
VkCommandBuffer InCommandBuffer,
uint32_t ImageIndex,
VkBuffer InVertexBuffer,
std::vector<Vertex> InVertices,
VkRenderPass RenderPass,
VkExtent2D SwapChainExtent,
VkPipeline GraphicsPipeline,
std::vector<VkFramebuffer> SwapChainFramebuffers);
std::vector<VkCommandBuffer> GetCommandBuffers() { return CommandBuffers; }
VkCommandBuffer GetCommandBuffer(int i) { return CommandBuffers[i]; }
private:
VkDevice Device;
VkRenderPass RenderPass;
VkQueue GraphicsQueue;
std::vector<VkCommandBuffer> CommandBuffers;
VkCommandPool CommandPool;
};

77
src/public/VulkanContext.h Executable file
View File

@@ -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 <vector>
#include <vulkan/vulkan_core.h>
#define GLFW_INCLUDE_VULKAN
#include <GLFW/glfw3.h>
static const std::vector<const char*> ValidationLayers = {
"VK_LAYER_KHRONOS_validation"
};
struct FVulkanConfig
{
bool bValidationEnabled = true;
bool bVerboseLogging = false;
GLFWwindow* Window = nullptr;
std::vector<Vertex> 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<VkSemaphore> ImageAvailableSemaphores;
std::vector<VkSemaphore> RenderFinishedSemaphores;
std::vector<VkFence> InFlightFences;
bool bFramebufferResized = false;
const int MAX_FRAMES_IN_FLIGHT = 2;
uint32_t CurrentFrame = 0;
};

View File

@@ -3,7 +3,7 @@
#define GLFW_INCLUDE_VULKAN
#include <GLFW/glfw3.h>
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,

View File

@@ -0,0 +1,86 @@
#pragma once
#include <optional>
#include <vector>
#include <vulkan/vulkan_core.h>
#define GLFW_INCLUDE_VULKAN
#include <GLFW/glfw3.h>
struct FDeviceConfig
{
VkInstance Instance;
bool bEnableValidationLayers;
VkSurfaceKHR Surface;
GLFWwindow* Window;
};
struct QueueFamilyIndices
{
std::optional<uint32_t> GraphicsFamily;
std::optional<uint32_t> PresentFamily;
bool IsComplete()
{
return GraphicsFamily.has_value() && PresentFamily.has_value();
}
};
struct SwapChainSupportDetails
{
VkSurfaceCapabilitiesKHR Capabilities;
std::vector<VkSurfaceFormatKHR> Formats;
std::vector<VkPresentModeKHR> 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);
};

View File

@@ -0,0 +1,39 @@
#pragma once
#include <vulkan/vulkan_core.h>
#define GLFW_INCLUDE_VULKAN
#include <GLFW/glfw3.h>
#include <vector>
struct FFramebufferConfig
{
VkDevice Device;
VkRenderPass RenderPass;
std::vector<VkImageView> SwapChainImageViews;
VkExtent2D SwapChainExtent;
};
class VulkanFramebuffers
{
public:
void Initialize(FFramebufferConfig InConfig);
void Cleanup();
void CreateFramebuffers();
// void CreateFramebuffers(VkRenderPass RenderPass, std::vector<VkImageView> SwapChainImageViews, VkExtent2D SwapChainExtent);
std::vector<VkFramebuffer> GetSwapChainFrameBuffers() { return SwapChainFramebuffers; }
// void CreateCommandPool(std::optional<uint32_t> GraphicsFamily);
//
// void CreateCommandBuffer();
//
// void RecordCommandBuffer(VkCommandBuffer CommandBuffer, uint32_t imageIndex, VkRenderPass RenderPass, VkExtent2D SwapChainExtent, VkPipeline GraphicsPipeline);
private:
FFramebufferConfig FramebufferConfig;
std::vector<VkFramebuffer> SwapChainFramebuffers;
};

View File

@@ -0,0 +1,27 @@
#pragma once
#include <vector>
#define GLFW_INCLUDE_VULKAN
#include <GLFW/glfw3.h>
#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<const char*> GetRequiredExtensions(bool bEnableValidationLayers);
bool CheckValidationLayerSupport();
};

33
src/public/VulkanPipeline.h Executable file
View File

@@ -0,0 +1,33 @@
#pragma once
#define GLFW_INCLUDE_VULKAN
#include <GLFW/glfw3.h>
#include <vector>
class VulkanPipeline
{
public:
void Initialize(VkDevice InDevice);
void Cleanup();
// void CreateRenderPass(VkFormat SwapChainImageFormat);
// void CreateFramebuffers(std::vector<VkImageView> SwapChainImageViews, VkExtent2D SwapChainExtent);
VkShaderModule CreateShaderModule(const std::vector<char>& 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<VkFramebuffer> SwapChainFrameBuffers;
};

View File

@@ -0,0 +1,20 @@
#pragma once
#define GLFW_INCLUDE_VULKAN
#include <GLFW/glfw3.h>
class VulkanRenderPass
{
public:
void Initialize(VkDevice InDevice);
void Cleanup();
void CreateRenderPass(VkFormat SwapChainImageFormat);
VkRenderPass GetRenderPass() { return RenderPass; }
private:
VkDevice Device;
VkRenderPass RenderPass;
};

View File

@@ -0,0 +1,93 @@
#pragma once
#include <optional>
#include <vector>
#include <vulkan/vulkan_core.h>
#define GLFW_INCLUDE_VULKAN
#include <GLFW/glfw3.h>
const std::vector<const char*> DeviceExtensions = {
VK_KHR_SWAPCHAIN_EXTENSION_NAME
};
//
// struct SwapChainSupportDetails
// {
// VkSurfaceCapabilitiesKHR Capabilities;
// std::vector<VkSurfaceFormatKHR> Formats;
// std::vector<VkPresentModeKHR> PresentModes;
// };
struct FSwapConfig
{
VkDevice Device;
VkSurfaceKHR Surface;
GLFWwindow* Window;
std::optional<uint32_t> GraphicsFamily;
std::optional<uint32_t> PresentFamily;
VkSurfaceCapabilitiesKHR Capabilities;
std::vector<VkSurfaceFormatKHR> Formats;
std::vector<VkPresentModeKHR> 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<uint32_t> GraphicsFamily,
// std::optional<uint32_t> PresentFamily,
// VkSurfaceCapabilitiesKHR Capabilities,
// std::vector<VkSurfaceFormatKHR> Formats,
// std::vector<VkPresentModeKHR> PresentModes);
void CreateImageViews();
// void RecreateSwapChain();
VkSwapchainKHR GetSwapChain() { return SwapChain; }
VkFormat GetSwapChainImageFormat() { return SwapChainImageFormat; }
VkExtent2D GetSwapChainExtent() { return SwapChainExtent; }
std::vector<VkImageView> GetSwapChainImageViews() { return SwapChainImageViews; }
private:
FSwapConfig SwapConfig;
// VkPhysicalDevice PhysicalDevice;
// VkDevice Device;
// VkSurfaceKHR Surface;
//
// GLFWwindow* Window = nullptr;
std::vector<VkImage> SwapChainImages;
VkSwapchainKHR SwapChain = VK_NULL_HANDLE;
VkFormat SwapChainImageFormat;
VkExtent2D SwapChainExtent;
std::vector<VkImageView> SwapChainImageViews;
// bool IsDeviceSuitable(VkPhysicalDevice Device);
//
// int RateDeviceSuitability(VkPhysicalDevice Device);
//
// bool CheckDeviceExtensionSupport(VkPhysicalDevice Device);
// SwapChainSupportDetails QuerySwapChainSupport(VkPhysicalDevice Device);
VkSurfaceFormatKHR ChooseSwapSurfaceFormat(const std::vector<VkSurfaceFormatKHR>& AvailableFormats);
VkPresentModeKHR ChooseSwapPresentMode(const std::vector<VkPresentModeKHR>& AvailablePresentModes);
VkExtent2D ChooseSwapExtent(const VkSurfaceCapabilitiesKHR& Capabilities);
};

View File

@@ -0,0 +1,35 @@
#pragma once
#include "Primitives.h"
#include <optional>
#include <vector>
#include <vulkan/vulkan_core.h>
#define GLFW_INCLUDE_VULKAN
#include <GLFW/glfw3.h>
struct FVertexBufferConfig
{
VkDevice Device;
VkPhysicalDevice PhysicalDevice;
};
class VulkanVertexBuffer
{
public:
void Initialize(FVertexBufferConfig InConfig);
void Cleanup();
void CreateVertexBuffer(std::vector<Vertex> InVertices);
uint32_t FindMemoryType(uint32_t TypeFilter, VkMemoryPropertyFlags Properties);
VkBuffer GetVertexBuffer() { return VertexBuffer; }
private:
FVertexBufferConfig Config;
VkBuffer VertexBuffer;
VkDeviceMemory VertexBufferMemory;
};

52
include/FileReader.h → src/utilities/FileReader.h Normal file → Executable file
View File

@@ -1,26 +1,26 @@
#pragma once
#include <fstream>
#include <vector>
#include "Logger.h"
static std::vector<char> 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<char> Buffer(FileSize);
File.seekg(0);
File.read(Buffer.data(), FileSize);
File.close();
return Buffer;
}
#pragma once
#include <fstream>
#include <vector>
#include "utilities/Logger.h"
static std::vector<char> 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<char> Buffer(FileSize);
File.seekg(0);
File.read(Buffer.data(), FileSize);
File.close();
return Buffer;
}

4
include/Logger.cpp → src/utilities/Logger.cpp Normal file → Executable file
View File

@@ -1,4 +1,4 @@
#include "Logger.h"
#include "utilities/Logger.h"
#include <iostream>
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);
}
}
}

0
include/Logger.h → src/utilities/Logger.h Normal file → Executable file
View File