Refactored for new coding scheme. No exceptions.

This commit is contained in:
Anish Bhobe 2024-06-26 17:41:59 +02:00
parent 7bf87f5127
commit f603bd5752
21 changed files with 933 additions and 938 deletions

View File

@ -3,86 +3,14 @@
# chosen value in case the base style changes (last sync: Clang 14.0). # chosen value in case the base style changes (last sync: Clang 14.0).
--- ---
### General config, applies to all languages ### ### General config, applies to all languages ###
BasedOnStyle: LLVM BasedOnStyle: Microsoft
AccessModifierOffset: -4 #AccessModifierOffset: -2
AlignAfterOpenBracket: DontAlign AlwaysBreakAfterReturnType: AllDefinitions
# AlignArrayOfStructures: None BreakConstructorInitializers: BeforeComma
# AlignConsecutiveMacros: None #ColumnLimit: 0
# AlignConsecutiveAssignments: None #ConstructorInitializerIndentWidth: 4
# AlignConsecutiveBitFields: None #ConstructorInitializerAllOnOneLineOrOnePerLine: true
# AlignConsecutiveDeclarations: None AlwaysBreakTemplateDeclarations: Yes
# 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
IncludeCategories: IncludeCategories:
- Regex: '".*"' - Regex: '".*"'
Priority: 1 Priority: 1
@ -90,110 +18,10 @@ IncludeCategories:
Priority: 2 Priority: 2
- Regex: '^<.*' - Regex: '^<.*'
Priority: 3 Priority: 3
# IncludeIsMainRegex: '(Test)?$' #IndentCaseLabels: true
# IncludeIsMainSourceRegex: ''
# IndentAccessModifiers: false
IndentCaseLabels: true
# IndentCaseBlocks: false
# IndentGotoLabels: true
# IndentPPDirectives: None
# IndentExternBlock: AfterExternBlock
# IndentRequires: false
IndentWidth: 4 IndentWidth: 4
# IndentWrappedFunctionNames: false #KeepEmptyLinesAtTheStartOfBlocks: false
# InsertTrailingCommas: None PenaltyReturnTypeOnItsOwnLine: 0
# 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 TabWidth: 4
# UseCRLF: false
UseTab: Always
# WhitespaceSensitiveMacros:
# - STRINGIZE
# - PP_STRINGIZE
# - BOOST_PP_STRINGIZE
# - NS_SWIFT_NAME
# - CF_SWIFT_NAME
---
### C++ specific config ###
Language: Cpp Language: Cpp
Standard: c++17 Standard: c++20
---
### 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']
...

View File

@ -29,9 +29,9 @@ CheckOptions:
- key: modernize-loop-convert.NamingStyle - key: modernize-loop-convert.NamingStyle
value: CamelCase value: CamelCase
- key: modernize-pass-by-value.IncludeStyle - key: modernize-pass-by-value.IncludeStyle
value: llvm value: microsoft
- key: modernize-replace-auto-ptr.IncludeStyle - key: modernize-replace-auto-ptr.IncludeStyle
value: llvm value: microsoft
- key: modernize-use-bool-literals.IgnoreMacros - key: modernize-use-bool-literals.IgnoreMacros
value: '0' value: '0'
- key: modernize-use-default-member-init.IgnoreMacros - key: modernize-use-default-member-init.IgnoreMacros

View File

@ -8,7 +8,7 @@ set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF) set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_CXX_FLAGS -Wall) set(CMAKE_CXX_FLAGS "-Wall -fno-rtti -fno-exceptions")
add_subdirectory("aster") add_subdirectory("aster")
add_subdirectory("triangle") add_subdirectory("triangle")

View File

