313 lines
8.7 KiB
C++
313 lines
8.7 KiB
C++
// =============================================
|
|
// Aster: global.h
|
|
// Copyright (c) 2020-2025 Anish Bhobe
|
|
// =============================================
|
|
|
|
#pragma once
|
|
|
|
#include "config.h"
|
|
|
|
#include "constants.h"
|
|
|
|
#include "aster/util/logger.h"
|
|
|
|
#include <GLFW/glfw3.h>
|
|
#include <glm/glm.hpp>
|
|
|
|
#include <EASTL/shared_ptr.h>
|
|
#include <fmt/format.h>
|
|
|
|
// Macros that can collide with functions.
|
|
#if defined(max)
|
|
#undef max
|
|
#endif
|
|
|
|
#if defined(min)
|
|
#undef min
|
|
#endif
|
|
|
|
#if !defined(NDEBUG)
|
|
#define VULKAN_HPP_ASSERT(expr) DEBUG_IF(!(expr), "Vulkan assert failed")
|
|
#endif
|
|
|
|
#include "EASTL/intrusive_ptr.h"
|
|
#include "type_traits.h"
|
|
|
|
#include <EASTL/fixed_string.h>
|
|
#include <EASTL/string.h>
|
|
#include <vk_mem_alloc.h>
|
|
|
|
#include <vulkan/vulkan.hpp>
|
|
|
|
#define CODE_LOC " @ " __FILE__ ":" VULKAN_HPP_STRINGIFY(__LINE__)
|
|
|
|
#define DISALLOW_COPY_AND_ASSIGN(CLASS_NAME) \
|
|
CLASS_NAME(const CLASS_NAME &other) = delete; \
|
|
CLASS_NAME &operator=(const CLASS_NAME &other) = delete
|
|
|
|
#define PIN_MEMORY(CLASS_NAME) \
|
|
CLASS_NAME(const CLASS_NAME &other) = delete; \
|
|
CLASS_NAME(CLASS_NAME &&other) noexcept = delete; \
|
|
CLASS_NAME &operator=(const CLASS_NAME &other) = delete; \
|
|
CLASS_NAME &operator=(CLASS_NAME &&other) noexcept = delete
|
|
|
|
#define Take(ELEMENT) eastl::exchange(ELEMENT, {})
|
|
|
|
#define TODO(...) assert(!("Unimplemented: " __VA_ARGS__))
|
|
#define FIX(...) static_assert(!("Unimplemented: " __VA_ARGS__))
|
|
#define UNREACHABLE(...) assert(!("Unreachable: " __VA_ARGS__))
|
|
|
|
#define AbortIfFailed(RESULT) \
|
|
do \
|
|
{ \
|
|
vk::Result _checkResultValue_; \
|
|
ERROR_IF(Failed(_checkResultValue_ = static_cast<vk::Result>(RESULT)), "Cause: {}", _checkResultValue_) \
|
|
THEN_ABORT(_checkResultValue_); \
|
|
} while (false)
|
|
|
|
#define AbortIfFailedMV(RESULT, MSG, EXTRA) \
|
|
do \
|
|
{ \
|
|
vk::Result _checkResultValue_; \
|
|
ERROR_IF(Failed(_checkResultValue_ = static_cast<vk::Result>(RESULT)), MSG " Cause: {}", EXTRA, \
|
|
_checkResultValue_) \
|
|
THEN_ABORT(_checkResultValue_); \
|
|
} while (false)
|
|
|
|
#define AbortIfFailedM(RESULT, MSG) \
|
|
do \
|
|
{ \
|
|
auto _checkResultValue_ = static_cast<vk::Result>(RESULT); \
|
|
ERROR_IF(Failed(_checkResultValue_), MSG " Cause: {}", _checkResultValue_) THEN_ABORT(_checkResultValue_); \
|
|
} while (false)
|
|
|
|
[[nodiscard]] inline bool
|
|
Failed(vk::Result const result)
|
|
{
|
|
return result != vk::Result::eSuccess;
|
|
}
|
|
|
|
namespace aster::concepts
|
|
{
|
|
template <typename T>
|
|
concept VkHandle = vk::isVulkanHandleType<T>::value;
|
|
}
|
|
|
|
namespace aster
|
|
{
|
|
constexpr u32 ASTER_API_VERSION = VK_API_VERSION_1_3;
|
|
|
|
using NameString = eastl::fixed_string<char, 32, false>;
|
|
|
|
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 = {
|
|
.m_Major = 0,
|
|
.m_Minor = 1,
|
|
.m_Patch = 0,
|
|
};
|
|
|
|
constexpr u32
|
|
Kilobyte(u32 const in)
|
|
{
|
|
return in * 1024;
|
|
}
|
|
|
|
constexpr usize
|
|
Kilobyte(usize const in)
|
|
{
|
|
return in * 1024;
|
|
}
|
|
|
|
constexpr u32
|
|
Megabyte(u32 const in)
|
|
{
|
|
return in * 1024 * 1024;
|
|
}
|
|
|
|
constexpr usize
|
|
Megabyte(usize const in)
|
|
{
|
|
return in * 1024 * 1024;
|
|
}
|
|
|
|
constexpr usize
|
|
Gigabyte(usize const in)
|
|
{
|
|
return in * 1024 * 1024 * 1024;
|
|
}
|
|
|
|
template <typename T>
|
|
[[nodiscard]] usize
|
|
HashAny(T const &val)
|
|
{
|
|
return eastl::hash<std::remove_cvref_t<T>>()(val);
|
|
}
|
|
|
|
[[nodiscard]] inline usize
|
|
HashCombine(usize const hash0, usize const hash1)
|
|
{
|
|
constexpr usize saltValue = 0x9e3779b9;
|
|
usize const tempVar = hash1 + saltValue + (hash0 << 6) + (hash0 >> 2);
|
|
return hash0 ^ tempVar;
|
|
}
|
|
|
|
struct Time
|
|
{
|
|
static constexpr f64 MAX_DELTA = 0.1;
|
|
|
|
inline static f64 m_Elapsed{Qnan<f64>};
|
|
inline static f64 m_Delta{Qnan<f64>};
|
|
|
|
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(m_Elapsed), "Time not init.");
|
|
auto const newElapsed = glfwGetTime();
|
|
m_Delta = std::clamp(newElapsed - m_Elapsed, 0.0, MAX_DELTA);
|
|
m_Elapsed = newElapsed;
|
|
}
|
|
};
|
|
|
|
[[nodiscard]] constexpr usize
|
|
ClosestMultiple(usize const val, usize const of)
|
|
{
|
|
return of * ((val + of - 1) / of);
|
|
}
|
|
|
|
[[nodiscard]] constexpr u32
|
|
ClosestMultiple(u32 const val, u32 const of)
|
|
{
|
|
return of * ((val + of - 1) / of);
|
|
}
|
|
|
|
[[nodiscard]] constexpr bool
|
|
IsPowerOfTwo(usize const val)
|
|
{
|
|
return val && !(val & (val - 1));
|
|
}
|
|
|
|
[[nodiscard]] constexpr bool
|
|
IsPowerOfTwo(u32 const val)
|
|
{
|
|
return val && !(val & (val - 1));
|
|
}
|
|
|
|
[[nodiscard]] constexpr usize
|
|
ClosestLargerPowerOfTwo(usize val)
|
|
{
|
|
val--;
|
|
val |= val >> 1;
|
|
val |= val >> 2;
|
|
val |= val >> 4;
|
|
val |= val >> 8;
|
|
val |= val >> 16;
|
|
val |= val >> 32;
|
|
val++;
|
|
return val;
|
|
}
|
|
|
|
[[nodiscard]] constexpr usize
|
|
ClosestPowerOfTwo(usize const val)
|
|
{
|
|
usize const largerPo2 = ClosestLargerPowerOfTwo(val);
|
|
usize const smallerPo2 = largerPo2 >> 1;
|
|
return (smallerPo2 + largerPo2 <= (val << 1)) ? largerPo2 : smallerPo2;
|
|
}
|
|
|
|
[[nodiscard]] constexpr u32
|
|
ClosestLargerPowerOfTwo(u32 val)
|
|
{
|
|
val--;
|
|
val |= val >> 1;
|
|
val |= val >> 2;
|
|
val |= val >> 4;
|
|
val |= val >> 8;
|
|
val |= val >> 16;
|
|
val++;
|
|
return val;
|
|
}
|
|
|
|
[[nodiscard]] constexpr u32
|
|
ClosestPowerOfTwo(u32 const val)
|
|
{
|
|
u32 const largerPo2 = ClosestLargerPowerOfTwo(val);
|
|
u32 const smallerPo2 = largerPo2 >> 1;
|
|
return (smallerPo2 + largerPo2 <= (val << 1)) ? largerPo2 : smallerPo2;
|
|
}
|
|
|
|
[[nodiscard]] constexpr u32
|
|
GetMaskOffset(u32 val)
|
|
{
|
|
u32 count = 0;
|
|
while ((val & 1) == 0)
|
|
{
|
|
count++;
|
|
val = val >> 1;
|
|
}
|
|
return count;
|
|
}
|
|
|
|
template <typename T>
|
|
concept VkToString = requires(T a) {
|
|
{ vk::to_string(a) } -> std::convertible_to<std::string>;
|
|
};
|
|
|
|
template <typename T>
|
|
using Ref = eastl::shared_ptr<T>;
|
|
|
|
template <typename T>
|
|
using WeakRef = eastl::weak_ptr<T>;
|
|
} // namespace aster
|
|
|
|
template <aster::VkToString T>
|
|
struct fmt::formatter<T> : nested_formatter<std::string>
|
|
{
|
|
auto
|
|
// ReSharper disable once CppInconsistentNaming
|
|
format(T result, format_context &ctx) const
|
|
{
|
|
return write_padded(ctx,
|
|
[this, result](auto out) { return fmt::format_to(out, "{}", nested(to_string(result))); });
|
|
}
|
|
};
|
|
|
|
template <typename TType, aster::usize TCount, bool TOverflow>
|
|
struct fmt::formatter<eastl::fixed_string<TType, TCount, TOverflow>> : nested_formatter<aster::cstr>
|
|
{
|
|
auto
|
|
// ReSharper disable once CppInconsistentNaming
|
|
format(eastl::fixed_string<TType, TCount, TOverflow> const &str, format_context &ctx) const
|
|
{
|
|
return write_padded(ctx, [this, str](auto out) { return fmt::format_to(out, "{}", nested(str.c_str())); });
|
|
}
|
|
};
|
|
|
|
template <typename TFlagBits>
|
|
struct eastl::hash<vk::Flags<TFlagBits>> // NOLINT(*-dcl58-cpp)
|
|
{
|
|
[[nodiscard]] aster::usize
|
|
operator()(vk::Flags<TFlagBits> const &val)
|
|
{
|
|
return std::hash<aster::u32>()(static_cast<aster::u32>(val));
|
|
}
|
|
}; |