Initial Gitea Commit

This commit is contained in:
onTheZero
2026-01-05 10:36:27 -05:00
parent 5b32d32b0b
commit fa7ae9ac1c
19 changed files with 1372 additions and 288 deletions

View File

@@ -12,6 +12,7 @@ AllowShortBlocksOnASingleLine: Empty
AllowShortEnumsOnASingleLine: false AllowShortEnumsOnASingleLine: false
AllowShortFunctionsOnASingleLine: Inline AllowShortFunctionsOnASingleLine: Inline
AllowShortLambdasOnASingleLine: All AllowShortLambdasOnASingleLine: All
InsertBraces: true
BraceWrapping: BraceWrapping:
AfterCaseLabel: true AfterCaseLabel: true
AfterClass: true AfterClass: true

179
.editorconfig Normal file
View File

@@ -0,0 +1,179 @@
# Visual Studio generated .editorconfig file with C++ settings.
root = true
[*.{c++,cc,cpp,cppm,cxx,h,h++,hh,hpp,hxx,inl,ipp,ixx,tlh,tli}]
# Visual C++ Code Style settings
cpp_generate_documentation_comments = xml
# Visual C++ Formatting settings
indent_style = tab
indent_size = 4
tab_width= 4
cpp_indent_braces = false
cpp_indent_multi_line_relative_to = innermost_parenthesis
cpp_indent_within_parentheses = indent
cpp_indent_preserve_within_parentheses = false
cpp_indent_case_contents = true
cpp_indent_case_labels = false
cpp_indent_case_contents_when_block = false
cpp_indent_lambda_braces_when_parameter = true
cpp_indent_goto_labels = one_left
cpp_indent_preprocessor = leftmost_column
cpp_indent_access_specifiers = false
cpp_indent_namespace_contents = true
cpp_indent_preserve_comments = false
cpp_new_line_before_open_brace_namespace = ignore
cpp_new_line_before_open_brace_type = ignore
cpp_new_line_before_open_brace_function = ignore
cpp_new_line_before_open_brace_block = ignore
cpp_new_line_before_open_brace_lambda = ignore
cpp_new_line_scope_braces_on_separate_lines = false
cpp_new_line_close_brace_same_line_empty_type = false
cpp_new_line_close_brace_same_line_empty_function = false
cpp_new_line_before_catch = true
cpp_new_line_before_else = true
cpp_new_line_before_while_in_do_while = false
cpp_space_before_function_open_parenthesis = remove
cpp_space_within_parameter_list_parentheses = false
cpp_space_between_empty_parameter_list_parentheses = false
cpp_space_after_keywords_in_control_flow_statements = true
cpp_space_within_control_flow_statement_parentheses = false
cpp_space_before_lambda_open_parenthesis = false
cpp_space_within_cast_parentheses = false
cpp_space_after_cast_close_parenthesis = false
cpp_space_within_expression_parentheses = false
cpp_space_before_block_open_brace = true
cpp_space_between_empty_braces = false
cpp_space_before_initializer_list_open_brace = false
cpp_space_within_initializer_list_braces = true
cpp_space_preserve_in_initializer_list = true
cpp_space_before_open_square_bracket = false
cpp_space_within_square_brackets = false
cpp_space_before_empty_square_brackets = false
cpp_space_between_empty_square_brackets = false
cpp_space_group_square_brackets = true
cpp_space_within_lambda_brackets = false
cpp_space_between_empty_lambda_brackets = false
cpp_space_before_comma = false
cpp_space_after_comma = true
cpp_space_remove_around_member_operators = true
cpp_space_before_inheritance_colon = true
cpp_space_before_constructor_colon = true
cpp_space_remove_before_semicolon = true
cpp_space_after_semicolon = true
cpp_space_remove_around_unary_operator = true
cpp_space_around_binary_operator = insert
cpp_space_around_assignment_operator = insert
cpp_space_pointer_reference_alignment = left
cpp_space_around_ternary_operator = insert
cpp_use_unreal_engine_macro_formatting = true
cpp_wrap_preserve_blocks = one_liners
# Visual C++ Include Cleanup settings
cpp_include_cleanup_add_missing_error_tag_type = suggestion
cpp_include_cleanup_remove_unused_error_tag_type = dimmed
cpp_include_cleanup_optimize_unused_error_tag_type = suggestion
cpp_include_cleanup_sort_after_edits = false
cpp_sort_includes_error_tag_type = none
cpp_sort_includes_priority_case_sensitive = false
cpp_sort_includes_priority_style = quoted
cpp_includes_style = default
cpp_includes_use_forward_slash = true
# Unreal naming conventions
[*.{cpp,h}]
# Naming convention rules (note: currently need to be ordered from more to less specific)
cpp_naming_rule.aactor_prefixed.symbols = aactor_class
cpp_naming_rule.aactor_prefixed.style = aactor_style
cpp_naming_rule.swidget_prefixed.symbols = swidget_class
cpp_naming_rule.swidget_prefixed.style = swidget_style
cpp_naming_rule.uobject_prefixed.symbols = uobject_class
cpp_naming_rule.uobject_prefixed.style = uobject_style
cpp_naming_rule.booleans_prefixed.symbols = boolean_vars
cpp_naming_rule.booleans_prefixed.style = boolean_style
cpp_naming_rule.structs_prefixed.symbols = structs
cpp_naming_rule.structs_prefixed.style = unreal_engine_structs
cpp_naming_rule.enums_prefixed.symbols = enums
cpp_naming_rule.enums_prefixed.style = unreal_engine_enums
cpp_naming_rule.templates_prefixed.symbols = templates
cpp_naming_rule.templates_prefixed.style = unreal_engine_templates
cpp_naming_rule.general_names.symbols = all_symbols
cpp_naming_rule.general_names.style = unreal_engine_default
# Naming convention symbols
cpp_naming_symbols.aactor_class.applicable_kinds = class
cpp_naming_symbols.aactor_class.applicable_type = AActor
cpp_naming_symbols.swidget_class.applicable_kinds = class
cpp_naming_symbols.swidget_class.applicable_type = SWidget
cpp_naming_symbols.uobject_class.applicable_kinds = class
cpp_naming_symbols.uobject_class.applicable_type = UObject
cpp_naming_symbols.boolean_vars.applicable_kinds = local,parameter,field
cpp_naming_symbols.boolean_vars.applicable_type = bool
cpp_naming_symbols.enums.applicable_kinds = enum
cpp_naming_symbols.templates.applicable_kinds = template_class
cpp_naming_symbols.structs.applicable_kinds = struct
cpp_naming_symbols.all_symbols.applicable_kinds = *
# Naming convention styles
cpp_naming_style.unreal_engine_default.capitalization = pascal_case
cpp_naming_style.unreal_engine_default.required_prefix =
cpp_naming_style.unreal_engine_default.required_suffix =
cpp_naming_style.unreal_engine_default.word_separator =
cpp_naming_style.unreal_engine_enums.capitalization = pascal_case
cpp_naming_style.unreal_engine_enums.required_prefix = E
cpp_naming_style.unreal_engine_enums.required_suffix =
cpp_naming_style.unreal_engine_enums.word_separator =
cpp_naming_style.unreal_engine_templates.capitalization = pascal_case
cpp_naming_style.unreal_engine_templates.required_prefix = T
cpp_naming_style.unreal_engine_templates.required_suffix =
cpp_naming_style.unreal_engine_templates.word_separator =
cpp_naming_style.unreal_engine_structs.capitalization = pascal_case
cpp_naming_style.unreal_engine_structs.required_prefix = F
cpp_naming_style.unreal_engine_structs.required_suffix =
cpp_naming_style.unreal_engine_structs.word_separator =
cpp_naming_style.uobject_style.capitalization = pascal_case
cpp_naming_style.uobject_style.required_prefix = U
cpp_naming_style.uobject_style.required_suffix =
cpp_naming_style.uobject_style.word_separator =
cpp_naming_style.aactor_style.capitalization = pascal_case
cpp_naming_style.aactor_style.required_prefix = A
cpp_naming_style.aactor_style.required_suffix =
cpp_naming_style.aactor_style.word_separator =
cpp_naming_style.swidget_style.capitalization = pascal_case
cpp_naming_style.swidget_style.required_prefix = S
cpp_naming_style.swidget_style.required_suffix =
cpp_naming_style.swidget_style.word_separator =
cpp_naming_style.boolean_style.capitalization = pascal_case
cpp_naming_style.boolean_style.required_prefix = b
cpp_naming_style.boolean_style.required_suffix =
cpp_naming_style.boolean_style.word_separator =

