From 9381b967e7909fa9860142cf81d7cd904e1f7735 Mon Sep 17 00:00:00 2001 From: Anish Bhobe Date: Wed, 26 Jun 2024 17:41:59 +0200 Subject: [PATCH] Refactored for new coding scheme. No exceptions. --- .clang-format | 214 +++------------------------ .clang-tidy | 76 +++++----- CMakeLists.txt | 2 +- aster/CMakeLists.txt | 5 +- aster/config.h | 5 + aster/constants.h | 125 +++++++++------- aster/context.cpp | 167 +++++++++++---------- aster/context.h | 76 +--------- aster/device.cpp | 129 ++++++++-------- aster/device.h | 27 ++-- aster/glfw_context.h | 50 ++++--- aster/global.cpp | 13 ++ aster/global.h | 142 ++++++++++++------ aster/logger.cpp | 19 ++- aster/logger.h | 301 +++++++++++++++++++++----------------- aster/physical_device.cpp | 200 +++++++++++++++---------- aster/physical_device.h | 45 +++--- aster/window.cpp | 117 ++++++++------- aster/window.h | 56 +++---- triangle/aster.cpp | 99 ++++++++----- vcpkg.json | 3 +- 21 files changed, 933 insertions(+), 938 deletions(-) diff --git a/.clang-format b/.clang-format index 1df6c35..a174591 100644 --- a/.clang-format +++ b/.clang-format @@ -3,197 +3,25 @@ # chosen value in case the base style changes (last sync: Clang 14.0). --- ### General config, applies to all languages ### -BasedOnStyle: LLVM -AccessModifierOffset: -4 -AlignAfterOpenBracket: DontAlign -# AlignArrayOfStructures: None -# AlignConsecutiveMacros: None -# AlignConsecutiveAssignments: None -# AlignConsecutiveBitFields: None -# AlignConsecutiveDeclarations: None -# AlignEscapedNewlines: Right -AlignOperands: DontAlign -AlignTrailingComments: false -# AllowAllArgumentsOnNextLine: true -AllowAllParametersOfDeclarationOnNextLine: false -# AllowShortEnumsOnASingleLine: true -# AllowShortBlocksOnASingleLine: Never -# AllowShortCaseLabelsOnASingleLine: false -# AllowShortFunctionsOnASingleLine: All -# AllowShortLambdasOnASingleLine: All -# AllowShortIfStatementsOnASingleLine: Never -# AllowShortLoopsOnASingleLine: false -# AlwaysBreakAfterDefinitionReturnType: None -# AlwaysBreakAfterReturnType: None -# AlwaysBreakBeforeMultilineStrings: false -# AlwaysBreakTemplateDeclarations: MultiLine -# AttributeMacros: -# - __capability -# BinPackArguments: true -# BinPackParameters: true -# BraceWrapping: -# AfterCaseLabel: false -# AfterClass: false -# AfterControlStatement: Never -# AfterEnum: false -# AfterFunction: false -# AfterNamespace: false -# AfterObjCDeclaration: false -# AfterStruct: false -# AfterUnion: false -# AfterExternBlock: false -# BeforeCatch: false -# BeforeElse: false -# BeforeLambdaBody: false -# BeforeWhile: false -# IndentBraces: false -# SplitEmptyFunction: true -# SplitEmptyRecord: true -# SplitEmptyNamespace: true -# BreakBeforeBinaryOperators: None -# BreakBeforeConceptDeclarations: true -# BreakBeforeBraces: Attach -# BreakBeforeInheritanceComma: false -# BreakInheritanceList: BeforeColon -# BreakBeforeTernaryOperators: true -# BreakConstructorInitializersBeforeComma: false -BreakConstructorInitializers: AfterColon -# BreakStringLiterals: true -ColumnLimit: 0 -# CommentPragmas: '^ IWYU pragma:' -# QualifierAlignment: Leave -# CompactNamespaces: false -ConstructorInitializerIndentWidth: 8 -ContinuationIndentWidth: 8 -Cpp11BracedListStyle: false -# DeriveLineEnding: true -# DerivePointerAlignment: false -# DisableFormat: false -# EmptyLineAfterAccessModifier: Never -# EmptyLineBeforeAccessModifier: LogicalBlock -# ExperimentalAutoDetectBinPacking: false -# PackConstructorInitializers: BinPack -ConstructorInitializerAllOnOneLineOrOnePerLine: true -# AllowAllConstructorInitializersOnNextLine: true -# FixNamespaceComments: true -# ForEachMacros: -# - foreach -# - Q_FOREACH -# - BOOST_FOREACH -# IfMacros: -# - KJ_IF_MAYBE -# IncludeBlocks: Preserve +BasedOnStyle: Microsoft +#AccessModifierOffset: -2 +AlwaysBreakAfterReturnType: AllDefinitions +BreakConstructorInitializers: BeforeComma +#ColumnLimit: 0 +#ConstructorInitializerIndentWidth: 4 +#ConstructorInitializerAllOnOneLineOrOnePerLine: true +AlwaysBreakTemplateDeclarations: Yes IncludeCategories: - - Regex: '".*"' - Priority: 1 - - Regex: '^<.*\.h>' - Priority: 2 - - Regex: '^<.*' - Priority: 3 -# IncludeIsMainRegex: '(Test)?$' -# IncludeIsMainSourceRegex: '' -# IndentAccessModifiers: false -IndentCaseLabels: true -# IndentCaseBlocks: false -# IndentGotoLabels: true -# IndentPPDirectives: None -# IndentExternBlock: AfterExternBlock -# IndentRequires: false -IndentWidth: 4 -# IndentWrappedFunctionNames: false -# InsertTrailingCommas: None -# JavaScriptQuotes: Leave -# JavaScriptWrapImports: true -KeepEmptyLinesAtTheStartOfBlocks: false -# LambdaBodyIndentation: Signature -# MacroBlockBegin: '' -# MacroBlockEnd: '' -# MaxEmptyLinesToKeep: 1 -# NamespaceIndentation: None -# PenaltyBreakAssignment: 2 -# PenaltyBreakBeforeFirstCallParameter: 19 -# PenaltyBreakComment: 300 -# PenaltyBreakFirstLessLess: 120 -# PenaltyBreakOpenParenthesis: 0 -# PenaltyBreakString: 1000 -# PenaltyBreakTemplateDeclaration: 10 -# PenaltyExcessCharacter: 1000000 -# PenaltyReturnTypeOnItsOwnLine: 60 -# PenaltyIndentedWhitespace: 0 -# PointerAlignment: Right -# PPIndentWidth: -1 -# ReferenceAlignment: Pointer -# ReflowComments: true -# RemoveBracesLLVM: false -# SeparateDefinitionBlocks: Leave -# ShortNamespaceLines: 1 -# SortIncludes: CaseSensitive -# SortJavaStaticImport: Before -# SortUsingDeclarations: true -# SpaceAfterCStyleCast: false -# SpaceAfterLogicalNot: false -# SpaceAfterTemplateKeyword: true -# SpaceBeforeAssignmentOperators: true -# SpaceBeforeCaseColon: false -# SpaceBeforeCpp11BracedList: false -# SpaceBeforeCtorInitializerColon: true -# SpaceBeforeInheritanceColon: true -# SpaceBeforeParens: ControlStatements -# SpaceBeforeParensOptions: -# AfterControlStatements: true -# AfterForeachMacros: true -# AfterFunctionDefinitionName: false -# AfterFunctionDeclarationName: false -# AfterIfMacros: true -# AfterOverloadedOperator: false -# BeforeNonEmptyParentheses: false -# SpaceAroundPointerQualifiers: Default -# SpaceBeforeRangeBasedForLoopColon: true -# SpaceInEmptyBlock: false -# SpaceInEmptyParentheses: false -# SpacesBeforeTrailingComments: 1 -# SpacesInAngles: Never -# SpacesInConditionalStatement: false -# SpacesInContainerLiterals: true -# SpacesInCStyleCastParentheses: false -## Godot TODO: We'll want to use a min of 1, but we need to see how to fix -## our comment capitalization at the same time. -SpacesInLineCommentPrefix: - Minimum: 0 - Maximum: -1 -# SpacesInParentheses: false -# SpacesInSquareBrackets: false -# SpaceBeforeSquareBrackets: false -# BitFieldColonSpacing: Both -# StatementAttributeLikeMacros: -# - Q_EMIT -# StatementMacros: -# - Q_UNUSED -# - QT_REQUIRE_VERSION -TabWidth: 4 -# UseCRLF: false -UseTab: Always -# WhitespaceSensitiveMacros: -# - STRINGIZE -# - PP_STRINGIZE -# - BOOST_PP_STRINGIZE -# - NS_SWIFT_NAME -# - CF_SWIFT_NAME ---- -### C++ specific config ### -Language: Cpp -Standard: c++17 ---- -### ObjC specific config ### -Language: ObjC -# ObjCBinPackProtocolList: Auto -ObjCBlockIndentWidth: 4 -# ObjCBreakBeforeNestedBlockParam: true -# ObjCSpaceAfterProperty: false -# ObjCSpaceBeforeProtocolList: true ---- -### Java specific config ### -Language: Java -# BreakAfterJavaFieldAnnotations: false -JavaImportGroups: ['org.godotengine', 'android', 'androidx', 'com.android', 'com.google', 'java', 'javax'] -... + - Regex: '".*"' + Priority: 1 + - Regex: '^<.*\.h>' + Priority: 2 + - Regex: '^<.*' + Priority: 3 +#IndentCaseLabels: true +IndentWidth: 4 +#KeepEmptyLinesAtTheStartOfBlocks: false +PenaltyReturnTypeOnItsOwnLine: 0 +TabWidth: 4 +Language: Cpp +Standard: c++20 \ No newline at end of file diff --git a/.clang-tidy b/.clang-tidy index d68e5f7..7fac31d 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -4,42 +4,42 @@ WarningsAsErrors: '' HeaderFilterRegex: '' FormatStyle: none CheckOptions: - - key: cert-dcl16-c.NewSuffixes - value: 'L;LL;LU;LLU' - - key: cert-oop54-cpp.WarnOnlyIfThisHasSuspiciousField - value: '0' - - key: cppcoreguidelines-explicit-virtual-functions.IgnoreDestructors - value: '1' - - key: cppcoreguidelines-non-private-member-variables-in-classes.IgnoreClassesWithAllMemberVariablesBeingPublic - value: '1' - - key: cppcoreguidelines-pro-type-member-init.IgnoreArrays - value: '1' - - key: cppcoreguidelines-pro-type-member-init.UseAssignment - value: '1' - - key: google-readability-function-size.StatementThreshold - value: '800' - - key: google-readability-namespace-comments.ShortNamespaceLines - value: '10' - - key: google-readability-namespace-comments.SpacesBeforeComments - value: '2' - - key: modernize-loop-convert.MaxCopySize - value: '16' - - key: modernize-loop-convert.MinConfidence - value: reasonable - - key: modernize-loop-convert.NamingStyle - value: CamelCase - - key: modernize-pass-by-value.IncludeStyle - value: llvm - - key: modernize-replace-auto-ptr.IncludeStyle - value: llvm - - key: modernize-use-bool-literals.IgnoreMacros - value: '0' - - key: modernize-use-default-member-init.IgnoreMacros - value: '0' - - key: modernize-use-default-member-init.UseAssignment - value: '1' - - key: modernize-use-nullptr.NullMacros - value: 'NULL' - - key: readability-braces-around-statements.ShortStatementLines - value: '0' + - key: cert-dcl16-c.NewSuffixes + value: 'L;LL;LU;LLU' + - key: cert-oop54-cpp.WarnOnlyIfThisHasSuspiciousField + value: '0' + - key: cppcoreguidelines-explicit-virtual-functions.IgnoreDestructors + value: '1' + - key: cppcoreguidelines-non-private-member-variables-in-classes.IgnoreClassesWithAllMemberVariablesBeingPublic + value: '1' + - key: cppcoreguidelines-pro-type-member-init.IgnoreArrays + value: '1' + - key: cppcoreguidelines-pro-type-member-init.UseAssignment + value: '1' + - key: google-readability-function-size.StatementThreshold + value: '800' + - key: google-readability-namespace-comments.ShortNamespaceLines + value: '10' + - key: google-readability-namespace-comments.SpacesBeforeComments + value: '2' + - key: modernize-loop-convert.MaxCopySize + value: '16' + - key: modernize-loop-convert.MinConfidence + value: reasonable + - key: modernize-loop-convert.NamingStyle + value: CamelCase + - key: modernize-pass-by-value.IncludeStyle + value: microsoft + - key: modernize-replace-auto-ptr.IncludeStyle + value: microsoft + - key: modernize-use-bool-literals.IgnoreMacros + value: '0' + - key: modernize-use-default-member-init.IgnoreMacros + value: '0' + - key: modernize-use-default-member-init.UseAssignment + value: '1' + - key: modernize-use-nullptr.NullMacros + value: 'NULL' + - key: readability-braces-around-statements.ShortStatementLines + value: '0' ... \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 1bb18ea..f3354bf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,7 +8,7 @@ set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) -set(CMAKE_CXX_FLAGS -Wall) +set(CMAKE_CXX_FLAGS "-Wall -fno-rtti -fno-exceptions") add_subdirectory("aster") add_subdirectory("triangle") diff --git a/aster/CMakeLists.txt b/aster/CMakeLists.txt index 361cc18..db069e5 100644 --- a/aster/CMakeLists.txt +++ b/aster/CMakeLists.txt @@ -6,9 +6,9 @@ find_package(glm CONFIG REQUIRED) find_package(glfw3 CONFIG REQUIRED) find_path(SCOTTT_DEBUGBREAK_INCLUDE_DIRS "debugbreak.h") find_package(Vulkan REQUIRED) -# find_package( VulkanHeaders CONFIG REQUIRED ) find_package(fmt CONFIG REQUIRED) find_package(VulkanMemoryAllocator CONFIG REQUIRED) +find_package(EASTL CONFIG REQUIRED) set(HEADER_FILES constants.h @@ -37,5 +37,6 @@ target_link_libraries(aster_core PUBLIC glm::glm-header-only) target_link_libraries(aster_core PRIVATE glfw) target_include_directories(aster_core PRIVATE ${SCOTTT_DEBUGBREAK_INCLUDE_DIRS}) target_link_libraries(aster_core PRIVATE fmt::fmt) -target_link_libraries(aster_core PRIVATE Vulkan::Vulkan Vulkan::Headers GPUOpen::VulkanMemoryAllocator) +target_link_libraries(aster_core PRIVATE EASTL) +target_link_libraries(aster_core PUBLIC Vulkan::Headers GPUOpen::VulkanMemoryAllocator) diff --git a/aster/config.h b/aster/config.h index f4493ad..b03eba9 100644 --- a/aster/config.h +++ b/aster/config.h @@ -11,10 +11,15 @@ #define GLFW_INCLUDE_VULKAN #define VULKAN_HPP_DISPATCH_LOADER_DYNAMIC 1 #define VULKAN_HPP_NO_STRUCT_CONSTRUCTORS +#define VULKAN_HPP_DISABLE_ENHANCED_MODE 1 #define VMA_STATIC_VULKAN_FUNCTIONS 0 #define VMA_DYNAMIC_VULKAN_FUNCTIONS 1 +#define EASTL_NO_EXCEPTIONS 1 +// ReSharper disable once CppInconsistentNaming +#define _HAS_EXCEPTIONS 0 + #if defined(NDEBUG) #define USE_OPTICK (0) #else diff --git a/aster/constants.h b/aster/constants.h index ce4c10e..d666735 100644 --- a/aster/constants.h +++ b/aster/constants.h @@ -5,10 +5,10 @@ #pragma once +#include + #include #include -#include -#include #include @@ -28,54 +28,70 @@ using b8 = bool; using b32 = u32; using usize = size_t; using p64 = intptr_t; +using cstr = const char *; -constexpr usize strlen_c(const char *s) { - usize len = 0; - char c = '\0'; - do { - c = s[len]; - len++; - } while (c != '\0'); - return len; +constexpr usize +strlenC(const char *s) +{ + usize len = 0; + char c = '\0'; + do + { + c = s[len]; + len++; + } while (c != '\0'); + return len; } -constexpr auto ANSI_Black = "\u001b[30m"; -constexpr auto ANSI_Red = "\u001b[31m"; -constexpr auto ANSI_Green = "\u001b[32m"; -constexpr auto ANSI_Yellow = "\u001b[33m"; -constexpr auto ANSI_Blue = "\u001b[34m"; -constexpr auto ANSI_Magenta = "\u001b[35m"; -constexpr auto ANSI_Cyan = "\u001b[36m"; -constexpr auto ANSI_White = "\u001b[37m"; -constexpr auto ANSI_Reset = "\u001b[0m"; +namespace ansi_color +{ +constexpr auto Black = "\u001b[30m"; +constexpr auto Red = "\u001b[31m"; +constexpr auto Green = "\u001b[32m"; +constexpr auto Yellow = "\u001b[33m"; +constexpr auto Blue = "\u001b[34m"; +constexpr auto Magenta = "\u001b[35m"; +constexpr auto Cyan = "\u001b[36m"; +constexpr auto White = "\u001b[37m"; +constexpr auto Reset = "\u001b[0m"; +} // namespace ansi_color -template -using Option = std::optional; - -template -constexpr auto cast(from_t &&_in) { - return static_cast(std::forward(_in)); +template +constexpr auto +cast(FromT &&in) +{ + return static_cast(std::forward(in)); } -template -constexpr auto recast(from_t &&_in) { - return reinterpret_cast(std::forward(_in)); +template +constexpr auto +recast(FromT &&in) +{ + return reinterpret_cast(std::forward(in)); } -constexpr f32 operator""_deg(long double degrees) { - return glm::radians(cast(degrees)); +constexpr f32 +operator""_deg(long double degrees) +{ + return glm::radians(cast(degrees)); } -constexpr f32 operator""_deg(unsigned long long int degrees) { - return glm::radians(cast(degrees)); +constexpr f32 +operator""_deg(unsigned long long int degrees) +{ + return glm::radians(cast(degrees)); } -constexpr f32 operator""_rad(long double rads) { - return cast(rads); +constexpr f32 +operator""_rad(long double rads) +{ + return cast(rads); } -constexpr f32 operator""_rad(unsigned long long int rads) { - return cast(rads); +constexpr f32 +operator""_rad(unsigned long long int rads) +{ + return cast(rads); } using glm::ivec2; @@ -91,38 +107,45 @@ using glm::mat4; constexpr auto *PROJECT_NAME = "Aster"; -struct Version { - u32 major; - u32 minor; - u32 patch; +struct Version +{ + u8 m_Major; + u8 m_Minor; + u8 m_Patch; + + [[nodiscard]] u32 + GetVkVersion() const + { + return VK_MAKE_API_VERSION(0, m_Major, m_Minor, m_Patch); + } }; constexpr Version VERSION = { - .major = 0, - .minor = 1, - .patch = 0, + .m_Major = 0, + .m_Minor = 1, + .m_Patch = 0, }; template -constexpr T max_value = std::numeric_limits::max(); +constexpr T MaxValue = std::numeric_limits::max(); template -constexpr T min_value = std::numeric_limits::min(); +constexpr T MinValue = std::numeric_limits::min(); template -constexpr T lowest_value = std::numeric_limits::lowest(); +constexpr T LowestValue = std::numeric_limits::lowest(); template -constexpr T err_epsilon = std::numeric_limits::epsilon(); +constexpr T ErrEpsilon = std::numeric_limits::epsilon(); template -constexpr T positive_inf = std::numeric_limits::infinity(); +constexpr T PositiveInf = std::numeric_limits::infinity(); template -constexpr T negative_inf = -std::numeric_limits::infinity(); +constexpr T NegativeInf = -std::numeric_limits::infinity(); template -constexpr T qnan = std::numeric_limits::quiet_NaN(); +constexpr T Qnan = std::numeric_limits::quiet_NaN(); template -constexpr T snan = std::numeric_limits::signalling_NaN(); +constexpr T Snan = std::numeric_limits::signalling_NaN(); diff --git a/aster/context.cpp b/aster/context.cpp index 809f925..ccbbc93 100644 --- a/aster/context.cpp +++ b/aster/context.cpp @@ -4,97 +4,108 @@ // ============================================= #include "context.h" +#include +#include -VKAPI_ATTR b32 VKAPI_CALL Context::debug_callback(VkDebugUtilsMessageSeverityFlagBitsEXT _message_severity, VkDebugUtilsMessageTypeFlagsEXT _message_type, const VkDebugUtilsMessengerCallbackDataEXT *_callback_data, [[maybe_unused]] void *_user_data) { - using Severity = vk::DebugUtilsMessageSeverityFlagsEXT; - using SeverityBits = vk::DebugUtilsMessageSeverityFlagBitsEXT; - using MessageType = vk::DebugUtilsMessageTypeFlagsEXT; - using MessageTypeBits = vk::DebugUtilsMessageTypeFlagBitsEXT; +constexpr eastl::array VALIDATION_LAYERS = { + "VK_LAYER_KHRONOS_validation", +}; - const auto severity = Severity(_message_severity); - const auto message_type = MessageType(_message_type); +VKAPI_ATTR b32 VKAPI_CALL +debugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageType, + const VkDebugUtilsMessengerCallbackDataEXT *callbackData, [[maybe_unused]] void *userData) +{ + using Severity = vk::DebugUtilsMessageSeverityFlagsEXT; + using SeverityBits = vk::DebugUtilsMessageSeverityFlagBitsEXT; + using MessageType = vk::DebugUtilsMessageTypeFlagsEXT; + using MessageTypeBits = vk::DebugUtilsMessageTypeFlagBitsEXT; - if (message_type & MessageTypeBits::eValidation) { - if (severity & SeverityBits::eError) - ERROR("{}", _callback_data->pMessage); - if (severity & SeverityBits::eWarning) - WARN("{}", _callback_data->pMessage); - if (severity & SeverityBits::eInfo) - INFO("{}", _callback_data->pMessage); - if (severity & SeverityBits::eVerbose) - VERBOSE("{}", _callback_data->pMessage); - } + const auto severity = Severity(messageSeverity); - return false; + if (MessageType(messageType) & MessageTypeBits::eValidation) + { + if (severity & SeverityBits::eError) + ERROR("{}", callbackData->pMessage); + if (severity & SeverityBits::eWarning) + WARN("{}", callbackData->pMessage); + if (severity & SeverityBits::eInfo) + INFO("{}", callbackData->pMessage); + if (severity & SeverityBits::eVerbose) + VERBOSE("{}", callbackData->pMessage); + } + + return false; } -void Context::init(const std::string_view &_app_name, const Version &_app_version) { - INFO_IF(enable_validation_layers, "Validation Layers enabled"); +Context::Context(cstr appName, Version version, bool enableValidation) +{ + INFO_IF(enableValidation, "Validation Layers enabled"); - // Creating Instance - const vk::ApplicationInfo app_info = { - .pApplicationName = _app_name.data(), - .applicationVersion = VK_MAKE_VERSION(_app_version.major, _app_version.minor, _app_version.patch), - .pEngineName = PROJECT_NAME, - .engineVersion = VK_MAKE_VERSION(VERSION.major, VERSION.minor, VERSION.patch), - .apiVersion = ASTER_API_VERSION, - }; + // Creating Instance + const vk::ApplicationInfo appInfo = { + .pApplicationName = appName, + .applicationVersion = version.GetVkVersion(), + .pEngineName = PROJECT_NAME, + .engineVersion = version.GetVkVersion(), + .apiVersion = ASTER_API_VERSION, + }; - vk::DebugUtilsMessengerCreateInfoEXT debug_messenger_create_info = { - .messageSeverity = vk::DebugUtilsMessageSeverityFlagBitsEXT::eError | - vk::DebugUtilsMessageSeverityFlagBitsEXT::eWarning | - vk::DebugUtilsMessageSeverityFlagBitsEXT::eInfo, - .messageType = vk::DebugUtilsMessageTypeFlagBitsEXT::eGeneral | - vk::DebugUtilsMessageTypeFlagBitsEXT::ePerformance | - vk::DebugUtilsMessageTypeFlagBitsEXT::eValidation, - .pfnUserCallback = debug_callback, - .pUserData = nullptr, - }; + vk::DebugUtilsMessengerCreateInfoEXT debugUtilsMessengerCreateInfo = { + .messageSeverity = vk::DebugUtilsMessageSeverityFlagBitsEXT::eError | + vk::DebugUtilsMessageSeverityFlagBitsEXT::eWarning | + vk::DebugUtilsMessageSeverityFlagBitsEXT::eInfo, + .messageType = vk::DebugUtilsMessageTypeFlagBitsEXT::eGeneral | + vk::DebugUtilsMessageTypeFlagBitsEXT::ePerformance | + vk::DebugUtilsMessageTypeFlagBitsEXT::eValidation, + .pfnUserCallback = debugCallback, + .pUserData = nullptr, + }; - u32 glfw_extension_count = 0; - const char **glfw_extensions = glfwGetRequiredInstanceExtensions(&glfw_extension_count); - std::vector vulkan_extensions(glfw_extensions, glfw_extensions + glfw_extension_count); - if (enable_validation_layers) { - vulkan_extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); - } + u32 glfwExtensionCount = 0; + cstr *glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount); + eastl::fixed_vector instanceExtensions(glfwExtensions, glfwExtensions + glfwExtensionCount); + if (enableValidation) + { + instanceExtensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); + } - const vk::DynamicLoader dl; - // ReSharper disable once CppInconsistentNaming - const auto vkGetInstanceProcAddr = dl.getProcAddress("vkGetInstanceProcAddr"); - VULKAN_HPP_DEFAULT_DISPATCHER.init(vkGetInstanceProcAddr); + const vk::DynamicLoader dl; + // ReSharper disable once CppInconsistentNaming + const auto vkGetInstanceProcAddr = dl.getProcAddress("vkGetInstanceProcAddr"); + VULKAN_HPP_DEFAULT_DISPATCHER.init(vkGetInstanceProcAddr); - const auto instance_create_info = vk::InstanceCreateInfo{ - .pNext = enable_validation_layers ? &debug_messenger_create_info : nullptr, - .pApplicationInfo = &app_info, - .enabledLayerCount = enable_validation_layers ? cast(validation_layers.size()) : 0, - .ppEnabledLayerNames = enable_validation_layers ? validation_layers.data() : nullptr, - .enabledExtensionCount = cast(vulkan_extensions.size()), - .ppEnabledExtensionNames = vulkan_extensions.data(), - }; + const auto instanceCreateInfo = vk::InstanceCreateInfo{ + .pNext = enableValidation ? &debugUtilsMessengerCreateInfo : nullptr, + .pApplicationInfo = &appInfo, + .enabledLayerCount = enableValidation ? cast(VALIDATION_LAYERS.size()) : 0, + .ppEnabledLayerNames = enableValidation ? VALIDATION_LAYERS.data() : nullptr, + .enabledExtensionCount = cast(instanceExtensions.size()), + .ppEnabledExtensionNames = instanceExtensions.data(), + }; - // May throw. Irrecoverable. - instance = vk::createInstance(instance_create_info); - INFO("Instance Created."); - VULKAN_HPP_DEFAULT_DISPATCHER.init(instance); + // May throw. Irrecoverable. + vk::Result result = vk::createInstance(&instanceCreateInfo, nullptr, &m_Instance); + ERROR_IF(result, "Instance creation failed. Cause: {}", to_string(result)) + THEN_ABORT(result) + ELSE_DEBUG("Instance Created."); + VULKAN_HPP_DEFAULT_DISPATCHER.init(m_Instance); - // Debug Messenger - if (enable_validation_layers) { - try { - debug_messenger = instance.createDebugUtilsMessengerEXT(debug_messenger_create_info); - } catch (const std::exception &_err) { - ERROR("Debug Messenger creation failed. Cause: {}", _err.what()); - // Non-critical. Continue. - } - INFO("Debug Messenger Created."); - } + // Debug Messenger + if (enableValidation) + { + result = m_Instance.createDebugUtilsMessengerEXT(&debugUtilsMessengerCreateInfo, nullptr, &m_DebugMessenger); + ERROR_IF(result, "Debug Messenger creation failed. Cause: {}", to_string(result)) // Non-critical. Continue. + ELSE_DEBUG("Debug Messenger Created."); + } } -Context::~Context() { - if (instance) { - if (enable_validation_layers && debug_messenger) { - instance.destroyDebugUtilsMessengerEXT(debug_messenger); - } - instance.destroy(); - INFO("Context destroyed"); - } +Context::~Context() +{ + if (m_DebugMessenger) + { + m_Instance.destroy(m_DebugMessenger, nullptr); + DEBUG("Debug Messenger destroyed"); + } + m_Instance.destroy(nullptr); + DEBUG("Instance destroyed"); } diff --git a/aster/context.h b/aster/context.h index b6c6f60..7fa3415 100644 --- a/aster/context.h +++ b/aster/context.h @@ -6,8 +6,6 @@ #pragma once #include "global.h" -#include -#include /** * @class Context @@ -16,71 +14,13 @@ * * Handles the required hardware interactions. */ -class Context final { -public: - Context(const std::string_view &_app_name, const Version &_app_version, const b8 _enable_validation = true) : - enable_validation_layers{ _enable_validation } { - init(_app_name, _app_version); - } +struct Context final +{ + // Members + vk::Instance m_Instance = nullptr; + vk::DebugUtilsMessengerEXT m_DebugMessenger = nullptr; - Context(const std::string_view &_app_name, const Version &_app_version, const std::vector &_additional_device_extensions, const b8 _enable_validation = true) : - enable_validation_layers{ _enable_validation } { - device_extensions.reserve(device_extensions.size() + _additional_device_extensions.size()); - device_extensions.insert(device_extensions.end(), _additional_device_extensions.begin(), _additional_device_extensions.end()); - - init(_app_name, _app_version); - } - - Context(const std::string_view &_app_name, const Version &_app_version, const std::vector &_additional_device_extensions, const std::vector &_additional_validation_layers) { - device_extensions.reserve(device_extensions.size() + _additional_device_extensions.size()); - device_extensions.insert(device_extensions.end(), _additional_device_extensions.begin(), _additional_device_extensions.end()); - - validation_layers.reserve(validation_layers.size() + _additional_validation_layers.size()); - validation_layers.insert(validation_layers.end(), _additional_validation_layers.begin(), _additional_validation_layers.end()); - - init(_app_name, _app_version); - } - - Context(const Context &_other) = delete; - - Context(Context &&_other) noexcept : - enable_validation_layers{ _other.enable_validation_layers }, validation_layers{ std::move(_other.validation_layers) }, device_extensions{ std::move(_other.device_extensions) }, instance{ std::exchange(_other.instance, nullptr) }, debug_messenger{ std::exchange(_other.debug_messenger, nullptr) } {} - - Context &operator=(const Context &_other) = delete; - - Context &operator=(Context &&_other) noexcept { - if (this == &_other) - return *this; - enable_validation_layers = _other.enable_validation_layers; - validation_layers = std::move(_other.validation_layers); - device_extensions = std::move(_other.device_extensions); - instance = std::exchange(_other.instance, nullptr); - debug_messenger = std::exchange(_other.debug_messenger, nullptr); - return *this; - } - - ~Context(); - - // Fields - bool enable_validation_layers{ true }; - - std::vector validation_layers = { - "VK_LAYER_KHRONOS_validation", - }; - - std::vector device_extensions = { - VK_KHR_SWAPCHAIN_EXTENSION_NAME, - VK_KHR_MULTIVIEW_EXTENSION_NAME, - }; - - vk::Instance instance; - vk::DebugUtilsMessengerEXT debug_messenger; - -private: - void init(const std::string_view &_app_name, const Version &_app_version); - - static VKAPI_ATTR b32 VKAPI_CALL debug_callback(VkDebugUtilsMessageSeverityFlagBitsEXT _message_severity, - VkDebugUtilsMessageTypeFlagsEXT _message_type, - const VkDebugUtilsMessengerCallbackDataEXT *_callback_data, - void *_user_data); + // Ctor/Dtor + Context(cstr appName, Version version, bool enableValidation = true); + ~Context(); }; diff --git a/aster/device.cpp b/aster/device.cpp index a9c5e98..5481203 100644 --- a/aster/device.cpp +++ b/aster/device.cpp @@ -5,76 +5,81 @@ #include "device.h" -Device::Device(const Context *_context, PhysicalDevice &&_physical_device, const vk::PhysicalDeviceFeatures *_enabled_features, const std::vector &_queue_allocation, std::optional _name) : - physical_device{ std::move(_physical_device) }, - name{ std::move(_name) } { - std::vector queue_create_infos; - queue_create_infos.reserve(_queue_allocation.size()); +#include - u32 num_priorities = 0; - for (auto [_, count] : _queue_allocation) { - num_priorities = std::max(count, num_priorities); - } - std::vector priorities(num_priorities, 1.0f); +constexpr eastl::array DEVICE_EXTENSIONS = {VK_KHR_SWAPCHAIN_EXTENSION_NAME}; - for (auto [family, count] : _queue_allocation) { - queue_create_infos.push_back({ - .queueFamilyIndex = family, - .queueCount = count, - .pQueuePriorities = priorities.data(), - }); - } +Device::Device(const Context *context, PhysicalDevice &&physicalDevice, + const vk::PhysicalDeviceFeatures *enabledFeatures, + const eastl::vector &queueAllocations, NameString name) + : m_Name(std::move(name)) + , m_PhysicalDevice(std::make_unique(physicalDevice)) +{ + // Shouldn't have more than 4 deviceQueueFamilies in use anyway. Else we can heap + eastl::fixed_vector deviceQueueCreateInfos; + deviceQueueCreateInfos.reserve(queueAllocations.size()); - try { - device = physical_device.device.createDevice({ - .queueCreateInfoCount = cast(queue_create_infos.size()), - .pQueueCreateInfos = queue_create_infos.data(), - .enabledLayerCount = _context->enable_validation_layers ? cast(_context->validation_layers.size()) : 0, - .ppEnabledLayerNames = _context->enable_validation_layers ? _context->validation_layers.data() : nullptr, - .enabledExtensionCount = cast(_context->device_extensions.size()), - .ppEnabledExtensionNames = _context->device_extensions.data(), - .pEnabledFeatures = _enabled_features, - }); - } catch (const std::exception &_err) { - ERROR("Could not initialize Vulkan Device. Cause: {}", _err.what()); - throw; - } + u32 numPriorities = 0; + for (auto [_, count] : queueAllocations) + { + numPriorities = std::max(count, numPriorities); + } + // Shouldn't have more than 4 queues either. + eastl::fixed_vector priorities(numPriorities, 1.0f); - INFO("{} ({}) Initialized!", name.value_or(DEFAULT_DEVICE_NAME), physical_device.properties.deviceName.data()); + for (auto [family, count] : queueAllocations) + { + deviceQueueCreateInfos.push_back({ + .queueFamilyIndex = family, + .queueCount = count, + .pQueuePriorities = priorities.data(), + }); + } - VmaVulkanFunctions vma_vulkan_functions = { - .vkGetInstanceProcAddr = vk::defaultDispatchLoaderDynamic.vkGetInstanceProcAddr, - .vkGetDeviceProcAddr = vk::defaultDispatchLoaderDynamic.vkGetDeviceProcAddr, - }; + vk::DeviceCreateInfo deviceCreateInfo = { + .queueCreateInfoCount = cast(deviceQueueCreateInfos.size()), + .pQueueCreateInfos = deviceQueueCreateInfos.data(), + .enabledExtensionCount = cast(DEVICE_EXTENSIONS.size()), + .ppEnabledExtensionNames = DEVICE_EXTENSIONS.data(), + .pEnabledFeatures = enabledFeatures, + }; - const VmaAllocatorCreateInfo vma_allocator_create_info = { - .flags = 0, - .physicalDevice = physical_device.device, - .device = device, - .pVulkanFunctions = &vma_vulkan_functions, - .instance = _context->instance, - .vulkanApiVersion = ASTER_API_VERSION, - }; + vk::Result result = m_PhysicalDevice->m_PhysicalDevice.createDevice(&deviceCreateInfo, nullptr, &m_Device); + ERROR_IF(failed(result), "Could not initialize Vulkan Device. Cause: {}", result) + THEN_ABORT(result) + ELSE_DEBUG("{} ({}) Initialized.", m_Name, m_PhysicalDevice->m_DeviceProperties.deviceName.data()); - const auto result = cast(vmaCreateAllocator(&vma_allocator_create_info, &allocator)); - if (failed(result)) { - device.destroy(); - auto _err = fmt::format("Memory allocator creation failed. Cause: {}", to_string(result)); - ERROR("{}", _err); - throw std::runtime_error(_err); - } - VERBOSE("Memory Allocator Created"); + VmaVulkanFunctions vmaVulkanFunctions = { + .vkGetInstanceProcAddr = vk::defaultDispatchLoaderDynamic.vkGetInstanceProcAddr, + .vkGetDeviceProcAddr = vk::defaultDispatchLoaderDynamic.vkGetDeviceProcAddr, + }; - INFO("Created '{}' Successfully", name.value_or(DEFAULT_DEVICE_NAME)); + const VmaAllocatorCreateInfo allocatorCreateInfo = { + .flags = 0, + .physicalDevice = m_PhysicalDevice->m_PhysicalDevice, + .device = m_Device, + .pVulkanFunctions = &vmaVulkanFunctions, + .instance = context->m_Instance, + .vulkanApiVersion = ASTER_API_VERSION, + }; + + result = cast(vmaCreateAllocator(&allocatorCreateInfo, &m_Allocator)); + ERROR_IF(failed(result), "Memory allocator creation failed. Cause: {}", to_string(result)) + DO(m_Device.destroy(nullptr)) + THEN_ABORT(result) + ELSE_VERBOSE("Memory Allocator Created"); + + DEBUG("Created '{}' Successfully", m_Name); } -Device::~Device() { - if (allocator) { - vmaDestroyAllocator(allocator); - allocator = nullptr; - VERBOSE("Memory Allocator Destroyed"); - } - device.destroy(); - INFO("Device '{}' Destroyed", name.value_or(DEFAULT_DEVICE_NAME)); - name = std::nullopt; +Device::~Device() +{ + if (m_Allocator) + { + vmaDestroyAllocator(m_Allocator); + m_Allocator = nullptr; + DEBUG("Memory Allocator Destroyed"); + } + m_Device.destroy(nullptr); + DEBUG("Device '{}' Destroyed", m_Name); } \ No newline at end of file diff --git a/aster/device.h b/aster/device.h index e48941c..bdf210c 100644 --- a/aster/device.h +++ b/aster/device.h @@ -8,20 +8,23 @@ #include "global.h" #include "physical_device.h" -constexpr std::string DEFAULT_DEVICE_NAME = ""; - -struct QueueAllocation { - u32 family; - u32 count; +struct QueueAllocation +{ + u32 m_Family; + u32 m_Count; }; -struct Device final { - vk::Device device; - PhysicalDevice physical_device; - VmaAllocator allocator{ nullptr }; - std::optional name{ nullptr }; +struct Device final +{ + using NameString = eastl::fixed_string; - Device(const Context *_context, PhysicalDevice &&_physical_device, const vk::PhysicalDeviceFeatures *_enabled_features, const std::vector &_queue_allocation, std::optional _name = std::nullopt); + NameString m_Name; + std::unique_ptr m_PhysicalDevice; + vk::Device m_Device = nullptr; + VmaAllocator m_Allocator = nullptr; - ~Device(); + Device(const Context *context, PhysicalDevice &&physicalDevice, const vk::PhysicalDeviceFeatures *enabledFeatures, + const eastl::vector &queueAllocations, NameString name); + + ~Device(); }; diff --git a/aster/glfw_context.h b/aster/glfw_context.h index a33449a..7f70138 100644 --- a/aster/glfw_context.h +++ b/aster/glfw_context.h @@ -7,28 +7,36 @@ #include "global.h" -struct GlfwContext { - static i32 post_error() noexcept { - static const char *error_ = nullptr; - const auto code = glfwGetError(&error_); - ERROR("GLFW {}", error_); - return code; - } +struct GlfwContext +{ - inline static u32 count = 0; + static i32 + PostError() noexcept + { + static const char *error = nullptr; + const auto code = glfwGetError(&error); + ERROR("GLFW {}", error); + return code; + } - GlfwContext() { - if (count++ > 0) - return; - if (glfwInit() == GLFW_FALSE) { - CRASH(post_error()); - } - } + inline static u32 m_Count = 0; - ~GlfwContext() { - if (--count == 0) { - glfwTerminate(); - } - count = 0; - } + GlfwContext() + { + if (m_Count++ > 0) + return; + if (glfwInit() == GLFW_FALSE) + { + ABORT(PostError()); + } + } + + ~GlfwContext() + { + if (--m_Count == 0) + { + glfwTerminate(); + } + m_Count = 0; + } }; diff --git a/aster/global.cpp b/aster/global.cpp index 4a2128b..7f635df 100644 --- a/aster/global.cpp +++ b/aster/global.cpp @@ -13,3 +13,16 @@ // NOTE: Vulkan Dispatch Loader Storage - Should only appear once. VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE + +void * +operator new[](size_t size, const char *pName, int flags, unsigned debugFlags, const char *file, int line) +{ + return new u8[size]; +} + +void * +operator new[](size_t size, size_t alignment, size_t alignmentOffset, const char *pName, int flags, unsigned debugFlags, + const char *file, int line) +{ + return new u8[size]; +} \ No newline at end of file diff --git a/aster/global.h b/aster/global.h index 4e6092d..9d3f4d7 100644 --- a/aster/global.h +++ b/aster/global.h @@ -11,31 +11,53 @@ #include #include -#include -#include + +#include + +// Macros that can collide with functions. +#if defined(max) +#undef max +#endif + +#if defined(min) +#undef min +#endif #define VULKAN_HPP_ASSERT(expr) DEBUG_IF(!(expr), "Vulkan assert failed") +#include +#include #include + #include constexpr u32 ASTER_API_VERSION = vk::ApiVersion13; #define CODE_LOC " @ " __FILE__ ":" VULKAN_HPP_STRINGIFY(__LINE__) -[[nodiscard]] inline bool failed(const vk::Result _result) { - return _result != vk::Result::eSuccess; + +[[nodiscard]] inline bool +failed(const vk::Result result) +{ + return result != vk::Result::eSuccess; } template -concept IsVkEnum = requires(T _t) { - { std::is_enum_v }; - { vk::to_string(_t) } -> std::same_as; +concept IsVkEnum = requires(T t) { + { + std::is_enum_v + }; + { + vk::to_string(t) + } -> std::same_as; }; template -requires IsVkEnum [[nodiscard]] const char *to_cstr(const T &_val) { - static std::string buffer; - buffer = vk::to_string(_val); - return buffer.c_str(); + requires IsVkEnum +[[nodiscard]] const char * +toCstr(const T &val) +{ + static std::string buffer; + buffer = vk::to_string(val); + return buffer.c_str(); } // TODO: Check why inline namespaces aren't working in MSVC 19.27.29110 @@ -43,49 +65,87 @@ using namespace std::literals::string_literals; using namespace std::literals::string_view_literals; template -requires vk::isVulkanHandleType::value [[nodiscard]] constexpr u64 -get_vk_handle(const T &_vk_handle) noexcept { - return reinterpret_cast(cast(_vk_handle)); + requires vk::isVulkanHandleType::value +[[nodiscard]] constexpr u64 +getVkHandle(const T &vkHandle) noexcept +{ + return reinterpret_cast(cast(vkHandle)); } template -struct std::hash> { - [[nodiscard]] usize operator()(const vk::Flags &_val) { - return std::hash()(cast(_val)); - } +struct std::hash> +{ + [[nodiscard]] usize + operator()(const vk::Flags &val) + { + return std::hash()(cast(val)); + } }; template -[[nodiscard]] usize hash_any(const T &_val) { - return std::hash>()(_val); +[[nodiscard]] usize +hashAny(const T &val) +{ + return std::hash>()(val); } -[[nodiscard]] inline usize hash_combine(const usize _hash0, - const usize _hash1) { - constexpr usize salt_value = 0x9e3779b9; - return _hash0 ^ (_hash1 + salt_value + (_hash0 << 6) + (_hash0 >> 2)); +[[nodiscard]] inline usize +hashCombine(const usize hash0, const usize hash1) +{ + constexpr usize saltValue = 0x9e3779b9; + return hash0 ^ (hash1 + saltValue + (hash0 << 6) + (hash0 >> 2)); } -struct Time { - static constexpr f64 max_delta = 0.1; +struct Time +{ + static constexpr f64 c_MaxDelta = 0.1; - inline static f64 elapsed{ qnan }; - inline static f64 delta{ qnan }; + inline static f64 m_Elapsed{Qnan}; + inline static f64 m_Delta{Qnan}; - static void init() { - WARN_IF(!std::isnan(elapsed), "Time already init."); - elapsed = glfwGetTime(); - delta = 1.0 / 60.0; - } + static void + Init() + { + WARN_IF(!std::isnan(m_Elapsed), "Time already init."); + m_Elapsed = glfwGetTime(); + m_Delta = 1.0 / 60.0; + } - static void update() { - ERROR_IF(std::isnan(elapsed), "Time not init."); - const auto new_elapsed = glfwGetTime(); - delta = std::clamp(new_elapsed - elapsed, 0.0, max_delta); - elapsed = new_elapsed; - } + static void + Update() + { + ERROR_IF(std::isnan(m_Elapsed), "Time not init."); + const auto newElapsed = glfwGetTime(); + m_Delta = std::clamp(newElapsed - m_Elapsed, 0.0, c_MaxDelta); + m_Elapsed = newElapsed; + } }; -[[nodiscard]] inline usize closest_multiple(const usize _val, const usize _of) { - return _of * ((_val + _of - 1) / _of); +[[nodiscard]] inline usize +closestMultiple(const usize val, const usize of) +{ + return of * ((val + of - 1) / of); } + +template <> +struct fmt::formatter : nested_formatter +{ + auto + // ReSharper disable once CppInconsistentNaming + format(vk::Result result, format_context &ctx) const + { + return write_padded(ctx, + [this, result](auto out) { return v10::format_to(out, "{}", nested(to_string(result))); }); + } +}; + +template +struct fmt::formatter> : nested_formatter +{ + auto + // ReSharper disable once CppInconsistentNaming + format(const eastl::fixed_string &str, format_context &ctx) const + { + return write_padded(ctx, [this, str](auto out) { return v10::format_to(out, "{}", nested(str.c_str())); }); + } +}; \ No newline at end of file diff --git a/aster/logger.cpp b/aster/logger.cpp index cdc2f6b..2367aeb 100644 --- a/aster/logger.cpp +++ b/aster/logger.cpp @@ -5,13 +5,16 @@ #include "logger.h" -Logger g_logger = Logger(); +Logger g_Logger = Logger(); +// ReSharper disable once CppInconsistentNaming /* Credits to Const-me */ -//namespace eastl { -// void __cdecl AssertionFailure(const char* af) -// { -// ERROR(af); -// __debugbreak(); -// } -//} +namespace eastl +{ +void +AssertionFailure(const char *af) +{ + ERROR("{}", af); + debug_break(); +} +} // namespace eastl diff --git a/aster/logger.h b/aster/logger.h index 2a2c53a..7d7689f 100644 --- a/aster/logger.h +++ b/aster/logger.h @@ -9,175 +9,200 @@ #include #include -#include +struct Logger +{ + enum class LogType : u32 + { + eError, + eWarning, + eInfo, + eDebug, + eVerbose, + }; -struct Logger { - enum class LogType : u32 { - eError, - eWarning, - eInfo, - eDebug, - eVerbose, - }; + u32 m_MinimumLoggingLevel{cast(LogType::eDebug)}; - u32 minimum_logging_level{ cast(LogType::eDebug) }; + void + SetMinimumLoggingLevel(LogType logType) + { + m_MinimumLoggingLevel = cast(logType); + } - void set_minimum_logging_level(LogType _log_type) { - minimum_logging_level = cast(_log_type); - } + template + constexpr static const char * + ToCstr() + { + if constexpr (LogLevel == LogType::eError) + return "[ERROR]:"; + if constexpr (LogLevel == LogType::eWarning) + return "[WARN]: "; + if constexpr (LogLevel == LogType::eInfo) + return "[INFO]: "; + if constexpr (LogLevel == LogType::eDebug) + return "[DEBUG]:"; + if constexpr (LogLevel == LogType::eVerbose) + return "[VERB]: "; + return ""; + } - template - constexpr static const char *to_cstr() { - if constexpr (LogLevel == LogType::eError) - return "[ERROR]:"; - if constexpr (LogLevel == LogType::eWarning) - return "[WARN]: "; - if constexpr (LogLevel == LogType::eInfo) - return "[INFO]: "; - if constexpr (LogLevel == LogType::eDebug) - return "[DEBUG]:"; - if constexpr (LogLevel == LogType::eVerbose) - return "[VERB]: "; - return ""; - } + template + constexpr static const char * + ToColorCstr() + { + if constexpr (LogLevel == LogType::eError) + return ansi_color::Red; + if constexpr (LogLevel == LogType::eWarning) + return ansi_color::Yellow; + if constexpr (LogLevel == LogType::eInfo) + return ansi_color::Green; + if constexpr (LogLevel == LogType::eDebug) + return ansi_color::White; + if constexpr (LogLevel == LogType::eVerbose) + return ansi_color::Blue; + return ansi_color::White; + } - template - constexpr static const char *to_color_cstr() { - if constexpr (LogLevel == LogType::eError) - return ANSI_Red; - if constexpr (LogLevel == LogType::eWarning) - return ANSI_Yellow; - if constexpr (LogLevel == LogType::eInfo) - return ANSI_Green; - if constexpr (LogLevel == LogType::eDebug) - return ANSI_White; - if constexpr (LogLevel == LogType::eVerbose) - return ANSI_Blue; - return ANSI_White; - } - - template - void log(const std::string_view &_message, const char *_loc, u32 _line) const { - if (cast(LogLevel) <= minimum_logging_level) { - fmt::println("{}{} {} {} at {}:{}{}", to_color_cstr(), to_cstr(), _message.data(), ANSI_Black, _loc, _line, ANSI_Reset); - } + template + void + Log(const std::string_view &message, const char *loc, u32 line) const + { + if (cast(LogLevel) <= m_MinimumLoggingLevel) + { + fmt::println("{}{} {} {} at {}:{}{}", ToColorCstr(), ToCstr(), message.data(), + ansi_color::Black, loc, line, ansi_color::Reset); + } #if !defined(NDEBUG) - if constexpr (LogLevel == LogType::eError) { - debug_break(); - } + if constexpr (LogLevel == LogType::eError) + { + debug_break(); + } #endif // !defined(NDEBUG) - } + } - template - void log_cond(const char *_expr_str, const std::string_view &_message, const char *_loc, u32 _line) const { - if (cast(LogLevel) <= minimum_logging_level) { - fmt::println("{}{} ({}) {} {} at {}:{}{}", to_color_cstr(), to_cstr(), _expr_str, _message.data(), ANSI_Black, _loc, _line, ANSI_Reset); - } + template + void + LogCond(const char *exprStr, const std::string_view &message, const char *loc, u32 line) const + { + if (cast(LogLevel) <= m_MinimumLoggingLevel) + { + fmt::println("{}{} ({}) {} {} at {}:{}{}", ToColorCstr(), ToCstr(), exprStr, + message.data(), ansi_color::Black, loc, line, ansi_color::Reset); + } #if !defined(NDEBUG) - if constexpr (LogLevel == LogType::eError) { - debug_break(); - } + if constexpr (LogLevel == LogType::eError) + { + debug_break(); + } #endif // !defined(NDEBUG) - } + } }; -extern Logger g_logger; +extern Logger g_Logger; -#define MIN_LOG_LEVEL(LOG_LVL) g_logger.set_minimum_logging_level(LOG_LVL) -#define ERROR(...) g_logger.log(fmt::format(__VA_ARGS__), __FILE__, __LINE__) -#define WARN(...) g_logger.log(fmt::format(__VA_ARGS__), __FILE__, __LINE__) -#define INFO(...) g_logger.log(fmt::format(__VA_ARGS__), __FILE__, __LINE__) +#define MIN_LOG_LEVEL(LOG_LVL) g_Logger.SetMinimumLoggingLevel(LOG_LVL) +#define ERROR(...) g_Logger.Log(fmt::format(__VA_ARGS__), __FILE__, __LINE__) +#define WARN(...) g_Logger.Log(fmt::format(__VA_ARGS__), __FILE__, __LINE__) +#define INFO(...) g_Logger.Log(fmt::format(__VA_ARGS__), __FILE__, __LINE__) -#define ERROR_IF(expr, ...) \ - if (cast(expr)) [[unlikely]] \ - g_logger.log_cond(#expr, fmt::format(__VA_ARGS__), __FILE__, __LINE__) -#define WARN_IF(expr, ...) \ - if (cast(expr)) [[unlikely]] \ - g_logger.log_cond(#expr, fmt::format(__VA_ARGS__), __FILE__, __LINE__) -#define INFO_IF(expr, ...) \ - if (cast(expr)) \ - g_logger.log_cond(#expr, fmt::format(__VA_ARGS__), __FILE__, __LINE__) +#define ERROR_IF(expr, ...) \ + if (cast(expr)) [[unlikely]] \ + g_Logger.LogCond(#expr, fmt::format(__VA_ARGS__), __FILE__, __LINE__) +#define WARN_IF(expr, ...) \ + if (cast(expr)) [[unlikely]] \ + g_Logger.LogCond(#expr, fmt::format(__VA_ARGS__), __FILE__, __LINE__) +#define INFO_IF(expr, ...) \ + if (cast(expr)) \ + g_Logger.LogCond(#expr, fmt::format(__VA_ARGS__), __FILE__, __LINE__) -#define ELSE_IF_ERROR(expr, ...) \ - ; \ - else if (cast(expr)) [[unlikely]] g_logger.log_cond(#expr, fmt::format(__VA_ARGS__), __FILE__, __LINE__) -#define ELSE_IF_WARN(expr, ...) \ - ; \ - else if (cast(expr)) [[unlikely]] g_logger.log_cond(#expr, fmt::format(__VA_ARGS__), __FILE__, __LINE__) -#define ELSE_IF_INFO(expr, ...) \ - ; \ - else if (cast(expr)) g_logger.log_cond(#expr, fmt::format(__VA_ARGS__), __FILE__, __LINE__) +#define ELSE_IF_ERROR(expr, ...) \ + ; \ + else if (cast(expr)) \ + [[unlikely]] g_Logger.LogCond(#expr, fmt::format(__VA_ARGS__), __FILE__, __LINE__) +#define ELSE_IF_WARN(expr, ...) \ + ; \ + else if (cast(expr)) \ + [[unlikely]] g_Logger.LogCond(#expr, fmt::format(__VA_ARGS__), __FILE__, __LINE__) +#define ELSE_IF_INFO(expr, ...) \ + ; \ + else if (cast(expr)) \ + g_Logger.LogCond(#expr, fmt::format(__VA_ARGS__), __FILE__, __LINE__) -#define ELSE_ERROR(...) \ - ; \ - else [[unlikely]] g_logger.log(fmt::format(__VA_ARGS__), __FILE__, __LINE__) -#define ELSE_WARN(...) \ - ; \ - else [[unlikely]] g_logger.log(fmt::format(__VA_ARGS__), __FILE__, __LINE__) -#define ELSE_INFO(...) \ - ; \ - else g_logger.log(fmt::format(__VA_ARGS__), __FILE__, __LINE__) +#define ELSE_ERROR(...) \ + ; \ + else [[unlikely]] g_Logger.Log(fmt::format(__VA_ARGS__), __FILE__, __LINE__) +#define ELSE_WARN(...) \ + ; \ + else [[unlikely]] g_Logger.Log(fmt::format(__VA_ARGS__), __FILE__, __LINE__) +#define ELSE_INFO(...) \ + ; \ + else g_Logger.Log(fmt::format(__VA_ARGS__), __FILE__, __LINE__) #if !defined(DEBUG_LOG_DISABLED) && !defined(NDEBUG) -#define DEBUG(...) g_logger.log(fmt::format(__VA_ARGS__), __FILE__, __LINE__) -#define DEBUG_IF(expr, ...) \ - if (cast(expr)) \ - g_logger.log_cond(#expr, fmt::format(__VA_ARGS__), __FILE__, __LINE__) -#define ELSE_IF_DEBUG(expr, ...) \ - ; \ - else if (cast(expr)) g_logger.log_cond(#expr, fmt::format(__VA_ARGS__), __FILE__, __LINE__) -#define ELSE_DEBUG(...) \ - ; \ - else [[unlikely]] g_logger.log(fmt::format(__VA_ARGS__), __FILE__, __LINE__) +#define DEBUG(...) g_Logger.Log(fmt::format(__VA_ARGS__), __FILE__, __LINE__) +#define DEBUG_IF(expr, ...) \ + if (cast(expr)) \ + g_Logger.LogCond(#expr, fmt::format(__VA_ARGS__), __FILE__, __LINE__) +#define ELSE_IF_DEBUG(expr, ...) \ + ; \ + else if (cast(expr)) \ + g_Logger.LogCond(#expr, fmt::format(__VA_ARGS__), __FILE__, __LINE__) +#define ELSE_DEBUG(...) \ + ; \ + else g_Logger.Log(fmt::format(__VA_ARGS__), __FILE__, __LINE__) #else // !defined(DEBUG_LOG_DISABLED) -#define DEBUG(msg) \ - {} -#define DEBUG_IF(expr, msg) \ - if (expr) \ - (void)msg -#define ELSE_IF_DEBUG(expr, msg) \ - ; \ - if (expr) \ - (void)msg -#define ELSE_DEBUG(msg) \ - ; \ - {} +#define DEBUG(msg) \ + { \ + } +#define DEBUG_IF(expr, msg) \ + if (expr) \ + (void)msg +#define ELSE_IF_DEBUG(expr, msg) \ + ; \ + if (expr) \ + (void)msg +#define ELSE_DEBUG(msg) \ + ; \ + { \ + } #endif // !defined(DEBUG_LOG_DISABLED) #if !defined(VERBOSE_LOG_DISABLED) && !defined(NDEBUG) -#define VERBOSE(...) g_logger.log(fmt::format(__VA_ARGS__), __FILE__, __LINE__) -#define VERBOSE_IF(expr, ...) \ - if (cast(expr)) \ - g_logger.log_cond(#expr, fmt::format(__VA_ARGS__), __FILE__, __LINE__) -#define ELSE_IF_VERBOSE(expr, ...) \ - ; \ - else if (cast(expr)) g_logger.log_cond(#expr, fmt::format(__VA_ARGS__), __FILE__, __LINE__) -#define ELSE_VERBOSE(...) \ - ; \ - else g_logger.log(fmt::format(__VA_ARGS__), __FILE__, __LINE__) +#define VERBOSE(...) g_Logger.Log(fmt::format(__VA_ARGS__), __FILE__, __LINE__) +#define VERBOSE_IF(expr, ...) \ + if (cast(expr)) \ + g_Logger.LogCond(#expr, fmt::format(__VA_ARGS__), __FILE__, __LINE__) +#define ELSE_IF_VERBOSE(expr, ...) \ + ; \ + else if (cast(expr)) \ + g_Logger.LogCond(#expr, fmt::format(__VA_ARGS__), __FILE__, __LINE__) +#define ELSE_VERBOSE(...) \ + ; \ + else g_Logger.Log(fmt::format(__VA_ARGS__), __FILE__, __LINE__) #else // !defined(DEBUG_LOG_DISABLED) -#define VERBOSE(msg) \ - {} -#define VERBOSE_IF(expr, msg) \ - if (expr) \ - (void)msg -#define ELSE_IF_VERBOSE(expr, msg) \ - ; \ - if (expr) \ - (void)msg -#define ELSE_VERBOSE(msg) \ - ; \ - {} +#define VERBOSE(msg) \ + { \ + } +#define VERBOSE_IF(expr, msg) \ + if (expr) \ + (void)msg +#define ELSE_IF_VERBOSE(expr, msg) \ + ; \ + if (expr) \ + (void)msg +#define ELSE_VERBOSE(msg) \ + ; \ + { \ + } #endif // !defined(VERBOSE_LOG_DISABLED) #define DO(code) , code -#define CRASH(code) exit(cast(code)) -#define THEN_CRASH(code) , CRASH(code) +#define ABORT(code) exit(cast(code)) +#define THEN_ABORT(code) , ABORT(code) diff --git a/aster/physical_device.cpp b/aster/physical_device.cpp index 770876a..7f2f449 100644 --- a/aster/physical_device.cpp +++ b/aster/physical_device.cpp @@ -5,95 +5,145 @@ #include "physical_device.h" -[[nodiscard]] std::vector get_surface_formats(const Window *_window, const vk::PhysicalDevice *_physical_device) { - try { - return _physical_device->getSurfaceFormatsKHR(_window->surface); - } catch (const std::exception &_err) { - ERROR("Could not get surface formats. Cause: {}", _err.what()); - throw; - } +[[nodiscard]] eastl::vector +getSurfaceFormats(const vk::SurfaceKHR surface, const vk::PhysicalDevice physicalDevice) +{ + // vk::Result::eIncomplete should not occur in this function. The rest are errors. Thus, abort is allowed. + u32 count = 0; + vk::Result result = physicalDevice.getSurfaceFormatsKHR(surface, &count, nullptr); + ERROR_IF(failed(result), "Could not get surface formats. Cause: {}", to_string(result)) + THEN_ABORT(result); + + eastl::vector surfaceFormats(count); + result = physicalDevice.getSurfaceFormatsKHR(surface, &count, surfaceFormats.data()); + ERROR_IF(failed(result), "Could not get surface formats. Cause: {}", to_string(result)) + THEN_ABORT(result); + + return surfaceFormats; } -[[nodiscard]] std::vector get_present_modes(const Window *_window, const vk::PhysicalDevice *_physical_device) { - try { - return _physical_device->getSurfacePresentModesKHR(_window->surface); - } catch (const std::exception &_err) { - ERROR("Could not get present modes. Cause: {}", _err.what()); - throw; - } +[[nodiscard]] eastl::vector +getSurfacePresentModes(const vk::SurfaceKHR surface, const vk::PhysicalDevice physicalDevice) +{ + // vk::Result::eIncomplete should not occur in this function. The rest are errors. Thus, abort is allowed. + u32 count = 0; + vk::Result result = physicalDevice.getSurfacePresentModesKHR(surface, &count, nullptr); + ERROR_IF(failed(result), "Could not get present modes. Cause: {}", to_string(result)) + THEN_ABORT(result); + + eastl::vector presentModes(count); + result = physicalDevice.getSurfacePresentModesKHR(surface, &count, presentModes.data()); + ERROR_IF(failed(result), "Could not get present modes. Cause: {}", to_string(result)) + THEN_ABORT(result); + + return presentModes; } -[[nodiscard]] bool get_present_support(const u32 _family_index, const Window *_window, const vk::PhysicalDevice *_device) { - try { - return _device->getSurfaceSupportKHR(_family_index, _window->surface); - } catch (const std::exception &_err) { - ERROR("Could not get queue family surface support. Cause: {}", _err.what()); - throw; - } +[[nodiscard]] bool +getQueuePresentSupport(const u32 queueFamilyIndex, vk::SurfaceKHR surface, const vk::PhysicalDevice physicalDevice) +{ + b32 supported = false; + const vk::Result result = physicalDevice.getSurfaceSupportKHR(queueFamilyIndex, surface, &supported); + ERROR_IF(failed(result), "Could not get queue family surface support. Cause: {}", to_string(result)) + THEN_ABORT(result); + + return supported; } -[[nodiscard]] std::vector get_queue_families(const Window *_window, const vk::PhysicalDevice *_device) { - auto queue_family_props = _device->getQueueFamilyProperties(); +[[nodiscard]] eastl::fixed_vector +getQueueFamilyProperties(const vk::PhysicalDevice physicalDevice) +{ + // Devices rarely have more than 32 queue families. Thus fixed vector + u32 count = 0; + physicalDevice.getQueueFamilyProperties(&count, nullptr); - std::vector queue_family_infos; - queue_family_infos.reserve(queue_family_props.size()); + eastl::fixed_vector queueFamilyProperties(count); + physicalDevice.getQueueFamilyProperties(&count, queueFamilyProperties.data()); - u32 family_index = 0; - for (auto qfp : queue_family_props) { - QueueSupportFlags support = {}; - - if (qfp.queueFlags | vk::QueueFlagBits::eGraphics) { - support |= QueueSupportFlagBits::eGraphics; - } - - if (qfp.queueFlags | vk::QueueFlagBits::eTransfer) { - support |= QueueSupportFlagBits::eTransfer; - } - - if (qfp.queueFlags | vk::QueueFlagBits::eCompute) { - support |= QueueSupportFlagBits::eCompute; - } - - if (get_present_support(family_index, _window, _device)) { - support |= QueueSupportFlagBits::ePresent; - } - - queue_family_infos.push_back({ - .index = family_index, - .count = qfp.queueCount, - .support = support, - }); - - family_index++; - } - - return queue_family_infos; + return queueFamilyProperties; } -PhysicalDevice::PhysicalDevice(const Window *_window, vk::PhysicalDevice _physical_device) { - _physical_device.getProperties(&properties); - _physical_device.getFeatures(&features); +// Size 384 return. +[[nodiscard]] eastl::vector +getQueueFamilies(const vk::SurfaceKHR surface, const vk::PhysicalDevice physicalDevice) +{ - surface_formats = get_surface_formats(_window, &_physical_device); - present_modes = get_present_modes(_window, &_physical_device); - queue_families = get_queue_families(_window, &_physical_device); + auto queueFamilyProperties = getQueueFamilyProperties(physicalDevice); - device = _physical_device; + eastl::vector queueFamilyInfos; + queueFamilyInfos.reserve(queueFamilyProperties.size()); + + u32 familyIndex = 0; + for (auto qfp : queueFamilyProperties) + { + QueueSupportFlags support = {}; + + if (qfp.queueFlags | vk::QueueFlagBits::eGraphics) + { + support |= QueueSupportFlagBits::eGraphics; + } + + if (qfp.queueFlags | vk::QueueFlagBits::eTransfer) + { + support |= QueueSupportFlagBits::eTransfer; + } + + if (qfp.queueFlags | vk::QueueFlagBits::eCompute) + { + support |= QueueSupportFlagBits::eCompute; + } + + if (getQueuePresentSupport(familyIndex, surface, physicalDevice)) + { + support |= QueueSupportFlagBits::ePresent; + } + + queueFamilyInfos.push_back({ + .m_Index = familyIndex, + .m_Count = qfp.queueCount, + .m_Support = support, + }); + + familyIndex++; + } + + return queueFamilyInfos; } -std::vector enumerate_physical_devices(const Context *_context) { - try { - return _context->instance.enumeratePhysicalDevices(); - } catch (const std::exception &_err) { - ERROR("Could not fetch vulkan devices. Cause: {}", _err.what()); - throw; - } +PhysicalDevice::PhysicalDevice(const vk::SurfaceKHR surface, const vk::PhysicalDevice physicalDevice) +{ + physicalDevice.getProperties(&m_DeviceProperties); + physicalDevice.getFeatures(&m_DeviceFeatures); + + m_SurfaceFormats = getSurfaceFormats(surface, physicalDevice); + m_PresentModes = getSurfacePresentModes(surface, physicalDevice); + m_QueueFamilies = getQueueFamilies(surface, physicalDevice); + + m_PhysicalDevice = physicalDevice; } -PhysicalDevices::PhysicalDevices(const Window *_window, const Context *_context) { - auto physical_devices = enumerate_physical_devices(_context); - this->reserve(physical_devices.size()); - for (auto physical_device : physical_devices) { - this->emplace_back(_window, physical_device); - } +eastl::fixed_vector +enumeratePhysicalDevices(const vk::Instance instance) +{ + u32 count = 0; + vk::Result result = instance.enumeratePhysicalDevices(&count, nullptr); + ERROR_IF(failed(result), "Could not fetch vulkan devices. Cause: {}", to_string(result)) + THEN_ABORT(result); + + eastl::fixed_vector physicalDevices(count); + result = instance.enumeratePhysicalDevices(&count, physicalDevices.data()); + ERROR_IF(failed(result), "Could not fetch vulkan devices. Cause: {}", to_string(result)) + THEN_ABORT(result); + + return physicalDevices; +} + +PhysicalDevices::PhysicalDevices(const Window *window, const Context *context) +{ + auto surface = window->m_Surface; + auto physicalDevices = enumeratePhysicalDevices(context->m_Instance); + for (auto physicalDevice : physicalDevices) + { + this->emplace_back(surface, physicalDevice); + } } diff --git a/aster/physical_device.h b/aster/physical_device.h index ef5b368..496afe1 100644 --- a/aster/physical_device.h +++ b/aster/physical_device.h @@ -7,34 +7,39 @@ #include "global.h" #include "window.h" +#include -enum class QueueSupportFlagBits { - eGraphics = 0b0001, - eTransfer = 0b0010, - eCompute = 0b0100, - ePresent = 0b1000, +enum class QueueSupportFlagBits +{ + eGraphics = 0b0001, + eTransfer = 0b0010, + eCompute = 0b0100, + ePresent = 0b1000, }; using QueueSupportFlags = vk::Flags; -struct QueueFamilyInfo { - u32 index; - u32 count; - QueueSupportFlags support; +struct QueueFamilyInfo +{ + u32 m_Index; + u32 m_Count; + QueueSupportFlags m_Support; }; -struct PhysicalDevice { - vk::PhysicalDevice device; - vk::PhysicalDeviceProperties properties; - vk::PhysicalDeviceFeatures features; - std::vector surface_formats; - std::vector present_modes; - std::vector queue_families; +struct PhysicalDevice +{ + vk::PhysicalDevice m_PhysicalDevice; + vk::PhysicalDeviceProperties m_DeviceProperties; + vk::PhysicalDeviceFeatures m_DeviceFeatures; + eastl::vector m_SurfaceFormats; + eastl::vector m_PresentModes; + eastl::vector m_QueueFamilies; - PhysicalDevice(const Window *_window, vk::PhysicalDevice _physical_device); + PhysicalDevice(vk::SurfaceKHR surface, vk::PhysicalDevice physicalDevice); }; -class PhysicalDevices : public std::vector { -public: - PhysicalDevices(const Window *_window, const Context *_context); +class PhysicalDevices : public eastl::fixed_vector +{ + public: + PhysicalDevices(const Window *window, const Context *context); }; \ No newline at end of file diff --git a/aster/window.cpp b/aster/window.cpp index c307e4f..1b85d7b 100644 --- a/aster/window.cpp +++ b/aster/window.cpp @@ -8,65 +8,72 @@ #include "glfw_context.h" #include "logger.h" -Window::Window(const std::string_view &_title, Context *_context, vk::Extent2D _extent, b8 _full_screen) : - parent_context{ std::move(_context) }, extent{ _extent }, name{ _title }, full_screen{ _full_screen } { - monitor = glfwGetPrimaryMonitor(); - ERROR_IF(monitor == nullptr, "No monitor found"); - - i32 x_, y_, w_, h_; - glfwGetMonitorWorkarea(monitor, &x_, &y_, &w_, &h_); - - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); - glfwWindowHint(GLFW_CENTER_CURSOR, GLFW_TRUE); - - window = glfwCreateWindow(extent.width, extent.height, name.data(), full_screen ? monitor : nullptr, nullptr); - ERROR_IF(window == nullptr, "Window creation failed") - ELSE_INFO("Window '{}' created with resolution '{}x{}'", name, extent.width, extent.height); - if (window == nullptr) { - auto code = GlfwContext::post_error(); - glfwTerminate(); - CRASH(code); - } - - if (full_screen == false) { - glfwSetWindowPos(window, (w_ - extent.width) / 2, (h_ - extent.height) / 2); - } - glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); - - VkSurfaceKHR surface_; - auto result = cast(glfwCreateWindowSurface(cast(_context->instance), window, nullptr, &surface_)); - ERROR_IF(failed(result), "Failed to create Surface with {}", to_string(result)) - THEN_CRASH(result) ELSE_INFO("Surface Created"); - surface = vk::SurfaceKHR(surface_); +void +Window::SetWindowSize(const vk::Extent2D &extent) const noexcept +{ + SetWindowSize(extent.width, extent.height); } -Window::Window(Window &&_other) noexcept : - parent_context{ std::move(_other.parent_context) }, window{ std::exchange(_other.window, nullptr) }, monitor{ _other.monitor }, surface{ std::exchange(_other.surface, nullptr) }, extent{ _other.extent }, name{ std::move(_other.name) }, full_screen{ _other.full_screen } {} - -Window &Window::operator=(Window &&_other) noexcept { - if (this == &_other) - return *this; - parent_context = std::move(_other.parent_context); - window = _other.window; - monitor = _other.monitor; - surface = std::exchange(_other.surface, nullptr); - extent = _other.extent; - name = std::move(_other.name); - full_screen = _other.full_screen; - return *this; +void +Window::SetWindowSize(const u32 width, const u32 height) const noexcept +{ + glfwSetWindowSize(m_Window, cast(width), cast(height)); } -Window::~Window() { - if (parent_context && surface) { - parent_context->instance.destroy(surface); - INFO("Surface Destroyed"); - } +Window::Window(cstr title, Context *context, vk::Extent2D extent, b8 isFullScreen) +{ + m_Context = context; + m_Name = title; - if (window != nullptr) { - glfwDestroyWindow(window); - window = nullptr; - } - monitor = nullptr; + GLFWmonitor *monitor = glfwGetPrimaryMonitor(); + ERROR_IF(!monitor, "No monitor found"); - INFO("Window '{}' Destroyed", name); + i32 windowX, windowY, windowWidth, windowHeight; + glfwGetMonitorWorkarea(monitor, &windowX, &windowY, &windowWidth, &windowHeight); + + glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); + glfwWindowHint(GLFW_CENTER_CURSOR, GLFW_TRUE); + + m_Window = glfwCreateWindow(cast(extent.width), cast(extent.height), m_Name.c_str(), + isFullScreen ? monitor : nullptr, nullptr); + ERROR_IF(m_Window == nullptr, "Window creation failed") + ELSE_DEBUG("Window '{}' created with resolution '{}x{}'", m_Name.c_str(), extent.width, extent.height); + if (m_Window == nullptr) + { + auto code = GlfwContext::PostError(); + glfwTerminate(); + CRASH(code); + } + + if (isFullScreen == false) + { + glfwSetWindowPos(m_Window, cast(windowWidth - extent.width) / 2, + cast(windowHeight - extent.height) / 2); + } + glfwSetInputMode(m_Window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); + + VkSurfaceKHR surface; + auto result = + cast(glfwCreateWindowSurface(cast(m_Context->m_Instance), m_Window, nullptr, &surface)); + ERROR_IF(failed(result), "Failed to create Surface with {}", to_string(result)) + THEN_ABORT(result) + ELSE_DEBUG("Surface {} Created", m_Name.c_str()); + m_Surface = vk::SurfaceKHR(surface); +} + +Window::~Window() +{ + if (m_Context && m_Surface) + { + m_Context->m_Instance.destroy(m_Surface, nullptr); + DEBUG("Surface Destroyed"); + } + + if (m_Window != nullptr) + { + glfwDestroyWindow(m_Window); + m_Window = nullptr; + } + + DEBUG("Window '{}' Destroyed", m_Name.c_str()); } diff --git a/aster/window.h b/aster/window.h index 288a3d2..ed3d0bb 100644 --- a/aster/window.h +++ b/aster/window.h @@ -5,45 +5,31 @@ #pragma once -#include "global.h" - #include "context.h" +#include "global.h" +#include -struct Window final { - Window(const std::string_view &_title, Context *_context, vk::Extent2D _extent, b8 _full_screen = false); +struct Window final +{ + // fields + Context *m_Context{}; - Window(const Window &_other) = delete; - Window(Window &&_other) noexcept; - Window &operator=(const Window &_other) = delete; - Window &operator=(Window &&_other) noexcept; + GLFWwindow *m_Window = nullptr; + vk::SurfaceKHR m_Surface; + eastl::fixed_string m_Name; - ~Window(); + // Methods + [[nodiscard]] bool + Poll() const noexcept + { + glfwPollEvents(); + return !glfwWindowShouldClose(m_Window); + } - [[nodiscard]] bool should_close() const noexcept { - return glfwWindowShouldClose(window); - } + void SetWindowSize(const vk::Extent2D &extent) const noexcept; + void SetWindowSize(u32 width, u32 height) const noexcept; - bool poll() const noexcept { - glfwPollEvents(); - return !glfwWindowShouldClose(window); - } - - void set_window_size(const vk::Extent2D &_extent) noexcept { - extent = _extent; - glfwSetWindowSize(window, extent.width, extent.height); - } - - void set_window_size(const u32 _width, const u32 _height) noexcept { - set_window_size({ _width, _height }); - } - - // fields - Context *parent_context{}; - - GLFWwindow *window{ nullptr }; - GLFWmonitor *monitor{ nullptr }; - vk::SurfaceKHR surface; - vk::Extent2D extent; - std::string name; - b8 full_screen{ false }; + // Ctor/Dtor + Window(cstr title, Context *context, vk::Extent2D extent, b8 isFullScreen = false); + ~Window(); }; diff --git a/triangle/aster.cpp b/triangle/aster.cpp index 96b38fd..d390379 100644 --- a/triangle/aster.cpp +++ b/triangle/aster.cpp @@ -4,60 +4,81 @@ #include "aster/physical_device.h" #include "aster/window.h" -constexpr QueueSupportFlags required_queue_support = QueueSupportFlags{} | QueueSupportFlagBits::eGraphics | QueueSupportFlagBits::eCompute | QueueSupportFlagBits::ePresent | QueueSupportFlagBits::eTransfer; +#include "aster/global.h" -[[nodiscard]] bool is_suitable_device(const PhysicalDevice *_physical_device) { - const bool all_required_queues = std::ranges::any_of(_physical_device->queue_families, [](const auto &_qfp) { - return (_qfp.support & required_queue_support) == required_queue_support; - }); +constexpr QueueSupportFlags REQUIRED_QUEUE_SUPPORT = QueueSupportFlags{} | QueueSupportFlagBits::eGraphics | + QueueSupportFlagBits::eCompute | QueueSupportFlagBits::ePresent | + QueueSupportFlagBits::eTransfer; - const bool device_type_check = _physical_device->properties.deviceType != vk::PhysicalDeviceType::eCpu; +[[nodiscard]] bool +isSuitableDevice(const PhysicalDevice *physicalDevice) +{ + const bool hasAllRequiredQueues = + std::ranges::any_of(physicalDevice->m_QueueFamilies, [](const auto &queueFamilyProp) { + return (queueFamilyProp.m_Support & REQUIRED_QUEUE_SUPPORT) == REQUIRED_QUEUE_SUPPORT; + }); - const bool supported_present_mode = !_physical_device->present_modes.empty(); + const bool isNotCpu = physicalDevice->m_DeviceProperties.deviceType != vk::PhysicalDeviceType::eCpu; - const bool supported_format = !_physical_device->surface_formats.empty(); + const bool hasPresentMode = !physicalDevice->m_PresentModes.empty(); - return supported_format && supported_present_mode && device_type_check && all_required_queues; + const bool hasSurfaceFormat = !physicalDevice->m_SurfaceFormats.empty(); + + return hasSurfaceFormat && hasPresentMode && isNotCpu && hasAllRequiredQueues; } -PhysicalDevice find_suitable_device(const PhysicalDevices &_physical_devices) { - for (auto &_physical_device : _physical_devices) { - if (is_suitable_device(&_physical_device)) { - return _physical_device; - } - } - throw std::runtime_error("No suitable device found."); +PhysicalDevice +findSuitableDevice(const PhysicalDevices &physicalDevices) +{ + for (auto &physicalDevice : physicalDevices) + { + if (isSuitableDevice(&physicalDevice)) + { + return physicalDevice; + } + } + + ERROR("No suitable GPU available on the system.") + THEN_ABORT(vk::Result::eErrorUnknown); } -QueueAllocation find_appropriate_queue_allocation(const PhysicalDevice* _physical_device) { - for (auto &_queue_info: _physical_device->queue_families) { - if ((_queue_info.support & required_queue_support) == required_queue_support) { - return { - .family = _queue_info.index, - .count = _queue_info.count, - }; - } - } - throw std::runtime_error("No suitable queue family."); +QueueAllocation +findAppropriateQueueAllocation(const PhysicalDevice *physicalDevice) +{ + for (auto &queueFamilyInfo : physicalDevice->m_QueueFamilies) + { + if ((queueFamilyInfo.m_Support & REQUIRED_QUEUE_SUPPORT) == REQUIRED_QUEUE_SUPPORT) + { + return { + .m_Family = queueFamilyInfo.m_Index, + .m_Count = queueFamilyInfo.m_Count, + }; + } + } + ERROR("No suitable queue family on the GPU.") + THEN_ABORT(vk::Result::eErrorUnknown); } -int main(int, char **) { - GlfwContext glfw_context = {}; - Context context = {"Aster", VERSION}; - Window window = {"Aster1", &context, { 640, 480 }}; +int +main(int, char **) +{ + GlfwContext glfwContext = {}; + Context context = {"Aster", VERSION}; + Window window = {"Aster1", &context, {640, 480}}; - PhysicalDevices physical_devices = { &window, &context }; - PhysicalDevice device_to_use = find_suitable_device(physical_devices); + PhysicalDevices physicalDevices = {&window, &context}; + PhysicalDevice deviceToUse = findSuitableDevice(physicalDevices); - INFO("Using {} as the primary device.", device_to_use.properties.deviceName.data()); + INFO("Using {} as the primary device.", deviceToUse.m_DeviceProperties.deviceName.data()); - vk::PhysicalDeviceFeatures features = {}; - QueueAllocation queue_allocation = find_appropriate_queue_allocation(&device_to_use); + vk::PhysicalDeviceFeatures features = {}; + QueueAllocation queueAllocation = findAppropriateQueueAllocation(&deviceToUse); - Device device = { &context, std::move(device_to_use), &features, {queue_allocation}, "Primary Device" }; + Device device = {&context, std::move(deviceToUse), &features, {queueAllocation}, "Primary Device"}; - while (window.poll()) { - } + while (window.Poll()) + { + } - return 0; + return 0; } diff --git a/vcpkg.json b/vcpkg.json index a4e31a8..c0ed20c 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -1,9 +1,10 @@ { "dependencies": [ + "fmt", "glfw3", "glm", "scottt-debugbreak", "vulkan-memory-allocator", - "fmt" + "eastl" ] }