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 9381b967e7
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).
---
### 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
@ -90,110 +18,10 @@ IncludeCategories:
Priority: 2
- Regex: '^<.*'
Priority: 3
# IncludeIsMainRegex: '(Test)?$'
# IncludeIsMainSourceRegex: ''
# IndentAccessModifiers: false
IndentCaseLabels: true
# IndentCaseBlocks: false
# IndentGotoLabels: true
# IndentPPDirectives: None
# IndentExternBlock: AfterExternBlock
# IndentRequires: false
#IndentCaseLabels: true
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
#KeepEmptyLinesAtTheStartOfBlocks: false
PenaltyReturnTypeOnItsOwnLine: 0
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']
...
Standard: c++20

View File

@ -29,9 +29,9 @@ CheckOptions:
- key: modernize-loop-convert.NamingStyle
value: CamelCase
- key: modernize-pass-by-value.IncludeStyle
value: llvm
value: microsoft
- key: modernize-replace-auto-ptr.IncludeStyle
value: llvm
value: microsoft
- key: modernize-use-bool-literals.IgnoreMacros
value: '0'
- 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_EXTENSIONS OFF)
set(CMAKE_CXX_FLAGS -Wall)
set(CMAKE_CXX_FLAGS "-Wall -fno-rtti -fno-exceptions")
add_subdirectory("aster")
add_subdirectory("triangle")

View File

@ -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)

View File

@ -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

View File