185
GlfwWindowManager.cpp Normal file
View File

@@ -0,0 +1,185 @@
#include "GlfwWindowManager.h"
#include <algorithm>
#include "Logger.h"
// bool WindowManager::bGlfwInitialized = false;
GlfwWindowManager::GlfwWindowManager() = default;
GlfwWindowManager::~GlfwWindowManager()
{
Cleanup();
}
GlfwWindowManager::GlfwWindowManager(GlfwWindowManager&& Other) noexcept
: Window(Other.Window), Title(std::move(Other.Title)), Width(Other.Width), Height(Other.Height)
{
Other.Window = nullptr;
}
GlfwWindowManager& GlfwWindowManager::operator=(GlfwWindowManager&& Other) noexcept
{
if (this != &Other)
{
Cleanup();
Window = Other.Window;
Title = std::move(Other.Title);
Width = Other.Width;
Height = Other.Height;
Other.Window = nullptr;
}
return *this;
}
void GlfwWindowManager::Initialize(const FWindowConfig& Config)
{
if (IsInitialized())
{
return;
}
InitializeGlfw();
Title = Config.Title;
Width = Config.Width;
Height = Config.Height;
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
glfwWindowHint(GLFW_RESIZABLE, Config.bResizable ? GLFW_TRUE : GLFW_FALSE);
Window = glfwCreateWindow(
Width,
Height,
Title.c_str(),
Config.bFullscreen ? glfwGetPrimaryMonitor() : nullptr,
nullptr);
if (!Window)
{
Log::Error("Failed to create GLFW window");
}
}
void GlfwWindowManager::Cleanup()
{
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());
}
}
VkSurfaceKHR GlfwWindowManager::CreateSurface(VkInstance Instance) const
{
if (!Window || !Instance)
{
return VK_NULL_HANDLE;
}
VkSurfaceKHR Surface = VK_NULL_HANDLE;
if (glfwCreateWindowSurface(Instance, Window, nullptr, &Surface) != VK_SUCCESS)
{
Log::Error("Failed to create window surface");
}
return Surface;
}
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");
}
}
}

