power_play/src/base/base_core.h
2025-08-24 20:43:08 -05:00

654 lines
20 KiB
C

////////////////////////////////
//~ Compiler flag checks
#ifndef RtcIsEnabled
# error Missing compile time definition for 'RtcIsEnabled'
#endif
#ifndef AsanIsEnabled
# error Missing compile time definition for 'AsanIsEnabled'
#endif
#ifndef CrtlibIsEnabled
# error Missing compile time definition for 'CrtlibIsEnabled'
#endif
#ifndef DebinfoEnabled
# error Missing compile time definition for 'DebinfoEnabled'
#endif
#ifndef DeveloperIsEnabled
# error Missing compile time definition for 'DeveloperIsEnabled'
#endif
#ifndef ProfilingIsEnabled
# error Missing compile time definition for 'ProfilingIsEnabled'
#endif
#ifndef UnoptimizedIsEnabled
# error Missing compile time definition for 'UnoptimizedIsEnabled'
#endif
#ifndef TestsAreEnabled
# error Missing compile time definition for 'TestsAreEnabled'
#endif
#ifndef IncbinRawDir
# error Missing compile time definition for 'IncbinRawDir'
#else
# define IncbinDir Stringize(IncbinRawDir)
#endif
////////////////////////////////
//~ Machine context
//- Compiler
#if defined(__clang__)
# define CompilerIsClang 1
# define CompilerIsMsvc 0
#elif defined(_MSC_VER)
# define CompilerIsClang 0
# define CompilerIsMsvc 1
#else
# error Unknown compiler
#endif
//- Language
#if defined(__HLSL_VERSION)
# define LanguageIsC 0
# define LanguageIsGpu 1
#else
# define LanguageIsC 1
# define LanguageIsGpu 0
#endif
//- Platform system
#if defined(_WIN32)
# define PlatformIsWindows 1
# define PlatformIsMac 0
# define PlatformIsLinux 0
#elif defined(__APPLE__) && defined(__MACH__)
# define PlatformIsWindows 0
# define PlatformIsMac 1
# define PlatformIsLinux 0
#elif defined(__gnu_linux__)
# define PlatformIsWindows 0
# define PlatformIsMac 0
# define PlatformIsLinux 1
#elif LanguageIsGpu
# define PlatformIsWindows 0
# define PlatformIsMac 0
# define PlatformIsLinux 0
#else
# error Unknown platform
#endif
//- Windows NTDDI version
/* FIXME: Remove this */
#if 0
#if CompilerIsMsvc
# define NTDDI_WIN11_DT 0x0C0A0000
# define NTDDI_VERSION 0x0A000000
# if RtcIsEnabled
# define _ALLOW_RTCc_IN_STL 1
# endif
#endif
#endif
//- Windows defines
#if PlatformIsWindows
# define COBJMACROS
# define WIN32_LEAN_AND_MEAN
# define UNICODE
# pragma warning(push, 0)
# include <Windows.h>
# pragma warning(pop)
#endif
////////////////////////////////
//~ Debug
//- Static assert
#if LanguageIsC
# define StaticAssert2(cond, line, counter) struct STATIC_ASSERT_____##line##counter {int foo[(cond) ? 1 : -1];}
# define StaticAssert1(cond, line, counter) StaticAssert2(cond, line, counter)
# define StaticAssert(cond) StaticAssert1(cond, __LINE__, __COUNTER__)
#else
# define StaticAssert(cond) static_assert(cond, "")
#endif
//- Debug assert
#if RtcIsEnabled
# if CompilerIsMsvc
// # define Assert(cond) ((cond) ? 1 : (IsRunningInDebugger() ? (*(volatile i32 *)0 = 0) : Panic(Lit("Assert(" #cond ") failed at " __FILE__ ":" Stringize(__LINE__)))))
# define Assert(cond) ((cond) ? 1 : (IsRunningInDebugger() ? (*(volatile i32 *)0 = 0) : Panic(Lit(__FILE__ "(" Stringize(__LINE__) "): error Assert("#cond")"))))
# define DEBUGBREAK __debugbreak
# else
# define Assert(cond) ((cond) ? 1 : (__builtin_trap(), 0))
# define DEBUGBREAK __builtin_debugtrap()
# endif
# define DEBUGBREAKABLE { volatile i32 __DEBUGBREAKABLE_VAR = 0; LAX __DEBUGBREAKABLE_VAR; } (void)0
#else
# define Assert(cond) (void)(0)
#endif
//- Root constant assert
#define AssertRootConst(s, n) StaticAssert((sizeof(s) % 16 == 0) && /* Root constant struct should pad to 16 byte alignment */ \
((sizeof(s) / 4) == n) && /* Root constant struct size should match the specified 32-bit-constant count */ \
(sizeof(s) <= 256)) /* Root constant struct can only fit 64 DWORDS */
//- Debug alias
/* TODO: Remove this */
#if CompilerIsMsvc
# if DebinfoEnabled
# define DebugAlias(var, alias) *(alias) = &(var)
# else
# define DebugAlias(var, alias) *(alias) = &(var)
# endif
#else
# if DebinfoEnabled
# define DebugAlias(var, alias) __attribute((used)) *(alias) = &(var)
# else
# define DebugAlias(var, alias) __attribute((unused)) *(alias) = &(var)
# endif
#endif
//- Address sanitization
#if AsanIsEnabled
void __asan_poison_memory_region(void const volatile *, size_t);
void __asan_unpoison_memory_region(void const volatile *add, size_t);
# define AsanPoison(addr, size) __asan_poison_memory_region((addr), (size))
# define AsanUnpoison(addr, size) __asan_unpoison_memory_region((addr), (size))
#else
# define AsanPoison(addr, size)
# define AsanUnpoison(addr, size)
#endif
////////////////////////////////
//~ Common utility macros
//- ZeroStruct initialization macro
#if LanguageIsC
# define ZI { 0 }
#else
# define ZI { }
#endif
//- Inline
#define Inline static inline
#if CompilerIsMsvc
# define ForceInline Inline __forceinline
#else
# define ForceInline Inline __attribute((always_inline))
#endif
#if CompilerIsMsvc
# define ForceNoInline __declspec(noinline)
#else
# define ForceNoInline __attribute__((noinline))
#endif
//- Static
#define LocalPersist static
#define Global static
/* TODO: Remove this */
#define internal static
//- Read-only
#if PlatformIsWindows
# if CompilerIsMsvc
# pragma section(".rdata$", read)
# define Readonly __declspec(allocate(".rdata$"))
# else
# define Readonly __declspec(allocate(".rdata"))
# endif
#elif PlatformIsMac
# define Readonly __attribute((section("__TEXT,__const")))
#else
# define Readonly __attribute((section(".rodata")))
#endif
//- Barriers
#if CompilerIsMsvc
# define WriteBarrier() _WriteBarrier()
# define ReadBarrier() _ReadBarrier()
#elif defined(__x86_64) || defined(__i386__)
# define WriteBarrier() __asm__ volatile("" ::: "memory")
# define ReadBarrier() __asm__ volatile("" ::: "memory")
#elif LanguageIsGpu
# define WriteBarrier()
# define ReadBarrier()
#else
# error Memory barriers not implemented
#endif
//- Unused markup
/* Strict unused markup */
#if CompilerIsClang
# define UNUSED __attribute((unused))
#else
# define UNUSED
#endif
/* Relaxed unused markup */
#define LAX (void)
//- Fallthrough
#if CompilerIsClang
# define FALLTHROUGH __attribute((fallthrough))
#else
# define FALLTHROUGH
#endif
//- Preprocessor concatenation
#define Cat1(a, b) a ## b
#define Cat(a, b) Cat1(a, b)
//- Preprocessor stringization
#define Stringize1(x) #x
#define Stringize(x) Stringize1(x)
//- Sizes
#define Kibi(n) (n*1024ULL)
#define Mebi(n) (n*Kibi(1024ULL))
#define Gibi(n) (n*Mebi(1024ULL))
#define Tebi(n) (n*Gibi(1024ULL))
//- Time
#define NsFromSeconds(s) ((i64)((s) * 1000000000.0))
#define SecondsFromNs(ns) ((f64)(ns) / 1000000000.0)
////////////////////////////////
//~ Linked list helper macros
/* Taken from the rad debugger
* https://github.com/EpicGamesExt/raddebugger/blob/be5634c44867a2e31f6a109df5e574930992df01/src/base/base_core.h#L239
*/
#define CheckNil(nil,p) ((p) == 0 || (p) == nil)
#define SetNil(nil,p) ((p) = nil)
//- Singly linked list stack (first & next pointers)
#define SllStackPush_N(f,n,next) ((n)->next=(f), (f)=(n))
#define SllStackPop_N(f,next) ((f)=(f)->next)
#define SllStackPush(f,n) SllStackPush_N(f,n,next)
#define SllStackPop(f) SllStackPop_N(f,next)
//- Singly linked list queue (first, last, & next pointers)
#define SllQueuePush_NZ(nil,f,l,n,next) (CheckNil(nil,f)?\
((f)=(l)=(n),SetNil(nil,(n)->next)):\
((l)->next=(n),(l)=(n),SetNil(nil,(n)->next)))
#define SllQueuePushFront_NZ(nil,f,l,n,next) (CheckNil(nil,f)?\
((f)=(l)=(n),SetNil(nil,(n)->next)):\
((n)->next=(f),(f)=(n)))
#define SllQueuePop_NZ(nil,f,l,next) ((f)==(l)?\
(SetNil(nil,f),SetNil(nil,l)):\
((f)=(f)->next))
#define SllQueuePush_N(f,l,n,next) SllQueuePush_NZ(0,f,l,n,next)
#define SllQueuePushFront_N(f,l,n,next) SllQueuePushFront_NZ(0,f,l,n,next)
#define SllQueuePop_N(f,l,next) SllQueuePop_NZ(0,f,l,next)
#define SllQueuePush(f,l,n) SllQueuePush_NZ(0,f,l,n,next)
#define SllQueuePushFront(f,l,n) SllQueuePushFront_NZ(0,f,l,n,next)
#define SllQueuePop(f,l) SllQueuePop_NZ(0,f,l,next)
//- Doubly linked list (first, last, next, & prev pointers)
#define DllInsert_NPZ(nil,f,l,p,n,next,prev) (CheckNil(nil,f) ? \
((f) = (l) = (n), SetNil(nil,(n)->next), SetNil(nil,(n)->prev)) :\
CheckNil(nil,p) ? \
((n)->next = (f), (f)->prev = (n), (f) = (n), SetNil(nil,(n)->prev)) :\
((p)==(l)) ? \
((l)->next = (n), (n)->prev = (l), (l) = (n), SetNil(nil, (n)->next)) :\
(((!CheckNil(nil,p) && CheckNil(nil,(p)->next)) ? (0) : ((p)->next->prev = (n))), ((n)->next = (p)->next), ((p)->next = (n)), ((n)->prev = (p))))
#define DllPushBack_NPZ(nil,f,l,n,next,prev) DllInsert_NPZ(nil,f,l,l,n,next,prev)
#define DllPushFront_NPZ(nil,f,l,n,next,prev) DllInsert_NPZ(nil,l,f,f,n,prev,next)
#define DllRemove_NPZ(nil,f,l,n,next,prev) (((n) == (f) ? (f) = (n)->next : (0)),\
((n) == (l) ? (l) = (l)->prev : (0)),\
(CheckNil(nil,(n)->prev) ? (0) :\
((n)->prev->next = (n)->next)),\
(CheckNil(nil,(n)->next) ? (0) :\
((n)->next->prev = (n)->prev)))
#define DllInsert_NP(f,l,p,n,next,prev) DllInsert_NPZ(0,f,l,p,n,next,prev)
#define DllPushBack_NP(f,l,n,next,prev) DllPushBack_NPZ(0,f,l,n,next,prev)
#define DllPushFront_NP(f,l,n,next,prev) DllPushFront_NPZ(0,f,l,n,next,prev)
#define DllRemove_NP(f,l,n,next,prev) DllRemove_NPZ(0,f,l,n,next,prev)
#define DllInsert(f,l,p,n) DllInsert_NPZ(0,f,l,p,n,next,prev)
#define DllPushBack(f,l,n) DllPushBack_NPZ(0,f,l,n,next,prev)
#define DllPushFront(f,l,n) DllPushFront_NPZ(0,f,l,n,next,prev)
#define DllRemove(f,l,n) DllRemove_NPZ(0,f,l,n,next,prev)
////////////////////////////////
//~ Struct alignment / padding macros
//- Pack
#if CompilerIsMsvc
# define Packed(s) __pragma(pack(push, 1)) s __pragma(pack(pop))
#elif CompilerIsClang
# define Packed(s) s __attribute((__packed__))
#elif LanguageIsGpu
# define Packed(s) s
#endif
//- alignas
#if (CompilerIsMsvc && LanguageIsC) || (LanguageIsC && __STDC_VERSION__ < 202311L)
# if CompilerIsMsvc
# define alignas(n) __declspec(align(n))
# else
# define alignas(n) __attribute__((aligned(n)))
# endif
#endif
////////////////////////////////
//~ Color helper macros
//- Rgba 32 bit helpers
#define Rgb32(r, g, b) Rgba32((r), (g), (b), 0xFF)
#define Rgba32(r, g, b, a) (u32)((u32)(r) | ((u32)(g) << 8) | ((u32)(b) << 16) | ((u32)(a) << 24))
#define Bgr32(rgb) ((((rgb >> 0) & 0xFF) << 16) | (((rgb >> 8) & 0xFF) << 8) | (((rgb >> 16) & 0xFF) << 0))
//- Rgba 32 bit float float helpers
#define _Rgb32U8FromF(fl) ((u8)((fl * 255.0) + 0.5))
#define Rgba32F(r, g, b, a) Rgba32(_Rgb32U8FromF((r)), _Rgb32U8FromF((g)), _Rgb32U8FromF((b)), _Rgb32U8FromF((a)))
#define Rgb32F(r, g, b) Rgba32F((r), (g), (b), 1.f)
#define Alpha32F(color, a) ((color) & 0x00FFFFFF) | (_Rgb32U8FromF((a)) << 24)
//- Pre-defined colors
#define ColorWhite Rgb32(0xFF, 0xFF, 0xFF)
#define ColorBlack Rgb32(0x00, 0x00, 0x00)
#define ColorRed Rgb32(0xFF, 0x00, 0x00)
#define ColorGreen Rgb32(0x00, 0xFF, 0x00)
#define ColorBlue Rgb32(0x00, 0x00, 0xFF)
#define ColorYellow Rgb32(0xFF, 0xFF, 0x00)
#define ColorOrange Rgb32(0xFF, 0xA5, 0x00)
#define ColorPurple Rgb32(0xFF, 0x00, 0XFF)
////////////////////////////////
//~ Gpu helpers
#if LanguageIsGpu
//- Resource heap index
# define GpuResourceFromUrid(urid) ResourceDescriptorHeap[urid]
# define GpuResourceFromNurid(nurid) ResourceDescriptorHeap[NonUniformResourceIndex(nurid)]
//- Semantic declaration
# define Semantic(t, n) t n : n
#endif
////////////////////////////////
//~ Intrinsic headers
#if LanguageIsC
/* Intrinsic header info:
* <mmintrin.h" MMX
* <xmmintrin.h" SSE
* <emmintrin.h" SSE2
* <pmmintrin.h" SSE3
* <tmmintrin.h" SSSE3
* <smmintrin.h" SSE4.1
* <nmmintrin.h" SSE4.2
* <ammintrin.h" SSE4A
* <wmmintrin.h" AES
* <immintrin.h" AVX, AVX2, FMA
*/
#include "intrin.h"
#include "nmmintrin.h" /* SSE4.2 */
#endif
////////////////////////////////
//~ Type helper macros
//- Struct
#define Struct(name) typedef struct name name; struct name
#define AlignedStruct(name, n) typedef struct name name; struct alignas(n) name
//- Enum
#define Enum(name) typedef enum name name; enum name
//- alignof
#if LanguageIsC && (CompilerIsMsvc || __STDC_VERSION__ < 202311L)
# define alignof(type) __alignof(type)
#endif
//- sizeof_field
#define sizeof_field(type, field) sizeof(((type *)0)->field)
//- countof
#define countof(a) (sizeof(a) / sizeof((a)[0]))
//- IsArray
#define IsIndexable(a) (sizeof(a[0]) != 0)
#define IsArray(a) (IsIndexable(a) && (((void *)&a) == ((void *)a)))
//- offsetof
#if 0
#if !CompilerIsMsvc
# if !defined _CRT_USE_BUILTIN_OFFSETOF
# define offsetof(type, field) ((u64)&(((type *)0)->field))
# else
# define offsetof(type, field) __builtin_offsetof(type, field)
# endif
#endif
#endif
////////////////////////////////
//~ Scalar types
#if LanguageIsC
//- Cpu scalar types
#include "stdint.h"
typedef int8_t i8;
typedef int16_t i16;
typedef int32_t i32;
typedef int64_t i64;
typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;
typedef uint64_t u64;
typedef float f32;
typedef double f64;
typedef i8 b8;
typedef u32 b32;
#else
//- Gpu scalar types
typedef int i32;
typedef uint u32;
typedef float f32;
typedef uint b32;
#endif
//- Min / max constants
#define U8Max (0xFF)
#define U16Max (0xFFFF)
#define U32Max (0xFFFFFFFF)
#define U64Max (0xFFFFFFFFFFFFFFFFULL)
#define I8Max (0x7F)
#define I16Max (0x7FFF)
#define I32Max (0x7FFFFFFF)
#define I64Max (0x7FFFFFFFFFFFFFFFLL)
#define I8Min ((i8)-0x80)
#define I16Min ((i16)0x8000)
#define I32Min ((i32)0x80000000)
#define I64Min ((i64)0x8000000000000000LL)
//- Float infinity / nan constants
#if LanguageIsC
Global const u32 _f32_infinity_u32 = 0x7f800000;
Global const f32 *_f32_infinity = (f32 *)&_f32_infinity_u32;
#define F32Infinity (*_f32_infinity)
Global const u64 _f64_infinity_u64 = 0x7ff0000000000000ULL;
Global const f64 *_f64_infinity = (f64 *)&_f64_infinity_u64;
#define F64Infinity (*_f64_infinity)
Global const u32 _f32_nan_u32 = 0x7f800001;
Global const f32 *_f32_nan = (f32 *)&_f32_nan_u32;
#define F32Nan (*_f32_nan)
Global const u64 _f64_nan_u64 = 0x7ff8000000000001;
Global const f64 *_f64_nan = (f64 *)&_f64_nan_u64;
#define F64Nan (*_f64_nan)
#define IsF32Nan(x) (x != x)
#define IsF64Nan(x) (x != x)
#endif
////////////////////////////////
//~ Atomics
#if LanguageIsC
//- Atomic types
Struct(Atomic8) { volatile i8 _v; };
Struct(Atomic16) { volatile i16 _v; };
Struct(Atomic32) { volatile i32 _v; };
Struct(Atomic64) { volatile i64 _v; };
//- Cache-line isolated aligned atomic types
AlignedStruct(Atomic8Padded, 64) { Atomic8 v; u8 _pad[63]; };
AlignedStruct(Atomic16Padded, 64) { Atomic16 v; u8 _pad[62]; };
AlignedStruct(Atomic32Padded, 64) { Atomic32 v; u8 _pad[60]; };
AlignedStruct(Atomic64Padded, 64) { Atomic64 v; u8 _pad[56]; };
StaticAssert(sizeof(Atomic8Padded) == 64 && alignof(Atomic8Padded) == 64);
StaticAssert(sizeof(Atomic16Padded) == 64 && alignof(Atomic16Padded) == 64);
StaticAssert(sizeof(Atomic32Padded) == 64 && alignof(Atomic32Padded) == 64);
StaticAssert(sizeof(Atomic64Padded) == 64 && alignof(Atomic64Padded) == 64);
#if PlatformIsWindows
//- 8 bit atomic operations
ForceInline i8 Atomic8Fetch(Atomic8 *x) { return (i8)_InterlockedCompareExchange8((char *)&x->_v, 0, 0); }
ForceInline i8 Atomic8FetchSet(Atomic8 *x, i8 e) { return (i8)_InterlockedExchange8((char *)&x->_v, e); }
ForceInline i8 Atomic8FetchTestSet(Atomic8 *x, i8 c, i8 e) { return (i8)_InterlockedCompareExchange8((char *)&x->_v, e, c); }
ForceInline i8 Atomic8FetchXor(Atomic8 *x, i8 c) { return (i8)_InterlockedXor8((char *)&x->_v, c); }
ForceInline i8 Atomic8FetchAdd(Atomic8 *x, i8 a) { return (i8)_InterlockedExchangeAdd8((char *)&x->_v, a); }
//- 16 bit atomic operations
ForceInline i16 Atomic16Fetch(Atomic16 *x) { return (i16)_InterlockedCompareExchange16(&x->_v, 0, 0); }
ForceInline i16 Atomic16FetchSet(Atomic16 *x, i16 e) { return (i16)_InterlockedExchange16(&x->_v, e); }
ForceInline i16 Atomic16FetchTestSet(Atomic16 *x, i16 c, i16 e) { return (i16)_InterlockedCompareExchange16(&x->_v, e, c); }
ForceInline i16 Atomic16FetchTestXor(Atomic16 *x, i16 c) { return (i16)_InterlockedXor16(&x->_v, c); }
ForceInline i16 Atomic16FetchTestAdd(Atomic16 *x, i16 a) { return (i16)_InterlockedExchangeAdd16(&x->_v, a); }
//- 32 bit atomic operations
ForceInline i32 Atomic32Fetch(Atomic32 *x) { return (i32)_InterlockedCompareExchange((volatile long *)&x->_v, 0, 0); }
ForceInline i32 Atomic32FetchSet(Atomic32 *x, i32 e) { return (i32)_InterlockedExchange((volatile long *)&x->_v, e); }
ForceInline i32 Atomic32FetchTestSet(Atomic32 *x, i32 c, i32 e) { return (i32)_InterlockedCompareExchange((volatile long *)&x->_v, e, c); }
ForceInline i32 Atomic32FetchXor(Atomic32 *x, i32 c) { return (i32)_InterlockedXor((volatile long *)&x->_v, c); }
ForceInline i32 Atomic32FetchAdd(Atomic32 *x, i32 a) { return (i32)_InterlockedExchangeAdd((volatile long *)&x->_v, a); }
//- 64 bit atomic operations
ForceInline i64 Atomic64Fetch(Atomic64 *x) { return (i64)_InterlockedCompareExchange64(&x->_v, 0, 0); }
ForceInline i64 Atomic64FetchSet(Atomic64 *x, i64 e) { return (i64)_InterlockedExchange64(&x->_v, e); }
ForceInline i64 Atomic64FetchTestSet(Atomic64 *x, i64 c, i64 e) { return (i64)_InterlockedCompareExchange64(&x->_v, e, c); }
ForceInline i64 Atomic64FetchXor(Atomic64 *x, i64 c) { return (i64)_InterlockedXor64(&x->_v, c); }
ForceInline i64 Atomic64FetchAdd(Atomic64 *x, i64 a) { return (i64)_InterlockedExchangeAdd64(&x->_v, a); }
#else
# error Atomics not implemented
#endif
#endif
////////////////////////////////
//~ Ticket mutex
#if LanguageIsC
Struct(TicketMutex)
{
Atomic64Padded ticket;
Atomic64Padded serving;
};
ForceInline void LockTicketMutex(TicketMutex *tm)
{
i64 ticket = Atomic64FetchAdd(&tm->ticket.v, 1);
while (Atomic64Fetch(&tm->serving.v) != ticket)
{
_mm_pause();
}
}
ForceInline void UnlockTicketMutex(TicketMutex *tm)
{
Atomic64FetchAdd(&tm->serving.v, 1);
}
#endif
////////////////////////////////
//~ String utils
#define STRING(size, data) ((String) { (size), (data) })
#define Lit(cstr_lit) (String) { (sizeof((cstr_lit)) - 1), (u8 *)(cstr_lit) }
#define LitNoCast(cstr_lit) { .len = (sizeof((cstr_lit)) - 1), .text = (u8 *)(cstr_lit) }
#define StringFromPointers(p0, p1) ((String) { (u8 *)(p1) - (u8 *)(p0), (u8 *)p0 })
#define StringFromStruct(ptr) ((String) { sizeof(*(ptr)), (u8 *)(ptr) })
#define StringFromArena(arena) (STRING((arena)->pos, ArenaBase(arena)))
/* String from static array */
#define StringFromArray(a) \
( \
Assert(IsArray(a)), \
((String) { .len = sizeof(a), .text = (u8 *)(a) }) \
)
Struct(String)
{
u64 len;
u8 *text;
};
Struct(String16)
{
u64 len;
u16 *text;
};
Struct(String32)
{
u64 len;
u32 *text;
};
////////////////////////////////
//~ Fibers
#define MaxFibers 1024
#if LanguageIsC
# if PlatformIsWindows
ForceInline i16 FiberId(void)
{
i16 *v = (void *)(u64)__readgsqword(32);
return *v;
}
# else
# error FiberId not implemented
# endif
StaticAssert(MaxFibers < I16Max); /* Fiber id type should fit max fibers */
#endif
////////////////////////////////
//~ @hookdecl Core hooks
void StartupBase(void);
b32 Panic(String msg);
b32 IsRunningInDebugger(void);
i16 ThreadId(void);
void TrueRand(String buffer);
#define MaxThreads 1024
StaticAssert(MaxThreads < I16Max); /* Thread id type should fit max threads */
////////////////////////////////
//~ @hookdecl Layer startup hook (defined by meta program)
void StartupLayers(void);
////////////////////////////////
//~ Prof
#include "../prof/prof_tracy.h"
////////////////////////////////
//~ Config
#include "../config.h"