//////////////////////////////// //~ Compiler flag checks #ifndef IsConsoleApp # error Missing compile time definition for 'IsConsoleApp' #endif #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 # 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: * 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 types #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; }; Struct(StringArray) { u64 count; String *strings; }; Struct(StringListNode) { String s; StringListNode *next; StringListNode *prev; }; Struct(StringList) { StringListNode *first; StringListNode *last; u64 count; }; //////////////////////////////// //~ Fiber id #if PlatformIsWindows # define FiberId *(i16 *)(void *)(volatile u64)__readgsqword(32) #else # error FiberId not implemented #endif #define MaxFibers 1024 StaticAssert(MaxFibers < I16Max); /* Fiber id type should fit max threads */ //////////////////////////////// //~ Exit callback types #define ExitFuncDef(name) void name(void) typedef ExitFuncDef(ExitFunc); //////////////////////////////// //~ @hookdecl Core hooks StringList GetCommandLineArgs(void); b32 Panic(String msg); b32 IsRunningInDebugger(void); void TrueRand(String buffer); void OnExit(ExitFunc *func); void SignalExit(i32 code); void ExitNow(i32 code); //////////////////////////////// //~ @hookdecl Layer initialization hook (defined by metaprogram) void StartupLayers(void); //////////////////////////////// //~ Prof #include "../prof/prof_tracy.h" //////////////////////////////// //~ Config #include "../config.h"