61
GlfwWindowManager.h Normal file
View File

@@ -0,0 +1,61 @@
#pragma once
#include <string>
#define GLFW_INCLUDE_VULKAN
#include <GLFW/glfw3.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();
bool ShouldClose() const;
void PollEvents();
void WaitEvents() const;
void SetTitle(const std::string& Title);
GLFWwindow* GetHandle() const { return Window; }
uint32_t GetWidth() const { return Width; }
uint32_t GetHeight() const { return Height; }
const std::string& GetTitle() const { return Title; }
bool IsInitialized() const { return Window != nullptr; }
VkSurfaceKHR CreateSurface(VkInstance Instance) const;
void SetResizeCallback(GLFWwindowsizefun Callback);
void SetKeyCallback(GLFWkeyfun Callback);
void SetMouseButtonCallback(GLFWmousebuttonfun Callback);
void SetCursorPositionCallback(GLFWcursorposfun Callback);
void SetScrollCallback(GLFWscrollfun Callback);
private:
// static bool bGlfwInitialized;
void InitializeGlfw();
GLFWwindow* Window = nullptr;
std::string Title;
uint32_t Width = 0;
uint32_t Height = 0;
void DestroyWindow();
};

View File

@@ -1,261 +0,0 @@
#define GLFW_INCLUDE_VULKAN
#include <GLFW/glfw3.h>
#include <iostream>
#include <stdexcept>
#include <cstdlib>
#include <vector>
#include <algorithm>
#include <string>
#include <sstream>
#include "Logger.h"
const uint32_t WIDTH = 800;
const uint32_t HEIGHT = 600;
const std::vector<const char*> validationLayers = {
"VK_LAYER_KHRONOS_validation"
};
#ifdef NDEBUG
const bool enableValidationLayers = false;
#else
const bool enableValidationLayers = true;
#endif
class HelloTriangleApplication
{
private:
static VKAPI_ATTR VkBool32 VKAPI_CALL DebugCallback(
VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
VkDebugUtilsMessageTypeFlagsEXT messageType,
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
void* pUserData)
{
std::cerr << "validation layer: " << pCallbackData->pMessage << std::endl;
return VK_FALSE;
}
private:
GLFWwindow* window;
VkInstance instance;
std::vector<const char*> GetRequiredExtensions()
{
uint32_t glfwExtensionCount = 0;
const char** glfwExtensions;
glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);
std::vector<const char*> extensions(glfwExtensions, glfwExtensions + glfwExtensionCount);
if (enableValidationLayers)
{
extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
}
return extensions;
}
bool CheckValidationLayerSupport()
{
uint32_t layerCount;
vkEnumerateInstanceLayerProperties(&layerCount, nullptr);
std::vector<VkLayerProperties> availableLayers(layerCount);
vkEnumerateInstanceLayerProperties(&layerCount, availableLayers.data());
for (const char* layerName : validationLayers)
{
bool layerFound = false;
for (const auto& layerProperties : availableLayers)
{
if (strcmp(layerName, layerProperties.layerName) == 0)
{
layerFound = true;
break;
}
}
if (!layerFound)
{
return false;
}
}
return true;
}
// VkResult vkCreateInstance(
// const VkInstanceCreateInfo* pCreateInfo,
// const VkAllocationCallbacks* pAllocator,
// VkInstance* instance)
//{
// if (pCreateInfo == nullptr || instance == nullptr) {
// log("Null pointer passed to required parameter!");
// return VK_ERROR_INITIALIZATION_FAILED;
// }
// return vkCreateInstance(pCreateInfo, pAllocator, instance);
//}
public:
void Run()
{
InitWindow();
InitVulkan();
MainLoop();
Cleanup();
}
private:
void CheckExtensions(const char* requiredExtensions[], uint32_t requiredExtensionsCount)
{
uint32_t extensionCount = 0;
vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr);
std::vector<VkExtensionProperties> extensions(extensionCount);
vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, extensions.data());
std::string required;
std::string available;
required += "Required extensions:\n";
bool found = false;
for (uint32_t i = 0; i < requiredExtensionsCount; i++)
{
std::string requiredExtension = requiredExtensions[i];
for (const auto& extension : extensions)
{
found = strcmp(extension.extensionName, requiredExtensions[i]);
if (found)
{
break;
}
}
std::string status = found ? "FOUND" : "NOT FOUND";
required += "\t" + requiredExtension + " : " + status + "\n";
}
available += "available extensions:\n";
for (const auto& extension : extensions)
{
std::string extensionName = extension.extensionName;
available += "\t" + extensionName + "\n";
}
log(INFO, required);
log(INFO, available);
}
void CreateInstance()
{
log(INFO, "Creating Vulkan instance");
if (enableValidationLayers && !CheckValidationLayerSupport())
{
throw std::runtime_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;
uint32_t glfwExtensionCount = 0;
const char** glfwExtensions;
glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);
createInfo.enabledExtensionCount = glfwExtensionCount;
createInfo.ppEnabledExtensionNames = glfwExtensions;
if (enableValidationLayers)
{
createInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size());
createInfo.ppEnabledLayerNames = validationLayers.data();
}
else
{
createInfo.enabledLayerCount = 0;
}
if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS)
{
throw std::runtime_error("failed to create instance!");
}
CheckExtensions(glfwExtensions, glfwExtensionCount);
auto extensions = GetRequiredExtensions();
createInfo.enabledExtensionCount = static_cast<uint32_t>(extensions.size());
createInfo.ppEnabledExtensionNames = extensions.data();
}
void InitWindow()
{
log(INFO, "Initializing GLFW window...");
glfwInit();
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
window = glfwCreateWindow(WIDTH, HEIGHT, "Vulkan", nullptr, nullptr);
}
void InitVulkan()
{
log(INFO, "Initializing Vulkan...");
CreateInstance();
}
void MainLoop()
{
while (!glfwWindowShouldClose(window))
{
glfwPollEvents();
}
}
void Cleanup()
{
vkDestroyInstance(instance, nullptr);
glfwDestroyWindow(window);
glfwTerminate();
}
};
int main()
{
HelloTriangleApplication app;
try
{
app.Run();
}
catch (const std::exception& e)
{
std::cerr << e.what() << std::endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}

View File

@@ -103,7 +103,7 @@
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode> <ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>C:\Users\jorda\Development\Libraries\OpenGL\glfw-3.4.bin.WIN64\glfw-3.4.bin.WIN64\include;C:\Users\jorda\Development\Libraries\Vulkan\1.4.335.0\Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>C:\Users\jorda\Development\Libraries\OpenGL\glfw-3.4.bin.WIN64\glfw-3.4.bin.WIN64\include;C:\Users\jorda\Development\Libraries\Vulkan\1.4.335.0\Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<LanguageStandard>stdcpp17</LanguageStandard> <LanguageStandard>stdcpp20</LanguageStandard>
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
@@ -121,7 +121,7 @@
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode> <ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>C:\Users\jorda\Development\Libraries\OpenGL\glfw-3.4.bin.WIN64\glfw-3.4.bin.WIN64\include;C:\Users\jorda\Development\Libraries\Vulkan\1.4.335.0\Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>C:\Users\jorda\Development\Libraries\OpenGL\glfw-3.4.bin.WIN64\glfw-3.4.bin.WIN64\include;C:\Users\jorda\Development\Libraries\Vulkan\1.4.335.0\Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<LanguageStandard>stdcpp17</LanguageStandard> <LanguageStandard>stdcpp20</LanguageStandard>
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
@@ -131,10 +131,19 @@
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="Learning Vulkan.cpp" /> <ClCompile Include="VulkanDebugManager.cpp" />
<ClCompile Include="main.cpp" />
<ClCompile Include="Logger.cpp" />
<ClCompile Include="VulkanDeviceManager.cpp" />
<ClCompile Include="VulkanInstanceManager.cpp" />
<ClCompile Include="GlfwWindowManager.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="VulkanDebugManager.h" />
<ClInclude Include="Logger.h" /> <ClInclude Include="Logger.h" />
<ClInclude Include="VulkanDeviceManager.h" />
<ClInclude Include="VulkanInstanceManager.h" />
<ClInclude Include="GlfwWindowManager.h" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include=".clang-format" /> <None Include=".clang-format" />

View File

@@ -15,7 +15,22 @@
</Filter> </Filter>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="Learning Vulkan.cpp"> <ClCompile Include="main.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="GlfwWindowManager.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="VulkanInstanceManager.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Logger.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="VulkanDebugManager.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="VulkanDeviceManager.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
</ItemGroup> </ItemGroup>
@@ -23,6 +38,18 @@
<ClInclude Include="Logger.h"> <ClInclude Include="Logger.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="GlfwWindowManager.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="VulkanInstanceManager.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="VulkanDebugManager.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="VulkanDeviceManager.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include=".clang-format" /> <None Include=".clang-format" />

View File

@@ -0,0 +1,64 @@
#include "Logger.h"
#include <iostream>
void Log::Message(Level Level, const std::string& Message, const std::source_location& Location)
{
std::string FullFunc = Location.function_name();
std::string DisplayName = FullFunc; // Default to full function name
// Simple cleanup: try to extract just class::method
size_t LastColon = FullFunc.rfind("::");
if (LastColon != std::string::npos)
{
// Find the class name start
size_t ClassStart = FullFunc.rfind(' ', LastColon);
if (ClassStart != std::string::npos)
{
std::string ClassName = FullFunc.substr(ClassStart + 1, LastColon - ClassStart - 1);
// Find method name end (first parenthesis after last ::)
size_t MethodEnd = FullFunc.find('(', LastColon);
if (MethodEnd != std::string::npos)
{
std::string MethodName = FullFunc.substr(LastColon + 2, MethodEnd - LastColon - 2);
DisplayName = ClassName + "::" + MethodName + "()";
}
}
}
std::string LevelString;
switch (Level)
{
case Level::Info:
LevelString = "INFO";
break;
case Level::Warning:
LevelString = "WARNING";
break;
case Level::Error:
LevelString = "ERROR";
break;
case Level::Debug:
LevelString = "DEBUG";
break;
case Level::VkValidation:
LevelString = "VALIDATION LAYER";
break;
case Level::DeviceSetup:
LevelString = "DEVICE SETUP";
break;
default:
LevelString = "UNKNOWN";
break;
}
std::string LogMessage = std::format("[{}] [{}] {}",
LevelString, DisplayName, Message);
std::cout << LogMessage << std::endl;
if (Level == Level::Error)
{
throw std::runtime_error(LogMessage);
}
}

View File

@@ -1,29 +1,59 @@
#pragma once #pragma once
#include <iostream> #include <string>
#include <source_location>
#include <format>
#include <stdexcept>
enum LogLevel { namespace Log
INFO, {
WARNING,
ERROR
};
void log(LogLevel level, const std::string& message) { enum class Level
std::string levelStr; {
Info,
Warning,
Error,
Debug,
VkValidation,
DeviceSetup
};
switch(level) { // void Message(Level Level, const std::source_location& Location = std::source_location::current(), const std::string& Message);
case INFO: void Message(Level Level, const std::string& Message, const std::source_location& Location);
levelStr = "[INFO]";
break; template <typename... Args>
case WARNING: void Info(const std::string& Format, Args&&... Arguments, const std::source_location& Location = std::source_location::current())
levelStr = "[WARNING]"; {
break; Message(Level::Info, std::vformat(Format, std::make_format_args(Arguments...)), Location);
case ERROR:
levelStr = "[ERROR]";
break;
default:
levelStr = "[UNKNOWN]";
break;
} }
std::cout << levelStr << " : " << message << std::endl;
} template <typename... Args>
void Warning(const std::string& Format, Args&&... Arguments, const std::source_location& Location = std::source_location::current())
{
Message(Level::Warning, std::vformat(Format, std::make_format_args(Arguments...)), Location);
}
template <typename... Args>
void Error(const std::string& Format, Args&&... Arguments, const std::source_location& Location = std::source_location::current())
{
Message(Level::Error, std::vformat(Format, std::make_format_args(Arguments...)), Location);
}
template <typename... Args>
void Debug(const std::string& Format, Args&&... Arguments, const std::source_location& Location = std::source_location::current())
{
Message(Level::Warning, std::vformat(Format, std::make_format_args(Arguments...)), Location);
}
template <typename... Args>
void Validation(const std::string& Format, Args&&... Arguments, const std::source_location& Location = std::source_location::current())
{
Message(Level::VkValidation, std::vformat(Format, std::make_format_args(Arguments...)), Location);
}
template <typename... Args>
void DeviceSetup(const std::string& Format, Args&&... Arguments, const std::source_location& Location = std::source_location::current())
{
Message(Level::DeviceSetup, std::vformat(Format, std::make_format_args(Arguments...)), Location);
}
} // namespace Log

77
VkDebug.h Normal file
View File

@@ -0,0 +1,77 @@
#pragma once
#define GLFW_INCLUDE_VULKAN
#include <GLFW/glfw3.h>
#include <iostream>
#include <vector>
#ifdef NDEBUG
const bool enableValidationLayers = false;
#else
const bool enableValidationLayers = true;
#endif
VkDebugUtilsMessengerEXT debugMessenger;
VkResult CreateDebugUtilsMessengerEXT(
VkInstance instance,
const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkDebugUtilsMessengerEXT* pDebugMessenger)
{
auto func = (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(instance, "vkCreateDebugUtilsMessengerEXT");
if (func != nullptr)
{
return func(instance, pCreateInfo, pAllocator, pDebugMessenger);
}
else
{
return VK_ERROR_EXTENSION_NOT_PRESENT;
}
}
static VKAPI_ATTR VkBool32 VKAPI_CALL DebugCallback(
VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
VkDebugUtilsMessageTypeFlagsEXT messageType,
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
void* pUserData)
{
std::cerr << "validation layer: " << pCallbackData->pMessage << std::endl;
if (messageSeverity >= VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT)
{
}
return VK_FALSE;
}
bool CheckValidationLayerSupport()
{
uint32_t layerCount;
vkEnumerateInstanceLayerProperties(&layerCount, nullptr);
std::vector<VkLayerProperties> availableLayers(layerCount);
vkEnumerateInstanceLayerProperties(&layerCount, availableLayers.data());
for (const char* layerName : validationLayers)
{
bool layerFound = false;
for (const auto& layerProperties : availableLayers)
{
if (strcmp(layerName, layerProperties.layerName) == 0)
{
layerFound = true;
break;
}
}
if (!layerFound)
{
return false;
}
}
return true;
}

65
VkSetup.h Normal file
View File

@@ -0,0 +1,65 @@
#pragma once
#define GLFW_INCLUDE_VULKAN
#include <GLFW/glfw3.h>
#include <vector>
#ifdef NDEBUG
const bool enableValidationLayers = false;
#else
const bool enableValidationLayers = true;
#endif
class VkSetup
{
GLFWwindow* window;
VkInstance instance;
std::vector<const char*> GetRequiredExtensions()
{
uint32_t glfwExtensionCount = 0;
const char** glfwExtensions;
glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);
std::vector<const char*> extensions(glfwExtensions, glfwExtensions + glfwExtensionCount);
if (enableValidationLayers)
{
extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
}
return extensions;
}
bool CheckValidationLayerSupport()
{
uint32_t layerCount;
vkEnumerateInstanceLayerProperties(&layerCount, nullptr);
std::vector<VkLayerProperties> availableLayers(layerCount);
vkEnumerateInstanceLayerProperties(&layerCount, availableLayers.data());
for (const char* layerName : validationLayers)
{
bool layerFound = false;
for (const auto& layerProperties : availableLayers)
{
if (strcmp(layerName, layerProperties.layerName) == 0)
{
layerFound = true;
break;
}
}
if (!layerFound)
{
return false;
}
}
return true;
}
};

View File

@@ -4,3 +4,10 @@
- Vulkan objects are allocated with `vkAllocateXXX` - Vulkan objects are allocated with `vkAllocateXXX`
- `vkDestroyXXX` and `vkFreeXXX` to destroy objects - `vkDestroyXXX` and `vkFreeXXX` to destroy objects
- -
# Validation Layers
There are a lot more settings for the behavior of validation layers than just the flags specified in the `VkDebugUtilsMessengerCreateInfoEXT` struct. Browse to the Vulkan SDK and go to the `Config` directory. There you will find a `vk_layer_settings.txt` file that explains how to configure the layers.
To configure the layer settings for your own application, copy the file to the `Debug` and `Release` directories of your project and follow the instructions to set the desired behavior. However, for the remainder of this tutorial I'll assume that you're using the default settings.
Throughout this tutorial I'll be making a couple of intentional mistakes to show you how helpful the validation layers are with catching them and to teach you how important it is to know exactly what you're doing with Vulkan. Now it's time to look at [Vulkan devices in the system](https://vulkan-tutorial.com/en/Drawing_a_triangle/Setup/Physical_devices_and_queue_families).

119
VulkanDebugManager.cpp Normal file
View File

@@ -0,0 +1,119 @@
#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
VulkanDebugManager.h Normal file
View 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();
};

