First commit from Arch
This commit is contained in:
212
src/GlfwWindowManager.cpp
Normal file
212
src/GlfwWindowManager.cpp
Normal file
@@ -0,0 +1,212 @@
|
||||
#include "GlfwWindowManager.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "Logger.h"
|
||||
|
||||
VkSurfaceKHR GlfwWindowManager::Surface = VK_NULL_HANDLE;
|
||||
GLFWwindow* GlfwWindowManager::Window = nullptr;
|
||||
|
||||
GlfwWindowManager::GlfwWindowManager() = default;
|
||||
|
||||
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())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this->Config = Config;
|
||||
|
||||
InitializeGlfw();
|
||||
}
|
||||
|
||||
void GlfwWindowManager::Cleanup(VkInstance Instance)
|
||||
{
|
||||
if (!IsInitialized())
|
||||
{
|
||||
Log::Warning("Not initialized");
|
||||
return;
|
||||
}
|
||||
|
||||
DestroyWindow();
|
||||
|
||||
glfwTerminate();
|
||||
}
|
||||
|
||||
bool GlfwWindowManager::ShouldClose() const
|
||||
{
|
||||
return Window && glfwWindowShouldClose(Window);
|
||||
}
|
||||
|
||||
void GlfwWindowManager::PollEvents()
|
||||
{
|
||||
if (Window)
|
||||
{
|
||||
glfwPollEvents();
|
||||
}
|
||||
}
|
||||
|
||||
void GlfwWindowManager::WaitEvents() const
|
||||
{
|
||||
if (Window)
|
||||
{
|
||||
glfwWaitEvents();
|
||||
}
|
||||
}
|
||||
|
||||
void GlfwWindowManager::SetTitle(const std::string& Title)
|
||||
{
|
||||
// this->Title = Title;
|
||||
|
||||
if (Window)
|
||||
{
|
||||
glfwSetWindowTitle(Window, Title.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
glfwSetWindowSizeCallback(Window, Callback);
|
||||
}
|
||||
}
|
||||
|
||||
void GlfwWindowManager::SetKeyCallback(GLFWkeyfun Callback)
|
||||
{
|
||||
if (Window)
|
||||
{
|
||||
glfwSetKeyCallback(Window, Callback);
|
||||
}
|
||||
}
|
||||
|
||||
void GlfwWindowManager::SetMouseButtonCallback(GLFWmousebuttonfun Callback)
|
||||
{
|
||||
if (Window)
|
||||
{
|
||||
glfwSetMouseButtonCallback(Window, Callback);
|
||||
}
|
||||
}
|
||||
|
||||
void GlfwWindowManager::SetCursorPositionCallback(GLFWcursorposfun Callback)
|
||||
{
|
||||
if (Window)
|
||||
{
|
||||
glfwSetCursorPosCallback(Window, Callback);
|
||||
}
|
||||
}
|
||||
|
||||
void GlfwWindowManager::SetScrollCallback(GLFWscrollfun Callback)
|
||||
{
|
||||
if (Window)
|
||||
{
|
||||
glfwSetScrollCallback(Window, Callback);
|
||||
}
|
||||
}
|
||||
|
||||
void GlfwWindowManager::DestroyWindow()
|
||||
{
|
||||
if (Window)
|
||||
{
|
||||
glfwDestroyWindow(Window);
|
||||
Window = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void GlfwWindowManager::InitializeGlfw()
|
||||
{
|
||||
if (!IsInitialized())
|
||||
{
|
||||
if (!glfwInit())
|
||||
{
|
||||
Log::Error("Failed to initialize GLFW");
|
||||
}
|
||||
}
|
||||
|
||||
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
||||
glfwWindowHint(GLFW_RESIZABLE, Config.bResizable ? GLFW_TRUE : GLFW_FALSE);
|
||||
|
||||
Window = glfwCreateWindow(
|
||||
Config.Width,
|
||||
Config.Height,
|
||||
Config.Title.c_str(),
|
||||
Config.bFullscreen ? glfwGetPrimaryMonitor() : nullptr,
|
||||
nullptr);
|
||||
|
||||
if (!Window)
|
||||
{
|
||||
Log::Error("Failed to create GLFW window");
|
||||
}
|
||||
else
|
||||
{
|
||||
Log::Info("Created GLFW window successfully.");
|
||||
}
|
||||
}
|
||||
67
src/GlfwWindowManager.h
Normal file
67
src/GlfwWindowManager.h
Normal file
@@ -0,0 +1,67 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
#define GLFW_INCLUDE_VULKAN
|
||||
|
||||
#include <GLFW/glfw3.h>
|
||||
#include <GLFW/glfw3native.h>
|
||||
#include <vulkan/vulkan_core.h>
|
||||
|
||||
struct FWindowConfig
|
||||
{
|
||||
std::string Title = "Learning Vulkan";
|
||||
uint32_t Width = 800;
|
||||
uint32_t Height = 600;
|
||||
bool bResizable = false;
|
||||
bool bFullscreen = false;
|
||||
};
|
||||
|
||||
class GlfwWindowManager
|
||||
{
|
||||
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);
|
||||
|
||||
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; }
|
||||
|
||||
void SetResizeCallback(GLFWwindowsizefun Callback);
|
||||
void SetKeyCallback(GLFWkeyfun Callback);
|
||||
void SetMouseButtonCallback(GLFWmousebuttonfun Callback);
|
||||
void SetCursorPositionCallback(GLFWcursorposfun Callback);
|
||||
void SetScrollCallback(GLFWscrollfun Callback);
|
||||
|
||||
void CreateSurface(VkInstance Instance);
|
||||
|
||||
static VkSurfaceKHR Surface;
|
||||
|
||||
static GLFWwindow* Window;
|
||||
|
||||
private:
|
||||
FWindowConfig Config;
|
||||
|
||||
// VkSurfaceKHR Surface = VK_NULL_HANDLE;
|
||||
|
||||
void InitializeGlfw();
|
||||
|
||||
void DestroyWindow();
|
||||
};
|
||||
1
src/VulkanContext.cpp
Normal file
1
src/VulkanContext.cpp
Normal file
@@ -0,0 +1 @@
|
||||
#include "VulkanContext.h"
|
||||
52
src/VulkanContext.h
Normal file
52
src/VulkanContext.h
Normal file
@@ -0,0 +1,52 @@
|
||||
#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; }
|
||||
};
|
||||
120
src/VulkanDebugManager.cpp
Normal file
120
src/VulkanDebugManager.cpp
Normal file
@@ -0,0 +1,120 @@
|
||||
#include "VulkanDebugManager.h"
|
||||
#include "Logger.h"
|
||||
|
||||
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)
|
||||
{
|
||||
if (IsInitialized())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this->Instance = Instance;
|
||||
SetupDebugMessanger();
|
||||
}
|
||||
|
||||
void VulkanDebugManager::Cleanup()
|
||||
{
|
||||
if (!IsInitialized())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
FDestroyDebugUtilsMessengerExtParams Params = { Instance, DebugMessenger, nullptr };
|
||||
DestroyDebugUtilsMessengerExt(Params);
|
||||
DebugMessenger = VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
VkResult VulkanDebugManager::CreateDebugUtilsMessengerExt(const FCreateDebugUtilsMessengerExtParams& Params)
|
||||
{
|
||||
auto func = (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(Params.Instance, "vkCreateDebugUtilsMessengerEXT");
|
||||
if (func != nullptr)
|
||||
{
|
||||
return func(Params.Instance, Params.pCreateInfo, Params.pAllocator, Params.pDebugMessenger);
|
||||
}
|
||||
else
|
||||
{
|
||||
return VK_ERROR_EXTENSION_NOT_PRESENT;
|
||||
}
|
||||
}
|
||||
|
||||
void VulkanDebugManager::DestroyDebugUtilsMessengerExt(const FDestroyDebugUtilsMessengerExtParams& Params)
|
||||
{
|
||||
auto func = (PFN_vkDestroyDebugUtilsMessengerEXT)vkGetInstanceProcAddr(
|
||||
Params.Instance,
|
||||
"vkDestroyDebugUtilsMessengerEXT");
|
||||
|
||||
if (func != nullptr)
|
||||
{
|
||||
func(Params.Instance, Params.DebugMessenger, Params.pAllocator);
|
||||
}
|
||||
}
|
||||
|
||||
VKAPI_ATTR VkBool32 VKAPI_CALL VulkanDebugManager::DebugCallback(
|
||||
VkDebugUtilsMessageSeverityFlagBitsEXT MessageSeverity,
|
||||
VkDebugUtilsMessageTypeFlagsEXT MessageType,
|
||||
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
|
||||
void* pUserData)
|
||||
{
|
||||
Log::Validation(pCallbackData->pMessage);
|
||||
// std::cerr << "[Validation layer] : " << pCallbackData->pMessage << std::endl;
|
||||
|
||||
if (MessageSeverity >= VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT)
|
||||
{
|
||||
}
|
||||
|
||||
return VK_FALSE;
|
||||
}
|
||||
|
||||
void VulkanDebugManager::PopulateDebugMessengerCreateInfo(VkDebugUtilsMessengerCreateInfoEXT& createInfo)
|
||||
{
|
||||
createInfo = {};
|
||||
createInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
|
||||
createInfo.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
|
||||
createInfo.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
|
||||
createInfo.pfnUserCallback = VulkanDebugManager::DebugCallback;
|
||||
}
|
||||
|
||||
void VulkanDebugManager::SetupDebugMessanger()
|
||||
{
|
||||
VkDebugUtilsMessengerCreateInfoEXT CreateInfo;
|
||||
|
||||
PopulateDebugMessengerCreateInfo(CreateInfo);
|
||||
|
||||
FCreateDebugUtilsMessengerExtParams 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!");
|
||||
}
|
||||
}
|
||||
58
src/VulkanDebugManager.h
Normal file
58
src/VulkanDebugManager.h
Normal file
@@ -0,0 +1,58 @@
|
||||
#pragma once
|
||||
|
||||
#define GLFW_INCLUDE_VULKAN
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
struct FCreateDebugUtilsMessengerExtParams
|
||||
{
|
||||
VkInstance Instance;
|
||||
const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo;
|
||||
const VkAllocationCallbacks* pAllocator;
|
||||
VkDebugUtilsMessengerEXT* pDebugMessenger;
|
||||
};
|
||||
|
||||
struct FDestroyDebugUtilsMessengerExtParams
|
||||
{
|
||||
VkInstance Instance;
|
||||
VkDebugUtilsMessengerEXT DebugMessenger;
|
||||
const VkAllocationCallbacks* pAllocator;
|
||||
};
|
||||
|
||||
class VulkanDebugManager
|
||||
{
|
||||
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();
|
||||
|
||||
bool IsInitialized() const { return DebugMessenger != VK_NULL_HANDLE; }
|
||||
|
||||
void PopulateDebugMessengerCreateInfo(VkDebugUtilsMessengerCreateInfoEXT& createInfo);
|
||||
|
||||
private:
|
||||
bool bVerboseLogging = false;
|
||||
|
||||
VkInstance Instance = VK_NULL_HANDLE;
|
||||
|
||||
VkDebugUtilsMessengerEXT DebugMessenger = VK_NULL_HANDLE;
|
||||
|
||||
VkResult CreateDebugUtilsMessengerExt(const FCreateDebugUtilsMessengerExtParams& Params);
|
||||
|
||||
void DestroyDebugUtilsMessengerExt(const FDestroyDebugUtilsMessengerExtParams& Params);
|
||||
|
||||
static VKAPI_ATTR VkBool32 VKAPI_CALL DebugCallback(
|
||||
VkDebugUtilsMessageSeverityFlagBitsEXT MessageSeverity,
|
||||
VkDebugUtilsMessageTypeFlagsEXT MessageType,
|
||||
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
|
||||
void* pUserData);
|
||||
|
||||
void SetupDebugMessanger();
|
||||
};
|
||||
442
src/VulkanDeviceManager.cpp
Normal file
442
src/VulkanDeviceManager.cpp
Normal file
@@ -0,0 +1,442 @@
|
||||
#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.");
|
||||
}
|
||||
101
src/VulkanDeviceManager.h
Normal file
101
src/VulkanDeviceManager.h
Normal file
@@ -0,0 +1,101 @@
|
||||
#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();
|
||||
};
|
||||
29
src/VulkanGraphicsPipeline.h
Normal file
29
src/VulkanGraphicsPipeline.h
Normal file
@@ -0,0 +1,29 @@
|
||||
#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;
|
||||
}
|
||||
};
|
||||
201
src/VulkanInstanceManager.cpp
Normal file
201
src/VulkanInstanceManager.cpp
Normal file
@@ -0,0 +1,201 @@
|
||||
#include "VulkanInstanceManager.h"
|
||||
|
||||
#include "Logger.h"
|
||||
|
||||
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()
|
||||
{
|
||||
uint32_t GlfwExtensionCount = 0;
|
||||
const char** GlfwExtensions;
|
||||
GlfwExtensions = glfwGetRequiredInstanceExtensions(&GlfwExtensionCount);
|
||||
|
||||
std::vector<const char*> Extensions(GlfwExtensions, GlfwExtensions + GlfwExtensionCount);
|
||||
|
||||
if (VkDebugManager)
|
||||
{
|
||||
Extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
|
||||
}
|
||||
|
||||
return Extensions;
|
||||
}
|
||||
|
||||
bool VulkanInstanceManager::CheckValidationLayerSupport()
|
||||
{
|
||||
uint32_t LayerCount;
|
||||
vkEnumerateInstanceLayerProperties(&LayerCount, nullptr);
|
||||
|
||||
std::vector<VkLayerProperties> AvailableLayers(LayerCount);
|
||||
vkEnumerateInstanceLayerProperties(&LayerCount, AvailableLayers.data());
|
||||
|
||||
for (const char* LayerName : ValidationLayers)
|
||||
{
|
||||
bool bLayerFound = false;
|
||||
|
||||
for (const auto& LayerProperties : AvailableLayers)
|
||||
{
|
||||
if (strcmp(LayerName, LayerProperties.layerName) == 0)
|
||||
{
|
||||
bLayerFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!bLayerFound)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void VulkanInstanceManager::CreateInstance()
|
||||
{
|
||||
Log::Info("Creating Vulkan instance.");
|
||||
|
||||
if (bValidationEnabled && !CheckValidationLayerSupport())
|
||||
{
|
||||
Log::Error("Validation layers requested, but not available!");
|
||||
}
|
||||
|
||||
VkApplicationInfo AppInfo{};
|
||||
AppInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
|
||||
AppInfo.pApplicationName = "Hello Triangle";
|
||||
AppInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
|
||||
AppInfo.pEngineName = "No Engine";
|
||||
AppInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
|
||||
AppInfo.apiVersion = VK_API_VERSION_1_0;
|
||||
|
||||
VkInstanceCreateInfo CreateInfo{};
|
||||
CreateInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
|
||||
CreateInfo.pApplicationInfo = &AppInfo;
|
||||
|
||||
auto Extensions = GetRequiredExtensions();
|
||||
CreateInfo.enabledExtensionCount = static_cast<uint32_t>(Extensions.size());
|
||||
CreateInfo.ppEnabledExtensionNames = Extensions.data();
|
||||
|
||||
if (VkDebugManager)
|
||||
{
|
||||
VkDebugUtilsMessengerCreateInfoEXT debugCreateInfo{};
|
||||
CreateInfo.enabledLayerCount = static_cast<uint32_t>(ValidationLayers.size());
|
||||
CreateInfo.ppEnabledLayerNames = ValidationLayers.data();
|
||||
|
||||
VkDebugManager->PopulateDebugMessengerCreateInfo(debugCreateInfo);
|
||||
CreateInfo.pNext = (VkDebugUtilsMessengerCreateInfoEXT*)&debugCreateInfo;
|
||||
}
|
||||
else
|
||||
{
|
||||
CreateInfo.enabledLayerCount = 0;
|
||||
CreateInfo.pNext = nullptr;
|
||||
}
|
||||
|
||||
if (vkCreateInstance(&CreateInfo, nullptr, &Instance) != VK_SUCCESS)
|
||||
{
|
||||
Log::Error("Failed to create instance!");
|
||||
}
|
||||
}
|
||||
67
src/VulkanInstanceManager.h
Normal file
67
src/VulkanInstanceManager.h
Normal file
@@ -0,0 +1,67 @@
|
||||
#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();
|
||||
};
|
||||
102
src/main.cpp
Normal file
102
src/main.cpp
Normal file
@@ -0,0 +1,102 @@
|
||||
|
||||
#include "Logger.h"
|
||||
#include "VulkanInstanceManager.h"
|
||||
#include "VulkanDeviceManager.h"
|
||||
#include "VulkanDebugManager.h"
|
||||
#include "GlfwWindowManager.h"
|
||||
#include "VulkanGraphicsPipeline.h"
|
||||
// #include "VulkanContext.h"
|
||||
|
||||
struct AppConfig
|
||||
{
|
||||
std::string Title = "Learning Vulkan";
|
||||
uint32_t Width = 800;
|
||||
uint32_t Height = 600;
|
||||
bool bResizable = false;
|
||||
bool bFullscreen = false;
|
||||
bool bValidationEnabled = true;
|
||||
bool bVerboseLogging = false;
|
||||
};
|
||||
|
||||
void test () {
|
||||
if (true) return;
|
||||
|
||||
}
|
||||
|
||||
class HelloTriangleApplication
|
||||
{
|
||||
public:
|
||||
void Run()
|
||||
{
|
||||
Initialization();
|
||||
MainLoop();
|
||||
Cleanup();
|
||||
}
|
||||
|
||||
private:
|
||||
AppConfig Settings = {};
|
||||
|
||||
VulkanInstanceManager InstanceManager;
|
||||
GlfwWindowManager WindowManager;
|
||||
|
||||
void Initialization()
|
||||
{
|
||||
InitGlfw();
|
||||
InitVulkan();
|
||||
InstanceManager.SetupDebug();
|
||||
WindowManager.CreateSurface(InstanceManager.GetInstance());
|
||||
InstanceManager.SetupDevice();
|
||||
}
|
||||
|
||||
void InitVulkan()
|
||||
{
|
||||
FVulkanConfig Config = {
|
||||
Settings.bValidationEnabled,
|
||||
Settings.bVerboseLogging
|
||||
};
|
||||
InstanceManager.Initialize(Config);
|
||||
}
|
||||
|
||||
void InitGlfw()
|
||||
{
|
||||
FWindowConfig Config = {
|
||||
Settings.Title,
|
||||
Settings.Width,
|
||||
Settings.Height,
|
||||
Settings.bResizable,
|
||||
Settings.bFullscreen
|
||||
};
|
||||
WindowManager.Initialize(Config);
|
||||
}
|
||||
|
||||
void MainLoop()
|
||||
{
|
||||
while (!WindowManager.ShouldClose())
|
||||
{
|
||||
WindowManager.PollEvents();
|
||||
}
|
||||
}
|
||||
|
||||
void Cleanup()
|
||||
{
|
||||
WindowManager.Cleanup(InstanceManager.GetInstance());
|
||||
InstanceManager.Cleanup();
|
||||
}
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
HelloTriangleApplication app;
|
||||
|
||||
try
|
||||
{
|
||||
app.Run();
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
Log::Error(e.what());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
Reference in New Issue
Block a user