Initial Gitea Commit
This commit is contained in:
@@ -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
179
.editorconfig
Normal 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
185
GlfwWindowManager.cpp
Normal 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
61
GlfwWindowManager.h
Normal 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();
|
||||||
|
};
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -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" />
|
||||||
|
|||||||
@@ -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" />
|
||||||
|
|||||||
64
Logger.cpp
64
Logger.cpp
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
72
Logger.h
72
Logger.h
@@ -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
|
enum class Level
|
||||||
|
{
|
||||||
|
Info,
|
||||||
|
Warning,
|
||||||
|
Error,
|
||||||
|
Debug,
|
||||||
|
VkValidation,
|
||||||
|
DeviceSetup
|
||||||
};
|
};
|
||||||
|
|
||||||
void log(LogLevel level, const std::string& message) {
|
// void Message(Level Level, const std::source_location& Location = std::source_location::current(), const std::string& Message);
|
||||||
std::string levelStr;
|
void Message(Level Level, const std::string& Message, const std::source_location& Location);
|
||||||
|
|
||||||
switch(level) {
|
template <typename... Args>
|
||||||
case INFO:
|
void Info(const std::string& Format, Args&&... Arguments, const std::source_location& Location = std::source_location::current())
|
||||||
levelStr = "[INFO]";
|
{
|
||||||
break;
|
Message(Level::Info, std::vformat(Format, std::make_format_args(Arguments...)), Location);
|
||||||
case WARNING:
|
|
||||||
levelStr = "[WARNING]";
|
|
||||||
break;
|
|
||||||
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
77
VkDebug.h
Normal 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
65
VkSetup.h
Normal 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;
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -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
119
VulkanDebugManager.cpp
Normal 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
58
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();
|
||||||
|
};
|
||||||
111
VulkanDeviceManager.cpp
Normal file
111
VulkanDeviceManager.cpp
Normal 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
47
VulkanDeviceManager.h
Normal 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
177
VulkanInstanceManager.cpp
Normal 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
53
VulkanInstanceManager.h
Normal 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
75
main.cpp
Normal 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;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user