@ -6,9 +6,9 @@ find_package(glm CONFIG REQUIRED)
find_package(glfw3 CONFIG REQUIRED) find_package(glfw3 CONFIG REQUIRED)
find_path(SCOTTT_DEBUGBREAK_INCLUDE_DIRS "debugbreak.h") find_path(SCOTTT_DEBUGBREAK_INCLUDE_DIRS "debugbreak.h")
find_package(Vulkan REQUIRED) find_package(Vulkan REQUIRED)
# find_package( VulkanHeaders CONFIG REQUIRED )
find_package(fmt CONFIG REQUIRED) find_package(fmt CONFIG REQUIRED)
find_package(VulkanMemoryAllocator CONFIG REQUIRED) find_package(VulkanMemoryAllocator CONFIG REQUIRED)
find_package(EASTL CONFIG REQUIRED)
set(HEADER_FILES set(HEADER_FILES
constants.h constants.h
@ -37,5 +37,6 @@ target_link_libraries(aster_core PUBLIC glm::glm-header-only)
target_link_libraries(aster_core PRIVATE glfw) target_link_libraries(aster_core PRIVATE glfw)
target_include_directories(aster_core PRIVATE ${SCOTTT_DEBUGBREAK_INCLUDE_DIRS}) target_include_directories(aster_core PRIVATE ${SCOTTT_DEBUGBREAK_INCLUDE_DIRS})
target_link_libraries(aster_core PRIVATE fmt::fmt) 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)

View File

@ -11,10 +11,15 @@
#define GLFW_INCLUDE_VULKAN #define GLFW_INCLUDE_VULKAN
#define VULKAN_HPP_DISPATCH_LOADER_DYNAMIC 1 #define VULKAN_HPP_DISPATCH_LOADER_DYNAMIC 1
#define VULKAN_HPP_NO_STRUCT_CONSTRUCTORS #define VULKAN_HPP_NO_STRUCT_CONSTRUCTORS
#define VULKAN_HPP_DISABLE_ENHANCED_MODE 1
#define VMA_STATIC_VULKAN_FUNCTIONS 0 #define VMA_STATIC_VULKAN_FUNCTIONS 0
#define VMA_DYNAMIC_VULKAN_FUNCTIONS 1 #define VMA_DYNAMIC_VULKAN_FUNCTIONS 1
#define EASTL_NO_EXCEPTIONS 1
// ReSharper disable once CppInconsistentNaming
#define _HAS_EXCEPTIONS 0
#if defined(NDEBUG) #if defined(NDEBUG)
#define USE_OPTICK (0) #define USE_OPTICK (0)
#else #else

View File

@ -5,10 +5,10 @@
#pragma once #pragma once
#include <vulkan/vulkan_core.h>
#include <cstdint> #include <cstdint>
#include <cstdio> #include <cstdio>
#include <optional>
#include <tuple>
#include <glm/glm.hpp> #include <glm/glm.hpp>
@ -28,53 +28,69 @@ using b8 = bool;
using b32 = u32; using b32 = u32;
using usize = size_t; using usize = size_t;
using p64 = intptr_t; using p64 = intptr_t;
using cstr = const char *;
constexpr usize strlen_c(const char *s) { constexpr usize
strlenC(const char *s)
{
usize len = 0; usize len = 0;
char c = '\0'; char c = '\0';
do { do
{
c = s[len]; c = s[len];
len++; len++;
} while (c != '\0'); } while (c != '\0');
return len; return len;
} }
constexpr auto ANSI_Black = "\u001b[30m"; namespace ansi_color
constexpr auto ANSI_Red = "\u001b[31m"; {
constexpr auto ANSI_Green = "\u001b[32m"; constexpr auto Black = "\u001b[30m";
constexpr auto ANSI_Yellow = "\u001b[33m"; constexpr auto Red = "\u001b[31m";
constexpr auto ANSI_Blue = "\u001b[34m"; constexpr auto Green = "\u001b[32m";
constexpr auto ANSI_Magenta = "\u001b[35m"; constexpr auto Yellow = "\u001b[33m";
constexpr auto ANSI_Cyan = "\u001b[36m"; constexpr auto Blue = "\u001b[34m";
constexpr auto ANSI_White = "\u001b[37m"; constexpr auto Magenta = "\u001b[35m";
constexpr auto ANSI_Reset = "\u001b[0m"; constexpr auto Cyan = "\u001b[36m";
constexpr auto White = "\u001b[37m";
constexpr auto Reset = "\u001b[0m";
} // namespace ansi_color
template <typename T> template <typename TypeT, typename FromT>
using Option = std::optional<T>; constexpr auto
cast(FromT &&in)
template <typename type_t, typename from_t> {
constexpr auto cast(from_t &&_in) { return static_cast<TypeT>(std::forward<FromT>(in));
return static_cast<type_t>(std::forward<from_t>(_in));
} }
template <typename type_t, typename from_t> template <typename TypeT, typename FromT>
constexpr auto recast(from_t &&_in) { constexpr auto
return reinterpret_cast<type_t>(std::forward<from_t>(_in)); recast(FromT &&in)
{
return reinterpret_cast<TypeT>(std::forward<FromT>(in));
} }
constexpr f32 operator""_deg(long double degrees) { constexpr f32
operator""_deg(long double degrees)
{
return glm::radians<f32>(cast<f32>(degrees)); return glm::radians<f32>(cast<f32>(degrees));
} }
constexpr f32 operator""_deg(unsigned long long int degrees) { constexpr f32
operator""_deg(unsigned long long int degrees)
{
return glm::radians<f32>(cast<f32>(degrees)); return glm::radians<f32>(cast<f32>(degrees));
} }
constexpr f32 operator""_rad(long double rads) { constexpr f32
operator""_rad(long double rads)
{
return cast<f32>(rads); return cast<f32>(rads);
} }
constexpr f32 operator""_rad(unsigned long long int rads) { constexpr f32
operator""_rad(unsigned long long int rads)
{
return cast<f32>(rads); return cast<f32>(rads);
} }
@ -91,38 +107,45 @@ using glm::mat4;
constexpr auto *PROJECT_NAME = "Aster"; constexpr auto *PROJECT_NAME = "Aster";
struct Version { struct Version
u32 major; {
u32 minor; u8 m_Major;
u32 patch; 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 = { constexpr Version VERSION = {
.major = 0, .m_Major = 0,
.minor = 1, .m_Minor = 1,
.patch = 0, .m_Patch = 0,
}; };
template <typename T> template <typename T>
constexpr T max_value = std::numeric_limits<T>::max(); constexpr T MaxValue = std::numeric_limits<T>::max();
template <typename T> template <typename T>
constexpr T min_value = std::numeric_limits<T>::min(); constexpr T MinValue = std::numeric_limits<T>::min();
template <typename T> template <typename T>
constexpr T lowest_value = std::numeric_limits<T>::lowest(); constexpr T LowestValue = std::numeric_limits<T>::lowest();
template <typename T> template <typename T>
constexpr T err_epsilon = std::numeric_limits<T>::epsilon(); constexpr T ErrEpsilon = std::numeric_limits<T>::epsilon();
template <typename T> template <typename T>
constexpr T positive_inf = std::numeric_limits<T>::infinity(); constexpr T PositiveInf = std::numeric_limits<T>::infinity();
template <typename T> template <typename T>
constexpr T negative_inf = -std::numeric_limits<T>::infinity(); constexpr T NegativeInf = -std::numeric_limits<T>::infinity();
template <typename T> template <typename T>
constexpr T qnan = std::numeric_limits<T>::quiet_NaN(); constexpr T Qnan = std::numeric_limits<T>::quiet_NaN();
template <typename T> template <typename T>
constexpr T snan = std::numeric_limits<T>::signalling_NaN(); constexpr T Snan = std::numeric_limits<T>::signalling_NaN();

View File

@ -4,58 +4,69 @@
// ============================================= // =============================================
#include "context.h" #include "context.h"
#include <EASTL/array.h>
#include <EASTL/fixed_vector.h>
VKAPI_ATTR b32 VKAPI_CALL Context::debug_callback(VkDebugUtilsMessageSeverityFlagBitsEXT _message_severity, VkDebugUtilsMessageTypeFlagsEXT _message_type, const VkDebugUtilsMessengerCallbackDataEXT *_callback_data, [[maybe_unused]] void *_user_data) { constexpr eastl::array VALIDATION_LAYERS = {
"VK_LAYER_KHRONOS_validation",
};
VKAPI_ATTR b32 VKAPI_CALL
debugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageType,
const VkDebugUtilsMessengerCallbackDataEXT *callbackData, [[maybe_unused]] void *userData)
{
using Severity = vk::DebugUtilsMessageSeverityFlagsEXT; using Severity = vk::DebugUtilsMessageSeverityFlagsEXT;
using SeverityBits = vk::DebugUtilsMessageSeverityFlagBitsEXT; using SeverityBits = vk::DebugUtilsMessageSeverityFlagBitsEXT;
using MessageType = vk::DebugUtilsMessageTypeFlagsEXT; using MessageType = vk::DebugUtilsMessageTypeFlagsEXT;
using MessageTypeBits = vk::DebugUtilsMessageTypeFlagBitsEXT; using MessageTypeBits = vk::DebugUtilsMessageTypeFlagBitsEXT;
const auto severity = Severity(_message_severity); const auto severity = Severity(messageSeverity);
const auto message_type = MessageType(_message_type);
if (message_type & MessageTypeBits::eValidation) { if (MessageType(messageType) & MessageTypeBits::eValidation)
{
if (severity & SeverityBits::eError) if (severity & SeverityBits::eError)
ERROR("{}", _callback_data->pMessage); ERROR("{}", callbackData->pMessage);
if (severity & SeverityBits::eWarning) if (severity & SeverityBits::eWarning)
WARN("{}", _callback_data->pMessage); WARN("{}", callbackData->pMessage);
if (severity & SeverityBits::eInfo) if (severity & SeverityBits::eInfo)
INFO("{}", _callback_data->pMessage); INFO("{}", callbackData->pMessage);
if (severity & SeverityBits::eVerbose) if (severity & SeverityBits::eVerbose)
VERBOSE("{}", _callback_data->pMessage); VERBOSE("{}", callbackData->pMessage);
} }
return false; return false;
} }
void Context::init(const std::string_view &_app_name, const Version &_app_version) { Context::Context(cstr appName, Version version, bool enableValidation)
INFO_IF(enable_validation_layers, "Validation Layers enabled"); {
INFO_IF(enableValidation, "Validation Layers enabled");
// Creating Instance // Creating Instance
const vk::ApplicationInfo app_info = { const vk::ApplicationInfo appInfo = {
.pApplicationName = _app_name.data(), .pApplicationName = appName,
.applicationVersion = VK_MAKE_VERSION(_app_version.major, _app_version.minor, _app_version.patch), .applicationVersion = version.GetVkVersion(),
.pEngineName = PROJECT_NAME, .pEngineName = PROJECT_NAME,
.engineVersion = VK_MAKE_VERSION(VERSION.major, VERSION.minor, VERSION.patch), .engineVersion = version.GetVkVersion(),
.apiVersion = ASTER_API_VERSION, .apiVersion = ASTER_API_VERSION,
}; };
vk::DebugUtilsMessengerCreateInfoEXT debug_messenger_create_info = { vk::DebugUtilsMessengerCreateInfoEXT debugUtilsMessengerCreateInfo = {
.messageSeverity = vk::DebugUtilsMessageSeverityFlagBitsEXT::eError | .messageSeverity = vk::DebugUtilsMessageSeverityFlagBitsEXT::eError |
vk::DebugUtilsMessageSeverityFlagBitsEXT::eWarning | vk::DebugUtilsMessageSeverityFlagBitsEXT::eWarning |
vk::DebugUtilsMessageSeverityFlagBitsEXT::eInfo, vk::DebugUtilsMessageSeverityFlagBitsEXT::eInfo,
.messageType = vk::DebugUtilsMessageTypeFlagBitsEXT::eGeneral | .messageType = vk::DebugUtilsMessageTypeFlagBitsEXT::eGeneral |
vk::DebugUtilsMessageTypeFlagBitsEXT::ePerformance | vk::DebugUtilsMessageTypeFlagBitsEXT::ePerformance |
vk::DebugUtilsMessageTypeFlagBitsEXT::eValidation, vk::DebugUtilsMessageTypeFlagBitsEXT::eValidation,
.pfnUserCallback = debug_callback, .pfnUserCallback = debugCallback,
.pUserData = nullptr, .pUserData = nullptr,
}; };
u32 glfw_extension_count = 0; u32 glfwExtensionCount = 0;
const char **glfw_extensions = glfwGetRequiredInstanceExtensions(&glfw_extension_count); cstr *glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);
std::vector vulkan_extensions(glfw_extensions, glfw_extensions + glfw_extension_count); eastl::fixed_vector<cstr, 3> instanceExtensions(glfwExtensions, glfwExtensions + glfwExtensionCount);
if (enable_validation_layers) { if (enableValidation)
vulkan_extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); {
instanceExtensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
} }
const vk::DynamicLoader dl; const vk::DynamicLoader dl;
@ -63,38 +74,38 @@ void Context::init(const std::string_view &_app_name, const Version &_app_versio
const auto vkGetInstanceProcAddr = dl.getProcAddress<PFN_vkGetInstanceProcAddr>("vkGetInstanceProcAddr"); const auto vkGetInstanceProcAddr = dl.getProcAddress<PFN_vkGetInstanceProcAddr>("vkGetInstanceProcAddr");
VULKAN_HPP_DEFAULT_DISPATCHER.init(vkGetInstanceProcAddr); VULKAN_HPP_DEFAULT_DISPATCHER.init(vkGetInstanceProcAddr);
const auto instance_create_info = vk::InstanceCreateInfo{ const auto instanceCreateInfo = vk::InstanceCreateInfo{
.pNext = enable_validation_layers ? &debug_messenger_create_info : nullptr, .pNext = enableValidation ? &debugUtilsMessengerCreateInfo : nullptr,
.pApplicationInfo = &app_info, .pApplicationInfo = &appInfo,
.enabledLayerCount = enable_validation_layers ? cast<u32>(validation_layers.size()) : 0, .enabledLayerCount = enableValidation ? cast<u32>(VALIDATION_LAYERS.size()) : 0,
.ppEnabledLayerNames = enable_validation_layers ? validation_layers.data() : nullptr, .ppEnabledLayerNames = enableValidation ? VALIDATION_LAYERS.data() : nullptr,
.enabledExtensionCount = cast<u32>(vulkan_extensions.size()), .enabledExtensionCount = cast<u32>(instanceExtensions.size()),
.ppEnabledExtensionNames = vulkan_extensions.data(), .ppEnabledExtensionNames = instanceExtensions.data(),
}; };
// May throw. Irrecoverable. // May throw. Irrecoverable.
instance = vk::createInstance(instance_create_info); vk::Result result = vk::createInstance(&instanceCreateInfo, nullptr, &m_Instance);
INFO("Instance Created."); ERROR_IF(result, "Instance creation failed. Cause: {}", to_string(result))
VULKAN_HPP_DEFAULT_DISPATCHER.init(instance); THEN_ABORT(result)
ELSE_DEBUG("Instance Created.");
VULKAN_HPP_DEFAULT_DISPATCHER.init(m_Instance);
// Debug Messenger // Debug Messenger
if (enable_validation_layers) { if (enableValidation)
try { {
debug_messenger = instance.createDebugUtilsMessengerEXT(debug_messenger_create_info); result = m_Instance.createDebugUtilsMessengerEXT(&debugUtilsMessengerCreateInfo, nullptr, &m_DebugMessenger);
} catch (const std::exception &_err) { ERROR_IF(result, "Debug Messenger creation failed. Cause: {}", to_string(result)) // Non-critical. Continue.
ERROR("Debug Messenger creation failed. Cause: {}", _err.what()); ELSE_DEBUG("Debug Messenger Created.");
// Non-critical. Continue.
}
INFO("Debug Messenger Created.");
} }
} }
Context::~Context() { Context::~Context()
if (instance) { {
if (enable_validation_layers && debug_messenger) { if (m_DebugMessenger)
instance.destroyDebugUtilsMessengerEXT(debug_messenger); {
} m_Instance.destroy(m_DebugMessenger, nullptr);
instance.destroy(); DEBUG("Debug Messenger destroyed");
INFO("Context destroyed");
} }
m_Instance.destroy(nullptr);
DEBUG("Instance destroyed");
} }

View File

@ -6,8 +6,6 @@
#pragma once #pragma once
#include "global.h" #include "global.h"
#include <utility>
#include <vector>
/** /**
* @class Context * @class Context
@ -16,71 +14,13 @@
* *
* Handles the required hardware interactions. * Handles the required hardware interactions.
*/ */
class Context final { struct Context final
public: {
Context(const std::string_view &_app_name, const Version &_app_version, const b8 _enable_validation = true) : // Members
enable_validation_layers{ _enable_validation } { vk::Instance m_Instance = nullptr;
init(_app_name, _app_version); vk::DebugUtilsMessengerEXT m_DebugMessenger = nullptr;
}
Context(const std::string_view &_app_name, const Version &_app_version, const std::vector<const char *> &_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<const char *> &_additional_device_extensions, const std::vector<const char *> &_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;
}
// Ctor/Dtor
Context(cstr appName, Version version, bool enableValidation = true);
~Context(); ~Context();
// Fields
bool enable_validation_layers{ true };
std::vector<const char *> validation_layers = {
"VK_LAYER_KHRONOS_validation",
};
std::vector<const char *> 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);
}; };