@ -5,10 +5,10 @@
#pragma once
#include <vulkan/vulkan_core.h>
#include <cstdint>
#include <cstdio>
#include <optional>
#include <tuple>
#include <glm/glm.hpp>
@ -28,53 +28,69 @@ 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) {
constexpr usize
strlenC(const char *s)
{
usize len = 0;
char c = '\0';
do {
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 <typename T>
using Option = std::optional<T>;
template <typename type_t, typename from_t>
constexpr auto cast(from_t &&_in) {
return static_cast<type_t>(std::forward<from_t>(_in));
template <typename TypeT, typename FromT>
constexpr auto
cast(FromT &&in)
{
return static_cast<TypeT>(std::forward<FromT>(in));
}
template <typename type_t, typename from_t>
constexpr auto recast(from_t &&_in) {
return reinterpret_cast<type_t>(std::forward<from_t>(_in));
template <typename TypeT, typename FromT>
constexpr auto
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));
}
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));
}
constexpr f32 operator""_rad(long double rads) {
constexpr f32
operator""_rad(long double 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);
}
@ -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 <typename T>
constexpr T max_value = std::numeric_limits<T>::max();
constexpr T MaxValue = std::numeric_limits<T>::max();
template <typename T>
constexpr T min_value = std::numeric_limits<T>::min();
constexpr T MinValue = std::numeric_limits<T>::min();
template <typename T>
constexpr T lowest_value = std::numeric_limits<T>::lowest();
constexpr T LowestValue = std::numeric_limits<T>::lowest();
template <typename T>
constexpr T err_epsilon = std::numeric_limits<T>::epsilon();
constexpr T ErrEpsilon = std::numeric_limits<T>::epsilon();
template <typename T>
constexpr T positive_inf = std::numeric_limits<T>::infinity();
constexpr T PositiveInf = std::numeric_limits<T>::infinity();
template <typename T>
constexpr T negative_inf = -std::numeric_limits<T>::infinity();
constexpr T NegativeInf = -std::numeric_limits<T>::infinity();
template <typename T>
constexpr T qnan = std::numeric_limits<T>::quiet_NaN();
constexpr T Qnan = std::numeric_limits<T>::quiet_NaN();
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 <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 SeverityBits = vk::DebugUtilsMessageSeverityFlagBitsEXT;
using MessageType = vk::DebugUtilsMessageTypeFlagsEXT;
using MessageTypeBits = vk::DebugUtilsMessageTypeFlagBitsEXT;
const auto severity = Severity(_message_severity);
const auto message_type = MessageType(_message_type);
const auto severity = Severity(messageSeverity);
if (message_type & MessageTypeBits::eValidation) {
if (MessageType(messageType) & MessageTypeBits::eValidation)
{
if (severity & SeverityBits::eError)
ERROR("{}", _callback_data->pMessage);
ERROR("{}", callbackData->pMessage);
if (severity & SeverityBits::eWarning)
WARN("{}", _callback_data->pMessage);
WARN("{}", callbackData->pMessage);
if (severity & SeverityBits::eInfo)
INFO("{}", _callback_data->pMessage);
INFO("{}", callbackData->pMessage);
if (severity & SeverityBits::eVerbose)
VERBOSE("{}", _callback_data->pMessage);
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),
const vk::ApplicationInfo appInfo = {
.pApplicationName = appName,
.applicationVersion = version.GetVkVersion(),
.pEngineName = PROJECT_NAME,
.engineVersion = VK_MAKE_VERSION(VERSION.major, VERSION.minor, VERSION.patch),
.engineVersion = version.GetVkVersion(),
.apiVersion = ASTER_API_VERSION,
};
vk::DebugUtilsMessengerCreateInfoEXT debug_messenger_create_info = {
vk::DebugUtilsMessengerCreateInfoEXT debugUtilsMessengerCreateInfo = {
.messageSeverity = vk::DebugUtilsMessageSeverityFlagBitsEXT::eError |
vk::DebugUtilsMessageSeverityFlagBitsEXT::eWarning |
vk::DebugUtilsMessageSeverityFlagBitsEXT::eInfo,
.messageType = vk::DebugUtilsMessageTypeFlagBitsEXT::eGeneral |
vk::DebugUtilsMessageTypeFlagBitsEXT::ePerformance |
vk::DebugUtilsMessageTypeFlagBitsEXT::eValidation,
.pfnUserCallback = debug_callback,
.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<cstr, 3> instanceExtensions(glfwExtensions, glfwExtensions + glfwExtensionCount);
if (enableValidation)
{
instanceExtensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
}
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");
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<u32>(validation_layers.size()) : 0,
.ppEnabledLayerNames = enable_validation_layers ? validation_layers.data() : nullptr,
.enabledExtensionCount = cast<u32>(vulkan_extensions.size()),
.ppEnabledExtensionNames = vulkan_extensions.data(),
const auto instanceCreateInfo = vk::InstanceCreateInfo{
.pNext = enableValidation ? &debugUtilsMessengerCreateInfo : nullptr,
.pApplicationInfo = &appInfo,
.enabledLayerCount = enableValidation ? cast<u32>(VALIDATION_LAYERS.size()) : 0,
.ppEnabledLayerNames = enableValidation ? VALIDATION_LAYERS.data() : nullptr,
.enabledExtensionCount = cast<u32>(instanceExtensions.size()),
.ppEnabledExtensionNames = instanceExtensions.data(),
};
// May throw. Irrecoverable.
instance = vk::createInstance(instance_create_info);
INFO("Instance Created.");
VULKAN_HPP_DEFAULT_DISPATCHER.init(instance);
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.");
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");
}

View File

@ -6,8 +6,6 @@
#pragma once
#include "global.h"
#include <utility>
#include <vector>
/**
* @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);
}
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;
}
struct Context final
{
// Members
vk::Instance m_Instance = nullptr;
vk::DebugUtilsMessengerEXT m_DebugMessenger = nullptr;
// Ctor/Dtor
Context(cstr appName, Version version, bool enableValidation = true);
~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,81 @@
#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) :
physical_device{ std::move(_physical_device) },
name{ std::move(_name) } {
std::vector<vk::DeviceQueueCreateInfo> queue_create_infos;
queue_create_infos.reserve(_queue_allocation.size());
#include <EASTL/array.h>
u32 num_priorities = 0;
for (auto [_, count] : _queue_allocation) {
num_priorities = std::max(count, num_priorities);
constexpr eastl::array DEVICE_EXTENSIONS = {VK_KHR_SWAPCHAIN_EXTENSION_NAME};
Device::Device(const Context *context, PhysicalDevice &&physicalDevice,
const vk::PhysicalDeviceFeatures *enabledFeatures,
const eastl::vector<QueueAllocation> &queueAllocations, NameString name)
: m_Name(std::move(name))
, m_PhysicalDevice(std::make_unique<PhysicalDevice>(physicalDevice))
{
// 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) {
queue_create_infos.push_back({
for (auto [family, count] : queueAllocations)
{
deviceQueueCreateInfos.push_back({
.queueFamilyIndex = family,
.queueCount = count,
.pQueuePriorities = priorities.data(),
});
}
try {
device = physical_device.device.createDevice({
.queueCreateInfoCount = cast<u32>(queue_create_infos.size()),
.pQueueCreateInfos = queue_create_infos.data(),
.enabledLayerCount = _context->enable_validation_layers ? cast<u32>(_context->validation_layers.size()) : 0,
.ppEnabledLayerNames = _context->enable_validation_layers ? _context->validation_layers.data() : nullptr,
.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;
}
vk::DeviceCreateInfo deviceCreateInfo = {
.queueCreateInfoCount = cast<u32>(deviceQueueCreateInfos.size()),
.pQueueCreateInfos = deviceQueueCreateInfos.data(),
.enabledExtensionCount = cast<u32>(DEVICE_EXTENSIONS.size()),
.ppEnabledExtensionNames = DEVICE_EXTENSIONS.data(),
.pEnabledFeatures = enabledFeatures,
};
INFO("{} ({}) Initialized!", name.value_or(DEFAULT_DEVICE_NAME), physical_device.properties.deviceName.data());
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());
VmaVulkanFunctions vma_vulkan_functions = {
VmaVulkanFunctions vmaVulkanFunctions = {
.vkGetInstanceProcAddr = vk::defaultDispatchLoaderDynamic.vkGetInstanceProcAddr,
.vkGetDeviceProcAddr = vk::defaultDispatchLoaderDynamic.vkGetDeviceProcAddr,
};
const VmaAllocatorCreateInfo vma_allocator_create_info = {
const VmaAllocatorCreateInfo allocatorCreateInfo = {
.flags = 0,
.physicalDevice = physical_device.device,
.device = device,
.pVulkanFunctions = &vma_vulkan_functions,
.instance = _context->instance,
.physicalDevice = m_PhysicalDevice->m_PhysicalDevice,
.device = m_Device,
.pVulkanFunctions = &vmaVulkanFunctions,
.instance = context->m_Instance,
.vulkanApiVersion = ASTER_API_VERSION,
};
const auto result = cast<vk::Result>(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");
result = cast<vk::Result>(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");
INFO("Created '{}' Successfully", name.value_or(DEFAULT_DEVICE_NAME));
DEBUG("Created '{}' Successfully", m_Name);
}
Device::~Device() {
if (allocator) {
vmaDestroyAllocator(allocator);
allocator = nullptr;
VERBOSE("Memory Allocator Destroyed");
Device::~Device()
{
if (m_Allocator)
{
vmaDestroyAllocator(m_Allocator);
m_Allocator = nullptr;
DEBUG("Memory Allocator Destroyed");
}
device.destroy();
INFO("Device '{}' Destroyed", name.value_or(DEFAULT_DEVICE_NAME));
name = std::nullopt;
m_Device.destroy(nullptr);
DEBUG("Device '{}' Destroyed", m_Name);
}

View File

@ -8,20 +8,23 @@
#include "global.h"
#include "physical_device.h"
constexpr std::string DEFAULT_DEVICE_NAME = "<Unnamed GPU>";
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<std::string> name{ nullptr };
struct Device final
{
using NameString = eastl::fixed_string<char, 32, false>;
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;
std::unique_ptr<PhysicalDevice> m_PhysicalDevice;
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();
};

View File

@ -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_);
struct GlfwContext
{
static i32
PostError() noexcept
{
static const char *error = nullptr;
const auto code = glfwGetError(&error);
ERROR("GLFW {}", error);
return code;
}
inline static u32 count = 0;
inline static u32 m_Count = 0;
GlfwContext() {
if (count++ > 0)
GlfwContext()
{
if (m_Count++ > 0)
return;
if (glfwInit() == GLFW_FALSE) {
CRASH(post_error());
if (glfwInit() == GLFW_FALSE)
{
ABORT(PostError());
}
}
~GlfwContext() {
if (--count == 0) {
~GlfwContext()
{
if (--m_Count == 0)
{
glfwTerminate();
}
count = 0;
m_Count = 0;
}
};

View File

@ -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];
}

View File

@ -11,30 +11,52 @@
#include <GLFW/glfw3.h>
#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")
#include <EASTL/fixed_string.h>
#include <EASTL/string.h>
#include <vk_mem_alloc.h>
#include <vulkan/vulkan.hpp>
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 <typename T>
concept IsVkEnum = requires(T _t) {
{ std::is_enum_v<T> };
{ vk::to_string(_t) } -> std::same_as<std::string>;
concept IsVkEnum = requires(T t) {
{
std::is_enum_v<T>
};
{
vk::to_string(t)
} -> std::same_as<std::string>;
};
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;
buffer = vk::to_string(_val);
buffer = vk::to_string(val);
return buffer.c_str();
}
@ -43,49 +65,87 @@ using namespace std::literals::string_literals;
using namespace std::literals::string_view_literals;
template <typename T>
requires vk::isVulkanHandleType<T>::value [[nodiscard]] constexpr u64
get_vk_handle(const T &_vk_handle) noexcept {
return reinterpret_cast<u64>(cast<T::CType>(_vk_handle));
requires vk::isVulkanHandleType<T>::value
[[nodiscard]] constexpr u64
getVkHandle(const T &vkHandle) noexcept
{
return reinterpret_cast<u64>(cast<T::CType>(vkHandle));
}
template <typename F>
struct std::hash<vk::Flags<F>> {
[[nodiscard]] usize operator()(const vk::Flags<F> &_val) {
return std::hash<u32>()(cast<u32>(_val));
struct std::hash<vk::Flags<F>>
{
[[nodiscard]] usize
operator()(const vk::Flags<F> &val)
{
return std::hash<u32>()(cast<u32>(val));
}
};
template <typename T>
[[nodiscard]] usize hash_any(const T &_val) {
return std::hash<std::remove_cvref_t<T>>()(_val);
[[nodiscard]] usize
hashAny(const T &val)
{
return std::hash<std::remove_cvref_t<T>>()(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<f64> };
inline static f64 delta{ qnan<f64> };
inline static f64 m_Elapsed{Qnan<f64>};
inline static f64 m_Delta{Qnan<f64>};
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<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"
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

View File

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

View File

@ -5,95 +5,145 @@
#include "physical_device.h"
[[nodiscard]] std::vector<vk::SurfaceFormatKHR> 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<vk::SurfaceFormatKHR>
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<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) {
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<vk::PresentModeKHR>
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<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) {
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<QueueFamilyInfo> get_queue_families(const Window *_window, const vk::PhysicalDevice *_device) {
auto queue_family_props = _device->getQueueFamilyProperties();
[[nodiscard]] eastl::fixed_vector<vk::QueueFamilyProperties, 32>
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;
queue_family_infos.reserve(queue_family_props.size());
eastl::fixed_vector<vk::QueueFamilyProperties, 32> queueFamilyProperties(count);
physicalDevice.getQueueFamilyProperties(&count, queueFamilyProperties.data());
u32 family_index = 0;
for (auto qfp : queue_family_props) {
return queueFamilyProperties;
}
// 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 = {};
if (qfp.queueFlags | vk::QueueFlagBits::eGraphics) {
if (qfp.queueFlags | vk::QueueFlagBits::eGraphics)
{
support |= QueueSupportFlagBits::eGraphics;
}
if (qfp.queueFlags | vk::QueueFlagBits::eTransfer) {
if (qfp.queueFlags | vk::QueueFlagBits::eTransfer)
{
support |= QueueSupportFlagBits::eTransfer;
}
if (qfp.queueFlags | vk::QueueFlagBits::eCompute) {
if (qfp.queueFlags | vk::QueueFlagBits::eCompute)
{
support |= QueueSupportFlagBits::eCompute;
}
if (get_present_support(family_index, _window, _device)) {
if (getQueuePresentSupport(familyIndex, surface, physicalDevice))
{
support |= QueueSupportFlagBits::ePresent;
}
queue_family_infos.push_back({
.index = family_index,
.count = qfp.queueCount,
.support = support,
queueFamilyInfos.push_back({
.m_Index = familyIndex,
.m_Count = qfp.queueCount,
.m_Support = support,
});
family_index++;
familyIndex++;
}
return queue_family_infos;
return queueFamilyInfos;
}
PhysicalDevice::PhysicalDevice(const Window *_window, vk::PhysicalDevice _physical_device) {
_physical_device.getProperties(&properties);
_physical_device.getFeatures(&features);
PhysicalDevice::PhysicalDevice(const vk::SurfaceKHR surface, const vk::PhysicalDevice physicalDevice)
{
physicalDevice.getProperties(&m_DeviceProperties);
physicalDevice.getFeatures(&m_DeviceFeatures);
surface_formats = get_surface_formats(_window, &_physical_device);
present_modes = get_present_modes(_window, &_physical_device);
queue_families = get_queue_families(_window, &_physical_device);
m_SurfaceFormats = getSurfaceFormats(surface, physicalDevice);
m_PresentModes = getSurfacePresentModes(surface, physicalDevice);
m_QueueFamilies = getQueueFamilies(surface, physicalDevice);
device = _physical_device;
m_PhysicalDevice = physicalDevice;
}
std::vector<vk::PhysicalDevice> 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;
}
}
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<vk::PhysicalDevice, 8>
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<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)
{
auto surface = window->m_Surface;
auto physicalDevices = enumeratePhysicalDevices(context->m_Instance);
for (auto physicalDevice : physicalDevices)
{
this->emplace_back(surface, physicalDevice);
}
}

View File

@ -7,8 +7,10 @@
#include "global.h"
#include "window.h"
#include <EASTL/fixed_vector.h>
enum class QueueSupportFlagBits {
enum class QueueSupportFlagBits
{
eGraphics = 0b0001,
eTransfer = 0b0010,
eCompute = 0b0100,
@ -17,24 +19,27 @@ enum class QueueSupportFlagBits {
using QueueSupportFlags = vk::Flags<QueueSupportFlagBits>;
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<vk::SurfaceFormatKHR> surface_formats;
std::vector<vk::PresentModeKHR> present_modes;
std::vector<QueueFamilyInfo> queue_families;
struct PhysicalDevice
{
vk::PhysicalDevice m_PhysicalDevice;
vk::PhysicalDeviceProperties m_DeviceProperties;
vk::PhysicalDeviceFeatures m_DeviceFeatures;
eastl::vector<vk::SurfaceFormatKHR> m_SurfaceFormats;
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> {
public:
PhysicalDevices(const Window *_window, const Context *_context);
class PhysicalDevices : public eastl::fixed_vector<PhysicalDevice, 4>
{
public:
PhysicalDevices(const Window *window, const Context *context);
};

View File

@ -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");
void
Window::SetWindowSize(const vk::Extent2D &extent) const noexcept
{
SetWindowSize(extent.width, extent.height);
}
i32 x_, y_, w_, h_;
glfwGetMonitorWorkarea(monitor, &x_, &y_, &w_, &h_);
void
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_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();
m_Window = glfwCreateWindow(cast<i32>(extent.width), cast<i32>(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 (full_screen == false) {
glfwSetWindowPos(window, (w_ - extent.width) / 2, (h_ - extent.height) / 2);
if (isFullScreen == false)
{
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_;
auto result = cast<vk::Result>(glfwCreateWindowSurface(cast<VkInstance>(_context->instance), window, nullptr, &surface_));
VkSurfaceKHR 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))
THEN_CRASH(result) ELSE_INFO("Surface Created");
surface = vk::SurfaceKHR(surface_);
THEN_ABORT(result)
ELSE_DEBUG("Surface {} Created", m_Name.c_str());
m_Surface = vk::SurfaceKHR(surface);
}
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;
}
Window::~Window() {
if (parent_context && surface) {
parent_context->instance.destroy(surface);
INFO("Surface Destroyed");
Window::~Window()
{
if (m_Context && m_Surface)
{
m_Context->m_Instance.destroy(m_Surface, nullptr);
DEBUG("Surface Destroyed");
}
if (window != nullptr) {
glfwDestroyWindow(window);
window = nullptr;
if (m_Window != nullptr)
{
glfwDestroyWindow(m_Window);
m_Window = nullptr;
}
monitor = nullptr;
INFO("Window '{}' Destroyed", name);
DEBUG("Window '{}' Destroyed", m_Name.c_str());
}

View File

@ -5,45 +5,31 @@
#pragma once
#include "global.h"
#include "context.h"
#include "global.h"
#include <EASTL/fixed_string.h>
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 });
}
struct Window final
{
// fields
Context *parent_context{};
Context *m_Context{};
GLFWwindow *window{ nullptr };
GLFWmonitor *monitor{ nullptr };
vk::SurfaceKHR surface;
vk::Extent2D extent;
std::string name;
b8 full_screen{ false };
GLFWwindow *m_Window = nullptr;
vk::SurfaceKHR m_Surface;
eastl::fixed_string<char, 32> m_Name;
// Methods
[[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,80 @@
#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;
[[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) {
for (auto &_physical_device : _physical_devices) {
if (is_suitable_device(&_physical_device)) {
return _physical_device;
PhysicalDevice
findSuitableDevice(const PhysicalDevices &physicalDevices)
{
for (auto &physicalDevice : physicalDevices)
{
if (isSuitableDevice(&physicalDevice))
{
return physicalDevice;
}
}
throw std::runtime_error("No suitable device found.");
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) {
QueueAllocation
findAppropriateQueueAllocation(const PhysicalDevice *physicalDevice)
{
for (auto &queueFamilyInfo : physicalDevice->m_QueueFamilies)
{
if ((queueFamilyInfo.m_Support & REQUIRED_QUEUE_SUPPORT) == REQUIRED_QUEUE_SUPPORT)
{
return {
.family = _queue_info.index,
.count = _queue_info.count,
.m_Family = queueFamilyInfo.m_Index,
.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 **) {
GlfwContext glfw_context = {};
int
main(int, char **)
{
GlfwContext glfwContext = {};
Context context = {"Aster", VERSION};
Window window = {"Aster1", &context, { 640, 480 }};
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);
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;

View File

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