111
VulkanDeviceManager.cpp Normal file
View File

@@ -0,0 +1,111 @@
#include "VulkanDeviceManager.h"
#include <vector>
#include "Logger.h"
#include <map>
VulkanDeviceManager::VulkanDeviceManager()
{
}
VulkanDeviceManager::~VulkanDeviceManager()
{
Cleanup();
}
VulkanDeviceManager::VulkanDeviceManager(VulkanDeviceManager&& Other) noexcept
{
}
VulkanDeviceManager& VulkanDeviceManager::operator=(VulkanDeviceManager&& Other) noexcept
{
if (this != &Other)
{
Cleanup();
}
return *this;
}
void VulkanDeviceManager::Initialize(VkInstance Instance)
{
if (IsInitialized())
{
return;
}
}
void VulkanDeviceManager::Cleanup()
{
if (!IsInitialized())
{
return;
}
}
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)
{
int Score = RateDeviceSuitability(Device);
Candidates.insert(std::make_pair(Score, Device));
}
if (Candidates.rbegin()->first > 0)
{
PhysicalDevice = Candidates.rbegin()->second;
}
else
{
Log::Error("Failed to find a suitable GPU");
}
}
// bool VulkanDeviceManager::IsDeviceSuitable(VkPhysicalDevice Device)
//{
// VkPhysicalDeviceProperties DeviceProperties;
// vkGetPhysicalDeviceProperties(Device, &DeviceProperties);
//
// VkPhysicalDeviceFeatures DeviceFeatures;
// vkGetPhysicalDeviceFeatures(Device, &DeviceFeatures);
//
// return DeviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU && DeviceFeatures.geometryShader;
// }
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;
}