View File

@ -5,76 +5,80 @@
#include "device.h" #include "device.h"
Device::Device(const Context *_context, PhysicalDevice &&_physical_device, const vk::PhysicalDeviceFeatures *_enabled_features, const std::vector<QueueAllocation> &_queue_allocation, std::optional<std::string> _name) : #include <EASTL/array.h>
physical_device{ std::move(_physical_device) },
name{ std::move(_name) } {
std::vector<vk::DeviceQueueCreateInfo> queue_create_infos;
queue_create_infos.reserve(_queue_allocation.size());
u32 num_priorities = 0; constexpr eastl::array DEVICE_EXTENSIONS = {VK_KHR_SWAPCHAIN_EXTENSION_NAME};
for (auto [_, count] : _queue_allocation) {
num_priorities = std::max(count, num_priorities); Device::Device(const Context *context, PhysicalDevice *physicalDevice,
const vk::PhysicalDeviceFeatures *enabledFeatures,
const eastl::vector<QueueAllocation> &queueAllocations, NameString name)
: m_Name(std::move(name))
{
// Shouldn't have more than 4 deviceQueueFamilies in use anyway. Else we can heap
eastl::fixed_vector<vk::DeviceQueueCreateInfo, 4> deviceQueueCreateInfos;
deviceQueueCreateInfos.reserve(queueAllocations.size());
u32 numPriorities = 0;
for (auto [_, count] : queueAllocations)
{
numPriorities = std::max(count, numPriorities);
} }
std::vector priorities(num_priorities, 1.0f); // Shouldn't have more than 4 queues either.
eastl::fixed_vector<f32, 4> priorities(numPriorities, 1.0f);
for (auto [family, count] : _queue_allocation) { for (auto [family, count] : queueAllocations)
queue_create_infos.push_back({ {
deviceQueueCreateInfos.push_back({
.queueFamilyIndex = family, .queueFamilyIndex = family,
.queueCount = count, .queueCount = count,
.pQueuePriorities = priorities.data(), .pQueuePriorities = priorities.data(),
}); });
} }
try { vk::DeviceCreateInfo deviceCreateInfo = {
device = physical_device.device.createDevice({ .queueCreateInfoCount = cast<u32>(deviceQueueCreateInfos.size()),
.queueCreateInfoCount = cast<u32>(queue_create_infos.size()), .pQueueCreateInfos = deviceQueueCreateInfos.data(),
.pQueueCreateInfos = queue_create_infos.data(), .enabledExtensionCount = cast<u32>(DEVICE_EXTENSIONS.size()),
.enabledLayerCount = _context->enable_validation_layers ? cast<u32>(_context->validation_layers.size()) : 0, .ppEnabledExtensionNames = DEVICE_EXTENSIONS.data(),
.ppEnabledLayerNames = _context->enable_validation_layers ? _context->validation_layers.data() : nullptr, .pEnabledFeatures = enabledFeatures,
.enabledExtensionCount = cast<u32>(_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;
}
INFO("{} ({}) Initialized!", name.value_or(DEFAULT_DEVICE_NAME), physical_device.properties.deviceName.data()); vk::Result result = 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, physicalDevice->m_DeviceProperties.deviceName.data());
VmaVulkanFunctions vma_vulkan_functions = { VmaVulkanFunctions vmaVulkanFunctions = {
.vkGetInstanceProcAddr = vk::defaultDispatchLoaderDynamic.vkGetInstanceProcAddr, .vkGetInstanceProcAddr = vk::defaultDispatchLoaderDynamic.vkGetInstanceProcAddr,
.vkGetDeviceProcAddr = vk::defaultDispatchLoaderDynamic.vkGetDeviceProcAddr, .vkGetDeviceProcAddr = vk::defaultDispatchLoaderDynamic.vkGetDeviceProcAddr,
}; };
const VmaAllocatorCreateInfo vma_allocator_create_info = { const VmaAllocatorCreateInfo allocatorCreateInfo = {
.flags = 0, .flags = 0,
.physicalDevice = physical_device.device, .physicalDevice = physicalDevice->m_PhysicalDevice,
.device = device, .device = m_Device,
.pVulkanFunctions = &vma_vulkan_functions, .pVulkanFunctions = &vmaVulkanFunctions,
.instance = _context->instance, .instance = context->m_Instance,
.vulkanApiVersion = ASTER_API_VERSION, .vulkanApiVersion = ASTER_API_VERSION,
}; };
const auto result = cast<vk::Result>(vmaCreateAllocator(&vma_allocator_create_info, &allocator)); result = cast<vk::Result>(vmaCreateAllocator(&allocatorCreateInfo, &m_Allocator));
if (failed(result)) { ERROR_IF(failed(result), "Memory allocator creation failed. Cause: {}", to_string(result))
device.destroy(); DO(m_Device.destroy(nullptr))
auto _err = fmt::format("Memory allocator creation failed. Cause: {}", to_string(result)); THEN_ABORT(result)
ERROR("{}", _err); ELSE_VERBOSE("Memory Allocator Created");
throw std::runtime_error(_err);
}
VERBOSE("Memory Allocator Created");
INFO("Created '{}' Successfully", name.value_or(DEFAULT_DEVICE_NAME)); DEBUG("Created '{}' Successfully", m_Name);
} }
Device::~Device() { Device::~Device()
if (allocator) { {
vmaDestroyAllocator(allocator); if (m_Allocator)
allocator = nullptr; {
VERBOSE("Memory Allocator Destroyed"); vmaDestroyAllocator(m_Allocator);
m_Allocator = nullptr;
DEBUG("Memory Allocator Destroyed");
} }
device.destroy(); m_Device.destroy(nullptr);
INFO("Device '{}' Destroyed", name.value_or(DEFAULT_DEVICE_NAME)); DEBUG("Device '{}' Destroyed", m_Name);
name = std::nullopt;
} }

View File

@ -8,20 +8,22 @@
#include "global.h" #include "global.h"
#include "physical_device.h" #include "physical_device.h"
constexpr std::string DEFAULT_DEVICE_NAME = "<Unnamed GPU>"; struct QueueAllocation
{
struct QueueAllocation { u32 m_Family;
u32 family; u32 m_Count;
u32 count;
}; };
struct Device final { struct Device final
vk::Device device; {
PhysicalDevice physical_device; using NameString = eastl::fixed_string<char, 32, false>;
VmaAllocator allocator{ nullptr };
std::optional<std::string> name{ nullptr };
Device(const Context *_context, PhysicalDevice &&_physical_device, const vk::PhysicalDeviceFeatures *_enabled_features, const std::vector<QueueAllocation> &_queue_allocation, std::optional<std::string> _name = std::nullopt); NameString m_Name;
vk::Device m_Device = nullptr;
VmaAllocator m_Allocator = nullptr;
Device(const Context *context, PhysicalDevice *physicalDevice, const vk::PhysicalDeviceFeatures *enabledFeatures,
const eastl::vector<QueueAllocation> &queueAllocations, NameString name);
~Device(); ~Device();
}; };

View File

@ -7,28 +7,36 @@
#include "global.h" #include "global.h"
struct GlfwContext { struct GlfwContext
static i32 post_error() noexcept { {
static const char *error_ = nullptr;
const auto code = glfwGetError(&error_); static i32
ERROR("GLFW {}", error_); PostError() noexcept
{
static const char *error = nullptr;
const auto code = glfwGetError(&error);
ERROR("GLFW {}", error);
return code; return code;
} }
inline static u32 count = 0; inline static u32 m_Count = 0;
GlfwContext() { GlfwContext()
if (count++ > 0) {
if (m_Count++ > 0)
return; return;
if (glfwInit() == GLFW_FALSE) { if (glfwInit() == GLFW_FALSE)
CRASH(post_error()); {
ABORT(PostError());
} }
} }
~GlfwContext() { ~GlfwContext()
if (--count == 0) { {
if (--m_Count == 0)
{
glfwTerminate(); glfwTerminate();
} }
count = 0; m_Count = 0;
} }
}; };

View File

@ -13,3 +13,16 @@
// NOTE: Vulkan Dispatch Loader Storage - Should only appear once. // NOTE: Vulkan Dispatch Loader Storage - Should only appear once.
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE 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];
}

View File

@ -11,30 +11,52 @@
#include <GLFW/glfw3.h> #include <GLFW/glfw3.h>
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <string> #include <fmt/format.h>
// 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") #define VULKAN_HPP_ASSERT(expr) DEBUG_IF(!(expr), "Vulkan assert failed")
#include <EASTL/fixed_string.h>
#include <EASTL/string.h>
#include <vk_mem_alloc.h> #include <vk_mem_alloc.h>
#include <vulkan/vulkan.hpp> #include <vulkan/vulkan.hpp>
constexpr u32 ASTER_API_VERSION = vk::ApiVersion13; constexpr u32 ASTER_API_VERSION = vk::ApiVersion13;
#define CODE_LOC " @ " __FILE__ ":" VULKAN_HPP_STRINGIFY(__LINE__) #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 <typename T> template <typename T>
concept IsVkEnum = requires(T _t) { concept IsVkEnum = requires(T t) {
{ std::is_enum_v<T> }; {
{ vk::to_string(_t) } -> std::same_as<std::string>; std::is_enum_v<T>
};
{
vk::to_string(t)
} -> std::same_as<std::string>;
}; };
template <typename T> template <typename T>
requires IsVkEnum<T> [[nodiscard]] const char *to_cstr(const T &_val) { requires IsVkEnum<T>
[[nodiscard]] const char *
toCstr(const T &val)
{
static std::string buffer; static std::string buffer;
buffer = vk::to_string(_val); buffer = vk::to_string(val);
return buffer.c_str(); return buffer.c_str();
} }
@ -43,49 +65,87 @@ using namespace std::literals::string_literals;
using namespace std::literals::string_view_literals; using namespace std::literals::string_view_literals;
template <typename T> template <typename T>
requires vk::isVulkanHandleType<T>::value [[nodiscard]] constexpr u64 requires vk::isVulkanHandleType<T>::value
get_vk_handle(const T &_vk_handle) noexcept { [[nodiscard]] constexpr u64
return reinterpret_cast<u64>(cast<T::CType>(_vk_handle)); getVkHandle(const T &vkHandle) noexcept
{
return reinterpret_cast<u64>(cast<T::CType>(vkHandle));
} }
template <typename F> template <typename F>
struct std::hash<vk::Flags<F>> { struct std::hash<vk::Flags<F>>
[[nodiscard]] usize operator()(const vk::Flags<F> &_val) { {
return std::hash<u32>()(cast<u32>(_val)); [[nodiscard]] usize
operator()(const vk::Flags<F> &val)
{
return std::hash<u32>()(cast<u32>(val));
} }
}; };
template <typename T> template <typename T>
[[nodiscard]] usize hash_any(const T &_val) { [[nodiscard]] usize
return std::hash<std::remove_cvref_t<T>>()(_val); hashAny(const T &val)
{
return std::hash<std::remove_cvref_t<T>>()(val);
} }
[[nodiscard]] inline usize hash_combine(const usize _hash0, [[nodiscard]] inline usize
const usize _hash1) { hashCombine(const usize hash0, const usize hash1)
constexpr usize salt_value = 0x9e3779b9; {
return _hash0 ^ (_hash1 + salt_value + (_hash0 << 6) + (_hash0 >> 2)); constexpr usize saltValue = 0x9e3779b9;
return hash0 ^ (hash1 + saltValue + (hash0 << 6) + (hash0 >> 2));
} }
struct Time { struct Time
static constexpr f64 max_delta = 0.1; {
static constexpr f64 c_MaxDelta = 0.1;
inline static f64 elapsed{ qnan<f64> }; inline static f64 m_Elapsed{Qnan<f64>};
inline static f64 delta{ qnan<f64> }; inline static f64 m_Delta{Qnan<f64>};
static void init() { static void
WARN_IF(!std::isnan(elapsed), "Time already init."); Init()
elapsed = glfwGetTime(); {
delta = 1.0 / 60.0; WARN_IF(!std::isnan(m_Elapsed), "Time already init.");
m_Elapsed = glfwGetTime();
m_Delta = 1.0 / 60.0;
} }
static void update() { static void
ERROR_IF(std::isnan(elapsed), "Time not init."); Update()
const auto new_elapsed = glfwGetTime(); {
delta = std::clamp(new_elapsed - elapsed, 0.0, max_delta); ERROR_IF(std::isnan(m_Elapsed), "Time not init.");
elapsed = new_elapsed; 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) { [[nodiscard]] inline usize
return _of * ((_val + _of - 1) / _of); closestMultiple(const usize val, const usize of)
{
return of * ((val + of - 1) / of);
} }
template <>
struct fmt::formatter<vk::Result> : nested_formatter<std::string>
{
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 <typename T, usize N, bool B>
struct fmt::formatter<eastl::fixed_string<T, N, B>> : nested_formatter<cstr>
{
auto
// ReSharper disable once CppInconsistentNaming
format(const eastl::fixed_string<T, N, B> &str, format_context &ctx) const
{
return write_padded(ctx, [this, str](auto out) { return v10::format_to(out, "{}", nested(str.c_str())); });
}
};

View File

@ -5,13 +5,16 @@
#include "logger.h" #include "logger.h"
Logger g_logger = Logger(); Logger g_Logger = Logger();
// ReSharper disable once CppInconsistentNaming
/* Credits to Const-me */ /* Credits to Const-me */
//namespace eastl { namespace eastl
// void __cdecl AssertionFailure(const char* af) {
// { void
// ERROR(af); AssertionFailure(const char *af)
// __debugbreak(); {
// } ERROR("{}", af);
//} debug_break();
}
} // namespace eastl

View File

@ -9,10 +9,10 @@
#include <debugbreak.h> #include <debugbreak.h>
#include <fmt/core.h> #include <fmt/core.h>
#include <string> struct Logger
{
struct Logger { enum class LogType : u32
enum class LogType : u32 { {
eError, eError,
eWarning, eWarning,
eInfo, eInfo,
@ -20,14 +20,18 @@ struct Logger {
eVerbose, eVerbose,
}; };
u32 minimum_logging_level{ cast<u32>(LogType::eDebug) }; u32 m_MinimumLoggingLevel{cast<u32>(LogType::eDebug)};
void set_minimum_logging_level(LogType _log_type) { void
minimum_logging_level = cast<u32>(_log_type); SetMinimumLoggingLevel(LogType logType)
{
m_MinimumLoggingLevel = cast<u32>(logType);
} }
template <LogType LogLevel> template <LogType LogLevel>
constexpr static const char *to_cstr() { constexpr static const char *
ToCstr()
{
if constexpr (LogLevel == LogType::eError) if constexpr (LogLevel == LogType::eError)
return "[ERROR]:"; return "[ERROR]:";
if constexpr (LogLevel == LogType::eWarning) if constexpr (LogLevel == LogType::eWarning)
@ -42,99 +46,116 @@ struct Logger {
} }
template <LogType LogLevel> template <LogType LogLevel>
constexpr static const char *to_color_cstr() { constexpr static const char *
ToColorCstr()
{
if constexpr (LogLevel == LogType::eError) if constexpr (LogLevel == LogType::eError)
return ANSI_Red; return ansi_color::Red;
if constexpr (LogLevel == LogType::eWarning) if constexpr (LogLevel == LogType::eWarning)
return ANSI_Yellow; return ansi_color::Yellow;
if constexpr (LogLevel == LogType::eInfo) if constexpr (LogLevel == LogType::eInfo)
return ANSI_Green; return ansi_color::Green;
if constexpr (LogLevel == LogType::eDebug) if constexpr (LogLevel == LogType::eDebug)
return ANSI_White; return ansi_color::White;
if constexpr (LogLevel == LogType::eVerbose) if constexpr (LogLevel == LogType::eVerbose)
return ANSI_Blue; return ansi_color::Blue;
return ANSI_White; return ansi_color::White;
} }
template <LogType LogLevel> template <LogType LogLevel>
void log(const std::string_view &_message, const char *_loc, u32 _line) const { void
if (cast<u32>(LogLevel) <= minimum_logging_level) { Log(const std::string_view &message, const char *loc, u32 line) const
fmt::println("{}{} {} {} at {}:{}{}", to_color_cstr<LogLevel>(), to_cstr<LogLevel>(), _message.data(), ANSI_Black, _loc, _line, ANSI_Reset); {
if (cast<u32>(LogLevel) <= m_MinimumLoggingLevel)
{
fmt::println("{}{} {} {} at {}:{}{}", ToColorCstr<LogLevel>(), ToCstr<LogLevel>(), message.data(),
ansi_color::Black, loc, line, ansi_color::Reset);
} }
#if !defined(NDEBUG) #if !defined(NDEBUG)
if constexpr (LogLevel == LogType::eError) { if constexpr (LogLevel == LogType::eError)
{
debug_break(); debug_break();
} }
#endif // !defined(NDEBUG) #endif // !defined(NDEBUG)
} }
template <LogType LogLevel> template <LogType LogLevel>
void log_cond(const char *_expr_str, const std::string_view &_message, const char *_loc, u32 _line) const { void
if (cast<u32>(LogLevel) <= minimum_logging_level) { LogCond(const char *exprStr, const std::string_view &message, const char *loc, u32 line) const
fmt::println("{}{} ({}) {} {} at {}:{}{}", to_color_cstr<LogLevel>(), to_cstr<LogLevel>(), _expr_str, _message.data(), ANSI_Black, _loc, _line, ANSI_Reset); {
if (cast<u32>(LogLevel) <= m_MinimumLoggingLevel)
{
fmt::println("{}{} ({}) {} {} at {}:{}{}", ToColorCstr<LogLevel>(), ToCstr<LogLevel>(), exprStr,
message.data(), ansi_color::Black, loc, line, ansi_color::Reset);
} }
#if !defined(NDEBUG) #if !defined(NDEBUG)
if constexpr (LogLevel == LogType::eError) { if constexpr (LogLevel == LogType::eError)
{
debug_break(); debug_break();
} }
#endif // !defined(NDEBUG) #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 MIN_LOG_LEVEL(LOG_LVL) g_Logger.SetMinimumLoggingLevel(LOG_LVL)
#define ERROR(...) g_logger.log<Logger::LogType::eError>(fmt::format(__VA_ARGS__), __FILE__, __LINE__) #define ERROR(...) g_Logger.Log<Logger::LogType::eError>(fmt::format(__VA_ARGS__), __FILE__, __LINE__)
#define WARN(...) g_logger.log<Logger::LogType::eWarning>(fmt::format(__VA_ARGS__), __FILE__, __LINE__) #define WARN(...) g_Logger.Log<Logger::LogType::eWarning>(fmt::format(__VA_ARGS__), __FILE__, __LINE__)
#define INFO(...) g_logger.log<Logger::LogType::eInfo>(fmt::format(__VA_ARGS__), __FILE__, __LINE__) #define INFO(...) g_Logger.Log<Logger::LogType::eInfo>(fmt::format(__VA_ARGS__), __FILE__, __LINE__)
#define ERROR_IF(expr, ...) \ #define ERROR_IF(expr, ...) \
if (cast<bool>(expr)) [[unlikely]] \ if (cast<bool>(expr)) [[unlikely]] \
g_logger.log_cond<Logger::LogType::eError>(#expr, fmt::format(__VA_ARGS__), __FILE__, __LINE__) g_Logger.LogCond<Logger::LogType::eError>(#expr, fmt::format(__VA_ARGS__), __FILE__, __LINE__)
#define WARN_IF(expr, ...) \ #define WARN_IF(expr, ...) \
if (cast<bool>(expr)) [[unlikely]] \ if (cast<bool>(expr)) [[unlikely]] \
g_logger.log_cond<Logger::LogType::eWarning>(#expr, fmt::format(__VA_ARGS__), __FILE__, __LINE__) g_Logger.LogCond<Logger::LogType::eWarning>(#expr, fmt::format(__VA_ARGS__), __FILE__, __LINE__)
#define INFO_IF(expr, ...) \ #define INFO_IF(expr, ...) \
if (cast<bool>(expr)) \ if (cast<bool>(expr)) \
g_logger.log_cond<Logger::LogType::eInfo>(#expr, fmt::format(__VA_ARGS__), __FILE__, __LINE__) g_Logger.LogCond<Logger::LogType::eInfo>(#expr, fmt::format(__VA_ARGS__), __FILE__, __LINE__)
#define ELSE_IF_ERROR(expr, ...) \ #define ELSE_IF_ERROR(expr, ...) \
; \ ; \
else if (cast<bool>(expr)) [[unlikely]] g_logger.log_cond<Logger::LogType::eError>(#expr, fmt::format(__VA_ARGS__), __FILE__, __LINE__) else if (cast<bool>(expr)) \
[[unlikely]] g_Logger.LogCond<Logger::LogType::eError>(#expr, fmt::format(__VA_ARGS__), __FILE__, __LINE__)
#define ELSE_IF_WARN(expr, ...) \ #define ELSE_IF_WARN(expr, ...) \
; \ ; \
else if (cast<bool>(expr)) [[unlikely]] g_logger.log_cond<Logger::LogType::eWarning>(#expr, fmt::format(__VA_ARGS__), __FILE__, __LINE__) else if (cast<bool>(expr)) \
[[unlikely]] g_Logger.LogCond<Logger::LogType::eWarning>(#expr, fmt::format(__VA_ARGS__), __FILE__, __LINE__)
#define ELSE_IF_INFO(expr, ...) \ #define ELSE_IF_INFO(expr, ...) \
; \ ; \
else if (cast<bool>(expr)) g_logger.log_cond<Logger::LogType::eInfo>(#expr, fmt::format(__VA_ARGS__), __FILE__, __LINE__) else if (cast<bool>(expr)) \
g_Logger.LogCond<Logger::LogType::eInfo>(#expr, fmt::format(__VA_ARGS__), __FILE__, __LINE__)
#define ELSE_ERROR(...) \ #define ELSE_ERROR(...) \
; \ ; \
else [[unlikely]] g_logger.log<Logger::LogType::eError>(fmt::format(__VA_ARGS__), __FILE__, __LINE__) else [[unlikely]] g_Logger.Log<Logger::LogType::eError>(fmt::format(__VA_ARGS__), __FILE__, __LINE__)
#define ELSE_WARN(...) \ #define ELSE_WARN(...) \
; \ ; \
else [[unlikely]] g_logger.log<Logger::LogType::eWarning>(fmt::format(__VA_ARGS__), __FILE__, __LINE__) else [[unlikely]] g_Logger.Log<Logger::LogType::eWarning>(fmt::format(__VA_ARGS__), __FILE__, __LINE__)
#define ELSE_INFO(...) \ #define ELSE_INFO(...) \
; \ ; \
else g_logger.log<Logger::LogType::eInfo>(fmt::format(__VA_ARGS__), __FILE__, __LINE__) else g_Logger.Log<Logger::LogType::eInfo>(fmt::format(__VA_ARGS__), __FILE__, __LINE__)
#if !defined(DEBUG_LOG_DISABLED) && !defined(NDEBUG) #if !defined(DEBUG_LOG_DISABLED) && !defined(NDEBUG)
#define DEBUG(...) g_logger.log<Logger::LogType::eDebug>(fmt::format(__VA_ARGS__), __FILE__, __LINE__) #define DEBUG(...) g_Logger.Log<Logger::LogType::eDebug>(fmt::format(__VA_ARGS__), __FILE__, __LINE__)
#define DEBUG_IF(expr, ...) \ #define DEBUG_IF(expr, ...) \
if (cast<bool>(expr)) \ if (cast<bool>(expr)) \
g_logger.log_cond<Logger::LogType::eDebug>(#expr, fmt::format(__VA_ARGS__), __FILE__, __LINE__) g_Logger.LogCond<Logger::LogType::eDebug>(#expr, fmt::format(__VA_ARGS__), __FILE__, __LINE__)
#define ELSE_IF_DEBUG(expr, ...) \ #define ELSE_IF_DEBUG(expr, ...) \
; \ ; \
else if (cast<bool>(expr)) g_logger.log_cond<Logger::LogType::eDebug>(#expr, fmt::format(__VA_ARGS__), __FILE__, __LINE__) else if (cast<bool>(expr)) \
g_Logger.LogCond<Logger::LogType::eDebug>(#expr, fmt::format(__VA_ARGS__), __FILE__, __LINE__)
#define ELSE_DEBUG(...) \ #define ELSE_DEBUG(...) \
; \ ; \
else [[unlikely]] g_logger.log<Logger::LogType::eDebug>(fmt::format(__VA_ARGS__), __FILE__, __LINE__) else g_Logger.Log<Logger::LogType::eDebug>(fmt::format(__VA_ARGS__), __FILE__, __LINE__)
#else // !defined(DEBUG_LOG_DISABLED) #else // !defined(DEBUG_LOG_DISABLED)
#define DEBUG(msg) \ #define DEBUG(msg) \
{} { \
}
#define DEBUG_IF(expr, msg) \ #define DEBUG_IF(expr, msg) \
if (expr) \ if (expr) \
(void)msg (void)msg
@ -144,27 +165,30 @@ extern Logger g_logger;
(void)msg (void)msg
#define ELSE_DEBUG(msg) \ #define ELSE_DEBUG(msg) \
; \ ; \
{} { \
}
#endif // !defined(DEBUG_LOG_DISABLED) #endif // !defined(DEBUG_LOG_DISABLED)
#if !defined(VERBOSE_LOG_DISABLED) && !defined(NDEBUG) #if !defined(VERBOSE_LOG_DISABLED) && !defined(NDEBUG)
#define VERBOSE(...) g_logger.log<Logger::LogType::eVerbose>(fmt::format(__VA_ARGS__), __FILE__, __LINE__) #define VERBOSE(...) g_Logger.Log<Logger::LogType::eVerbose>(fmt::format(__VA_ARGS__), __FILE__, __LINE__)
#define VERBOSE_IF(expr, ...) \ #define VERBOSE_IF(expr, ...) \
if (cast<bool>(expr)) \ if (cast<bool>(expr)) \
g_logger.log_cond<Logger::LogType::eVerbose>(#expr, fmt::format(__VA_ARGS__), __FILE__, __LINE__) g_Logger.LogCond<Logger::LogType::eVerbose>(#expr, fmt::format(__VA_ARGS__), __FILE__, __LINE__)
#define ELSE_IF_VERBOSE(expr, ...) \ #define ELSE_IF_VERBOSE(expr, ...) \
; \ ; \
else if (cast<bool>(expr)) g_logger.log_cond<Logger::LogType::eVerbose>(#expr, fmt::format(__VA_ARGS__), __FILE__, __LINE__) else if (cast<bool>(expr)) \
g_Logger.LogCond<Logger::LogType::eVerbose>(#expr, fmt::format(__VA_ARGS__), __FILE__, __LINE__)
#define ELSE_VERBOSE(...) \ #define ELSE_VERBOSE(...) \
; \ ; \
else g_logger.log<Logger::LogType::eVerbose>(fmt::format(__VA_ARGS__), __FILE__, __LINE__) else g_Logger.Log<Logger::LogType::eVerbose>(fmt::format(__VA_ARGS__), __FILE__, __LINE__)
#else // !defined(DEBUG_LOG_DISABLED) #else // !defined(DEBUG_LOG_DISABLED)
#define VERBOSE(msg) \ #define VERBOSE(msg) \
{} { \
}
#define VERBOSE_IF(expr, msg) \ #define VERBOSE_IF(expr, msg) \
if (expr) \ if (expr) \
(void)msg (void)msg
@ -174,10 +198,11 @@ extern Logger g_logger;
(void)msg (void)msg
#define ELSE_VERBOSE(msg) \ #define ELSE_VERBOSE(msg) \
; \ ; \
{} { \
}
#endif // !defined(VERBOSE_LOG_DISABLED) #endif // !defined(VERBOSE_LOG_DISABLED)
#define DO(code) , code #define DO(code) , code
#define CRASH(code) exit(cast<i32>(code)) #define ABORT(code) exit(cast<i32>(code))
#define THEN_CRASH(code) , CRASH(code) #define THEN_ABORT(code) , ABORT(code)

View File

@ -5,95 +5,145 @@
#include "physical_device.h" #include "physical_device.h"
[[nodiscard]] std::vector<vk::SurfaceFormatKHR> get_surface_formats(const Window *_window, const vk::PhysicalDevice *_physical_device) { [[nodiscard]] eastl::vector<vk::SurfaceFormatKHR>
try { getSurfaceFormats(const vk::SurfaceKHR surface, const vk::PhysicalDevice physicalDevice)
return _physical_device->getSurfaceFormatsKHR(_window->surface); {
} catch (const std::exception &_err) { // vk::Result::eIncomplete should not occur in this function. The rest are errors. Thus, abort is allowed.
ERROR("Could not get surface formats. Cause: {}", _err.what()); u32 count = 0;
throw; 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<vk::SurfaceFormatKHR> 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<vk::PresentModeKHR> get_present_modes(const Window *_window, const vk::PhysicalDevice *_physical_device) { [[nodiscard]] eastl::vector<vk::PresentModeKHR>
try { getSurfacePresentModes(const vk::SurfaceKHR surface, const vk::PhysicalDevice physicalDevice)
return _physical_device->getSurfacePresentModesKHR(_window->surface); {
} catch (const std::exception &_err) { // vk::Result::eIncomplete should not occur in this function. The rest are errors. Thus, abort is allowed.
ERROR("Could not get present modes. Cause: {}", _err.what()); u32 count = 0;
throw; 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<vk::PresentModeKHR> 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) { [[nodiscard]] bool
try { getQueuePresentSupport(const u32 queueFamilyIndex, vk::SurfaceKHR surface, const vk::PhysicalDevice physicalDevice)
return _device->getSurfaceSupportKHR(_family_index, _window->surface); {
} catch (const std::exception &_err) { b32 supported = false;
ERROR("Could not get queue family surface support. Cause: {}", _err.what()); const vk::Result result = physicalDevice.getSurfaceSupportKHR(queueFamilyIndex, surface, &supported);
throw; ERROR_IF(failed(result), "Could not get queue family surface support. Cause: {}", to_string(result))
} THEN_ABORT(result);
return supported;
} }
[[nodiscard]] std::vector<QueueFamilyInfo> get_queue_families(const Window *_window, const vk::PhysicalDevice *_device) { [[nodiscard]] eastl::fixed_vector<vk::QueueFamilyProperties, 32>
auto queue_family_props = _device->getQueueFamilyProperties(); 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<QueueFamilyInfo> queue_family_infos; eastl::fixed_vector<vk::QueueFamilyProperties, 32> queueFamilyProperties(count);
queue_family_infos.reserve(queue_family_props.size()); physicalDevice.getQueueFamilyProperties(&count, queueFamilyProperties.data());
u32 family_index = 0; return queueFamilyProperties;
for (auto qfp : queue_family_props) { }
// Size 384 return.
[[nodiscard]] eastl::vector<QueueFamilyInfo>
getQueueFamilies(const vk::SurfaceKHR surface, const vk::PhysicalDevice physicalDevice)
{
auto queueFamilyProperties = getQueueFamilyProperties(physicalDevice);
eastl::vector<QueueFamilyInfo> queueFamilyInfos;
queueFamilyInfos.reserve(queueFamilyProperties.size());
u32 familyIndex = 0;
for (auto qfp : queueFamilyProperties)
{
QueueSupportFlags support = {}; QueueSupportFlags support = {};
if (qfp.queueFlags | vk::QueueFlagBits::eGraphics) { if (qfp.queueFlags | vk::QueueFlagBits::eGraphics)
{
support |= QueueSupportFlagBits::eGraphics; support |= QueueSupportFlagBits::eGraphics;
} }
if (qfp.queueFlags | vk::QueueFlagBits::eTransfer) { if (qfp.queueFlags | vk::QueueFlagBits::eTransfer)
{
support |= QueueSupportFlagBits::eTransfer; support |= QueueSupportFlagBits::eTransfer;
} }
if (qfp.queueFlags | vk::QueueFlagBits::eCompute) { if (qfp.queueFlags | vk::QueueFlagBits::eCompute)
{
support |= QueueSupportFlagBits::eCompute; support |= QueueSupportFlagBits::eCompute;
} }
if (get_present_support(family_index, _window, _device)) { if (getQueuePresentSupport(familyIndex, surface, physicalDevice))
{
support |= QueueSupportFlagBits::ePresent; support |= QueueSupportFlagBits::ePresent;
} }
queue_family_infos.push_back({ queueFamilyInfos.push_back({
.index = family_index, .m_Index = familyIndex,
.count = qfp.queueCount, .m_Count = qfp.queueCount,
.support = support, .m_Support = support,
}); });
family_index++; familyIndex++;
} }
return queue_family_infos; return queueFamilyInfos;
} }
PhysicalDevice::PhysicalDevice(const Window *_window, vk::PhysicalDevice _physical_device) { PhysicalDevice::PhysicalDevice(const vk::SurfaceKHR surface, const vk::PhysicalDevice physicalDevice)
_physical_device.getProperties(&properties); {
_physical_device.getFeatures(&features); physicalDevice.getProperties(&m_DeviceProperties);
physicalDevice.getFeatures(&m_DeviceFeatures);
surface_formats = get_surface_formats(_window, &_physical_device); m_SurfaceFormats = getSurfaceFormats(surface, physicalDevice);
present_modes = get_present_modes(_window, &_physical_device); m_PresentModes = getSurfacePresentModes(surface, physicalDevice);
queue_families = get_queue_families(_window, &_physical_device); m_QueueFamilies = getQueueFamilies(surface, physicalDevice);
device = _physical_device; m_PhysicalDevice = physicalDevice;
} }
std::vector<vk::PhysicalDevice> enumerate_physical_devices(const Context *_context) { eastl::fixed_vector<vk::PhysicalDevice, 8>
try { enumeratePhysicalDevices(const vk::Instance instance)
return _context->instance.enumeratePhysicalDevices(); {
} catch (const std::exception &_err) { u32 count = 0;
ERROR("Could not fetch vulkan devices. Cause: {}", _err.what()); vk::Result result = instance.enumeratePhysicalDevices(&count, nullptr);
throw; ERROR_IF(failed(result), "Could not fetch vulkan devices. Cause: {}", to_string(result))
} THEN_ABORT(result);
eastl::fixed_vector<vk::PhysicalDevice, 8> 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) { PhysicalDevices::PhysicalDevices(const Window *window, const Context *context)
auto physical_devices = enumerate_physical_devices(_context); {
this->reserve(physical_devices.size()); auto surface = window->m_Surface;
for (auto physical_device : physical_devices) { auto physicalDevices = enumeratePhysicalDevices(context->m_Instance);
this->emplace_back(_window, physical_device); for (auto physicalDevice : physicalDevices)
{
this->emplace_back(surface, physicalDevice);
} }
} }

View File

@ -7,8 +7,10 @@
#include "global.h" #include "global.h"
#include "window.h" #include "window.h"
#include <EASTL/fixed_vector.h>
enum class QueueSupportFlagBits { enum class QueueSupportFlagBits
{
eGraphics = 0b0001, eGraphics = 0b0001,
eTransfer = 0b0010, eTransfer = 0b0010,
eCompute = 0b0100, eCompute = 0b0100,
@ -17,24 +19,27 @@ enum class QueueSupportFlagBits {
using QueueSupportFlags = vk::Flags<QueueSupportFlagBits>; using QueueSupportFlags = vk::Flags<QueueSupportFlagBits>;
struct QueueFamilyInfo { struct QueueFamilyInfo
u32 index; {
u32 count; u32 m_Index;
QueueSupportFlags support; u32 m_Count;
QueueSupportFlags m_Support;
}; };
struct PhysicalDevice { struct PhysicalDevice
vk::PhysicalDevice device; {
vk::PhysicalDeviceProperties properties; vk::PhysicalDevice m_PhysicalDevice;
vk::PhysicalDeviceFeatures features; vk::PhysicalDeviceProperties m_DeviceProperties;
std::vector<vk::SurfaceFormatKHR> surface_formats; vk::PhysicalDeviceFeatures m_DeviceFeatures;
std::vector<vk::PresentModeKHR> present_modes; eastl::vector<vk::SurfaceFormatKHR> m_SurfaceFormats;
std::vector<QueueFamilyInfo> queue_families; eastl::vector<vk::PresentModeKHR> m_PresentModes;
eastl::vector<QueueFamilyInfo> m_QueueFamilies;
PhysicalDevice(const Window *_window, vk::PhysicalDevice _physical_device); PhysicalDevice(vk::SurfaceKHR surface, vk::PhysicalDevice physicalDevice);
}; };
class PhysicalDevices : public std::vector<PhysicalDevice> { class PhysicalDevices : public eastl::fixed_vector<PhysicalDevice, 4>
{
public: public:
PhysicalDevices(const Window *_window, const Context *_context); PhysicalDevices(const Window *window, const Context *context);
}; };

View File

@ -8,65 +8,72 @@
#include "glfw_context.h" #include "glfw_context.h"
#include "logger.h" #include "logger.h"
Window::Window(const std::string_view &_title, Context *_context, vk::Extent2D _extent, b8 _full_screen) : void
parent_context{ std::move(_context) }, extent{ _extent }, name{ _title }, full_screen{ _full_screen } { Window::SetWindowSize(const vk::Extent2D &extent) const noexcept
monitor = glfwGetPrimaryMonitor(); {
ERROR_IF(monitor == nullptr, "No monitor found"); SetWindowSize(extent.width, extent.height);
}
i32 x_, y_, w_, h_; void
glfwGetMonitorWorkarea(monitor, &x_, &y_, &w_, &h_); Window::SetWindowSize(const u32 width, const u32 height) const noexcept
{
glfwSetWindowSize(m_Window, cast<i32>(width), cast<i32>(height));
}
Window::Window(cstr title, Context *context, vk::Extent2D extent, b8 isFullScreen)
{
m_Context = context;
m_Name = title;
GLFWmonitor *monitor = glfwGetPrimaryMonitor();
ERROR_IF(!monitor, "No monitor found");
i32 windowX, windowY, windowWidth, windowHeight;
glfwGetMonitorWorkarea(monitor, &windowX, &windowY, &windowWidth, &windowHeight);
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
glfwWindowHint(GLFW_CENTER_CURSOR, GLFW_TRUE); glfwWindowHint(GLFW_CENTER_CURSOR, GLFW_TRUE);
window = glfwCreateWindow(extent.width, extent.height, name.data(), full_screen ? monitor : nullptr, nullptr); m_Window = glfwCreateWindow(cast<i32>(extent.width), cast<i32>(extent.height), m_Name.c_str(),
ERROR_IF(window == nullptr, "Window creation failed") isFullScreen ? monitor : nullptr, nullptr);
ELSE_INFO("Window '{}' created with resolution '{}x{}'", name, extent.width, extent.height); ERROR_IF(m_Window == nullptr, "Window creation failed")
if (window == nullptr) { ELSE_DEBUG("Window '{}' created with resolution '{}x{}'", m_Name.c_str(), extent.width, extent.height);
auto code = GlfwContext::post_error(); if (m_Window == nullptr)
{
auto code = GlfwContext::PostError();
glfwTerminate(); glfwTerminate();
CRASH(code); ABORT(code);
} }
if (full_screen == false) { if (isFullScreen == false)
glfwSetWindowPos(window, (w_ - extent.width) / 2, (h_ - extent.height) / 2); {
glfwSetWindowPos(m_Window, cast<i32>(windowWidth - extent.width) / 2,
cast<i32>(windowHeight - extent.height) / 2);
} }
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); glfwSetInputMode(m_Window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
VkSurfaceKHR surface_; VkSurfaceKHR surface;
auto result = cast<vk::Result>(glfwCreateWindowSurface(cast<VkInstance>(_context->instance), window, nullptr, &surface_)); auto result =
cast<vk::Result>(glfwCreateWindowSurface(cast<VkInstance>(m_Context->m_Instance), m_Window, nullptr, &surface));
ERROR_IF(failed(result), "Failed to create Surface with {}", to_string(result)) ERROR_IF(failed(result), "Failed to create Surface with {}", to_string(result))
THEN_CRASH(result) ELSE_INFO("Surface Created"); THEN_ABORT(result)
surface = vk::SurfaceKHR(surface_); ELSE_DEBUG("Surface {} Created", m_Name.c_str());
m_Surface = vk::SurfaceKHR(surface);
} }
Window::Window(Window &&_other) noexcept : Window::~Window()
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 } {} {
if (m_Context && m_Surface)
Window &Window::operator=(Window &&_other) noexcept { {
if (this == &_other) m_Context->m_Instance.destroy(m_Surface, nullptr);
return *this; DEBUG("Surface Destroyed");
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;
} }
Window::~Window() { if (m_Window != nullptr)
if (parent_context && surface) { {
parent_context->instance.destroy(surface); glfwDestroyWindow(m_Window);
INFO("Surface Destroyed"); m_Window = nullptr;
} }
if (window != nullptr) { DEBUG("Window '{}' Destroyed", m_Name.c_str());
glfwDestroyWindow(window);
window = nullptr;
}
monitor = nullptr;
INFO("Window '{}' Destroyed", name);
} }

View File

@ -5,45 +5,31 @@
#pragma once #pragma once
#include "global.h"
#include "context.h" #include "context.h"
#include "global.h"
#include <EASTL/fixed_string.h>
struct Window final { struct Window final
Window(const std::string_view &_title, Context *_context, vk::Extent2D _extent, b8 _full_screen = false); {
Window(const Window &_other) = delete;
Window(Window &&_other) noexcept;
Window &operator=(const Window &_other) = delete;
Window &operator=(Window &&_other) noexcept;
~Window();
[[nodiscard]] bool should_close() const noexcept {
return glfwWindowShouldClose(window);
}
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 // fields
Context *parent_context{}; Context *m_Context{};
GLFWwindow *window{ nullptr }; GLFWwindow *m_Window = nullptr;
GLFWmonitor *monitor{ nullptr }; vk::SurfaceKHR m_Surface;
vk::SurfaceKHR surface; eastl::fixed_string<char, 32> m_Name;
vk::Extent2D extent;
std::string name; // Methods
b8 full_screen{ false }; [[nodiscard]] bool
Poll() const noexcept
{
glfwPollEvents();
return !glfwWindowShouldClose(m_Window);
}
void SetWindowSize(const vk::Extent2D &extent) const noexcept;
void SetWindowSize(u32 width, u32 height) const noexcept;
// Ctor/Dtor
Window(cstr title, Context *context, vk::Extent2D extent, b8 isFullScreen = false);
~Window();
}; };

View File

@ -4,59 +4,82 @@
#include "aster/physical_device.h" #include "aster/physical_device.h"
#include "aster/window.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) { constexpr QueueSupportFlags REQUIRED_QUEUE_SUPPORT = QueueSupportFlags{} | QueueSupportFlagBits::eGraphics |
const bool all_required_queues = std::ranges::any_of(_physical_device->queue_families, [](const auto &_qfp) { QueueSupportFlagBits::eCompute | QueueSupportFlagBits::ePresent |
return (_qfp.support & required_queue_support) == required_queue_support; QueueSupportFlagBits::eTransfer;
[[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 device_type_check = _physical_device->properties.deviceType != vk::PhysicalDeviceType::eCpu; const bool isNotCpu = physicalDevice->m_DeviceProperties.deviceType != vk::PhysicalDeviceType::eCpu;
const bool supported_present_mode = !_physical_device->present_modes.empty(); const bool hasPresentMode = !physicalDevice->m_PresentModes.empty();
const bool supported_format = !_physical_device->surface_formats.empty(); const bool hasSurfaceFormat = !physicalDevice->m_SurfaceFormats.empty();
return supported_format && supported_present_mode && device_type_check && all_required_queues; return hasSurfaceFormat && hasPresentMode && isNotCpu && hasAllRequiredQueues;
} }
PhysicalDevice find_suitable_device(const PhysicalDevices &_physical_devices) { PhysicalDevice
for (auto &_physical_device : _physical_devices) { findSuitableDevice(const PhysicalDevices &physicalDevices)
if (is_suitable_device(&_physical_device)) { {
return _physical_device; for (auto &physicalDevice : physicalDevices)
{
if (isSuitableDevice(&physicalDevice))
{
return physicalDevice;
} }
} }
throw std::runtime_error("No suitable device found.");
}
QueueAllocation find_appropriate_queue_allocation(const PhysicalDevice* _physical_device) { ERROR("No suitable GPU available on the system.")
for (auto &_queue_info: _physical_device->queue_families) { THEN_ABORT(vk::Result::eErrorUnknown);
if ((_queue_info.support & required_queue_support) == required_queue_support) { }
QueueAllocation
findAppropriateQueueAllocation(const PhysicalDevice *physicalDevice)
{
for (auto &queueFamilyInfo : physicalDevice->m_QueueFamilies)
{
if ((queueFamilyInfo.m_Support & REQUIRED_QUEUE_SUPPORT) == REQUIRED_QUEUE_SUPPORT)
{
return { return {
.family = _queue_info.index, .m_Family = queueFamilyInfo.m_Index,
.count = _queue_info.count, .m_Count = queueFamilyInfo.m_Count,
}; };
} }
} }
throw std::runtime_error("No suitable queue family."); ERROR("No suitable queue family on the GPU.")
THEN_ABORT(vk::Result::eErrorUnknown);
} }
int main(int, char **) { int
GlfwContext glfw_context = {}; main(int, char **)
{
MIN_LOG_LEVEL(Logger::LogType::eInfo);
GlfwContext glfwContext = {};
Context context = {"Aster", VERSION}; Context context = {"Aster", VERSION};
Window window = {"Aster1", &context, {640, 480}}; Window window = {"Aster1", &context, {640, 480}};
PhysicalDevices physical_devices = { &window, &context }; PhysicalDevices physicalDevices = {&window, &context};
PhysicalDevice device_to_use = find_suitable_device(physical_devices); 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 = {}; vk::PhysicalDeviceFeatures features = {};
QueueAllocation queue_allocation = find_appropriate_queue_allocation(&device_to_use); QueueAllocation queueAllocation = findAppropriateQueueAllocation(&deviceToUse);
Device device = { &context, std::move(device_to_use), &features, {queue_allocation}, "Primary Device" }; Device device = {&context, &deviceToUse, &features, {queueAllocation}, "Primary Device"};
while (window.poll()) { while (window.Poll())
{
} }
return 0; return 0;

View File

@ -1,9 +1,10 @@
{ {
"dependencies": [ "dependencies": [
"fmt",
"glfw3", "glfw3",
"glm", "glm",
"scottt-debugbreak", "scottt-debugbreak",
"vulkan-memory-allocator", "vulkan-memory-allocator",
"fmt" "eastl"
] ]
} }