47
VulkanDeviceManager.h Normal file
View File

@@ -0,0 +1,47 @@
#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 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);
void Cleanup();
bool IsInitialized() const { return PhysicalDevice != VK_NULL_HANDLE; }
private:
VkPhysicalDevice PhysicalDevice = VK_NULL_HANDLE;
VkInstance Instance = VK_NULL_HANDLE;
void PickPhysicalDevice();
// bool IsDeviceSuitable(VkPhysicalDevice Device);
int RateDeviceSuitability(VkPhysicalDevice Device);
};

177
VulkanInstanceManager.cpp Normal file
View File

@@ -0,0 +1,177 @@
#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();
if (VkDebugManager)
{
VkDebugManager->Initialize(Instance);
}
VkDeviceManager = std::make_unique<VulkanDeviceManager>();
VkDeviceManager->Initialize(Instance);
}
void VulkanInstanceManager::Cleanup()
{
if (!IsInitialized())
{
Log::Warning("Not initialized.");
return;
}
if (VkDebugManager)
{
VkDebugManager->Cleanup();
}
if (VkDeviceManager)
{
VkDeviceManager->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!");
}
}

53
VulkanInstanceManager.h Normal file
View File

@@ -0,0 +1,53 @@
#pragma once
#include <vector>
#include <memory>
#define GLFW_INCLUDE_VULKAN
#include <GLFW/glfw3.h>
#include "VulkanDebugManager.h"
#include "VulkanDeviceManager.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 Cleanup();
bool IsInitialized() const { return Instance != VK_NULL_HANDLE; }
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();
};

75
main.cpp Normal file
View File

@@ -0,0 +1,75 @@
#include "Logger.h"
#include "VulkanInstanceManager.h"
#include "GlfwWindowManager.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;
};
class HelloTriangleApplication
{
public:
void Run()
{
InitGlfw();
InitVulkan();
MainLoop();
Cleanup();
}
private:
VulkanInstanceManager VkInstanceManager;
GlfwWindowManager GlfwWindowManager;
AppConfig Settings = {};
void InitVulkan()
{
FVulkanConfig Config = { Settings.bValidationEnabled, Settings.bVerboseLogging };
VkInstanceManager.Initialize(Config);
}
void InitGlfw()
{
FWindowConfig Config = { Settings.Title, Settings.Width, Settings.Height, Settings.bResizable, Settings.bFullscreen };
GlfwWindowManager.Initialize(Config);
}
void MainLoop()
{
while (!GlfwWindowManager.ShouldClose())
{
GlfwWindowManager.PollEvents();
}
}
void Cleanup()
{
// VkInstanceManager.Cleanup();
// GlfwWindowManager.Cleanup();
}
};
int main()
{
HelloTriangleApplication app;
try
{
app.Run();
}
catch (const std::exception& e)
{
Log::Error(e.what());
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}