//////////////////////////////////////////////////////////// //~ Compiler flag checks #ifndef IsConsoleApp #error Missing compile time definition for 'IsConsoleApp' #endif #ifndef IsRtcEnabled #error Missing compile time definition for 'IsRtcEnabled' #endif #ifndef IsAsanEnabled #error Missing compile time definition for 'IsAsanEnabled' #endif #ifndef IsCrtlibEnabled #error Missing compile time definition for 'IsCrtlibEnabled' #endif #ifndef IsDebinfoEnabled #error Missing compile time definition for 'IsDebinfoEnabled' #endif #ifndef IsDeveloperModeEnabled #error Missing compile time definition for 'IsDeveloperModeEnabled' #endif #ifndef IsUnoptimized #error Missing compile time definition for 'IsUnoptimized' #endif #ifndef IsTestingEnabled #error Missing compile time definition for 'IsTestingEnabled' #endif #ifndef IsHotSwappingEnabled #error Missing compile time definition for 'IsHotSwappingEnabled' #endif //////////////////////////////////////////////////////////// //~ Machine context //- Compiler #if defined(__clang__) #define IsCompilerClang 1 #define IsCompilerMsvc 0 #elif defined(_MSC_VER) #define IsCompilerClang 0 #define IsCompilerMsvc 1 #else #error Unknown compiler #endif //- Language #if defined(__HLSL_VERSION) #define IsLanguageC 0 #define IsLanguageG 1 #else #define IsLanguageC 1 #define IsLanguageG 0 #endif //- Platform system #if defined(_WIN32) #define IsPlatformWindows 1 #define IsPlatformMac 0 #define IsPlatformLinux 0 #elif defined(__APPLE__) && defined(__MACH__) #define IsPlatformWindows 0 #define IsPlatformMac 1 #define IsPlatformLinux 0 #elif defined(__gnu_linux__) #define IsPlatformWindows 0 #define IsPlatformMac 0 #define IsPlatformLinux 1 #elif IsLanguageG #define IsPlatformWindows 0 #define IsPlatformMac 0 #define IsPlatformLinux 0 #else #error Unknown platform #endif //- Architecture #if defined(_M_AMD64) || defined(__amd64__) #define IsArchX64 1 #define IsArchArm64 0 #elif defined(_M_ARM64) || defined(__aarch64__) #define IsArchX64 0 #define IsArchArm64 1 #elif IsLanguageG #define IsArchX64 0 #define IsArchArm64 0 #else #error Unknown architecture #endif //- Cache line size /* TODO: Just hard-code to something like 128 or 256 if Apple silicon is ever supported */ #define CachelineSize 64 //- Windows NTDDI version /* TODO: Remove this */ #if 0 #if IsCompilerMsvc #define NTDDI_WIN11_DT 0x0C0A0000 #define NTDDI_VERSION 0x0A000000 #if IsRtcEnabled #define _ALLOW_RTCc_IN_STL 1 #endif #endif #endif //////////////////////////////////////////////////////////// //~ C headers #if IsLanguageC #include #include #endif //////////////////////////////////////////////////////////// //~ Debug //- Static assert #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__) //- Debug assert #if IsRtcEnabled #if IsCompilerMsvc #define Assert(cond) ((cond) ? 1 : (IsRunningInDebugger() ? (*(volatile i32 *)0 = 0) : Panic(Lit(__FILE__ ":" Stringize(__LINE__) ":0: assertion failed: "#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; __DEBUGBREAKABLE_VAR; } (void)0 #else #define Assert(cond) (void)(0) #endif //- Address sanitization #if IsAsanEnabled 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 IsLanguageC #define ZI { 0 } #else #define ZI { } #endif //- Inline #define Inline static inline #if IsCompilerMsvc #define ForceInline Inline __forceinline #else #define ForceInline Inline __attribute((always_inline)) #endif #if IsCompilerMsvc #define ForceNoInline __declspec(noinline) #else #define ForceNoInline __attribute__((noinline)) #endif //- Static #define PERSIST static #define Global static //- Read-only #if IsPlatformWindows #if IsCompilerMsvc #pragma section(".rdata$", read) #define Readonly __declspec(allocate(".rdata$")) #else #define Readonly __declspec(allocate(".rdata$")) #endif #elif IsPlatformMac #define Readonly __attribute((section("__TEXT,__const"))) #else #define Readonly __attribute((section(".rodata"))) #endif //- Thread-local #if IsCompilerMsvc #define ThreadLocal __declspec(thread) #endif //- Compiler memory barriers #if IsCompilerMsvc #define CompilerBarrier() _ReadWriteBarrier() #elif IsArchX64 #define CompilerBarrier() __asm__ volatile("" ::: "memory") #endif //- Fallthrough #if IsCompilerClang #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 stack (first & next pointers) #define SllStackPushN(f,n,next) ((n)->next=(f), (f)=(n)) #define SllStackPopN(f,next) ((f)=(f)->next) #define SllStackPush(f,n) SllStackPushN(f,n,next) #define SllStackPop(f) SllStackPopN(f,next) //- Singly linked queue (first, last, & next pointers) #define SllQueuePushNZ(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 SllQueuePushFrontNZ(nil,f,l,n,next) \ ( \ CheckNil(nil,f) ? \ ((f)=(l)=(n),SetNil(nil,(n)->next)) : \ ((n)->next=(f),(f)=(n)) \ ) #define SllQueuePopNZ(nil,f,l,next) \ ( \ (f)==(l) ? \ (SetNil(nil,f),SetNil(nil,l)) : \ ((f)=(f)->next) \ ) #define SllQueuePushN(f,l,n,next) SllQueuePushNZ(0,f,l,n,next) #define SllQueuePush(f,l,n) SllQueuePushNZ(0,f,l,n,next) #define SllQueuePushFrontN(f,l,n,next) SllQueuePushFrontNZ(0,f,l,n,next) #define SllQueuePushFront(f,l,n) SllQueuePushFrontNZ(0,f,l,n,next) #define SllQueuePopN(f,l,next) SllQueuePopNZ(0,f,l,next) #define SllQueuePop(f,l) SllQueuePopNZ(0,f,l,next) //- Doubly linked stack (first, next, & prev pointers) #define DllStackPushNPZ(nil,f,n,next,prev) \ ( \ SetNil(nil,(n)->prev), \ ((n)->next = (f)), \ CheckNil(nil,f) ? (0) : ((f)->prev = (n)), \ ((f) = (n)) \ ) #define DllStackInsertNPZ(nil,f,p,n,next,prev) \ ( \ (CheckNil(nil,f) || CheckNil(nil,p)) ? (DllStackPushNPZ(nil,(f),(n),next,prev)) : \ ( \ ((n)->prev = (p)), \ ((n)->next = (p)->next), \ ((p)->next = (n)), \ CheckNil(nil,(p)->next) ? (0) : ((p)->next->prev = (n)) \ ) \ ) #define DllStackRemoveNPZ(nil,f,n,next,prev) \ ( \ ((n) == (f) ? ((f) = (n)->next) : (0)), \ (CheckNil(nil,(n)->next) ? (0) : ((n)->next->prev = (n)->prev)), \ (CheckNil(nil,(n)->prev) ? (0) : ((n)->prev->next = (n)->next)) \ ) #define DllStackPushNP(f,n,next,prev) DllStackPushNPZ(0,f,n,next,prev) #define DllStackPush(f,n) DllStackPushNPZ(0,f,n,next,prev) #define DllStackInsertNP(f,p,n,next,prev) DllStackInsertNPZ(0,f,p,n,next,prev) #define DllStackInsert(f,p,n) DllStackInsertNPZ(0,f,p,n,next,prev) #define DllStackRemoveNP(f,n,next,prev) DllStackRemoveNPZ(0,f,n,next,prev) #define DllStackRemove(f,n) DllStackRemoveNPZ(0,f,n,next,prev) //- Doubly linked queue (first, last, next, & prev pointers) #define DllQueueInsertNPZ(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 DllQueueRemoveNPZ(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 DllQueuePushNPZ(nil,f,l,n,next,prev) DllQueueInsertNPZ(nil,f,l,l,n,next,prev) #define DllQueuePushNP(f,l,n,next,prev) DllQueuePushNPZ(0,f,l,n,next,prev) #define DllQueuePush(f,l,n) DllQueuePushNPZ(0,f,l,n,next,prev) #define DllQueuePushFrontNPZ(nil,f,l,n,next,prev) DllQueueInsertNPZ(nil,l,f,f,n,prev,next) #define DllQueuePushFrontNP(f,l,n,next,prev) DllQueuePushFrontNPZ(0,f,l,n,next,prev) #define DllQueuePushFront(f,l,n) DllQueuePushFrontNPZ(0,f,l,n,next,prev) #define DllQueueInsertNP(f,l,p,n,next,prev) DllQueueInsertNPZ(0,f,l,p,n,next,prev) #define DllQueueInsert(f,l,p,n) DllQueueInsertNPZ(0,f,l,p,n,next,prev) #define DllQueueRemoveNP(f,l,n,next,prev) DllQueueRemoveNPZ(0,f,l,n,next,prev) #define DllQueueRemove(f,l,n) DllQueueRemoveNPZ(0,f,l,n,next,prev) //////////////////////////////////////////////////////////// //~ Bit helper macros #define AllBits(a, b) (((a) & (b)) == (b)) #define AnyBit(a, b) (((a) & (b)) != 0) //////////////////////////////////////////////////////////// //~ Color helper macros #define Rgba32(v) Vec4FromU32((u32)(v)) #define Rgb32(v) Vec4FromU32((u32)(v) | (0xFF << 24)) // #define Bgr32(rgb) ((((rgb >> 0) & 0xFF) << 16) | (((rgb >> 8) & 0xFF) << 8) | (((rgb >> 16) & 0xFF) << 0)) #define Rgba(r, g, b, a) VEC4((r), (g), (b), (a)) #define Rgb(r, g, b) VEC4((r), (g), (b), 1) #define Color_White Rgba32(0xFFFFFFFF) #define Color_Black Rgba32(0xFF000000) #define Color_Red Rgba32(0xFF0000FF) #define Color_Green Rgba32(0xFF00FF00) #define Color_Blue Rgba32(0xFFFF0000) #define Color_Yellow Rgba32(0xFF00FFFF) #define Color_Orange Rgba32(0xFF00A5FF) #define Color_Purple Rgba32(0xFFFF00FF) #define Color_Cyan Rgba32(0xFFFFFF00) //////////////////////////////////////////////////////////// //~ Intrinsic headers #if IsLanguageC /* 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 #include /* 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 #define AlignedBlock(n) struct alignas(n) //- Enum #if IsLanguageC #define Enum(name) typedef enum name name; enum name #else #define Enum(name) enum name #endif //- alignof #if IsLanguageC && (IsCompilerMsvc || __STDC_VERSION__ < 202311L) #define alignof(type) __alignof(type) #endif //- field sizeof #define sizeof_field(type, field) sizeof(((type *)0)->field) //- countof #if IsLanguageC #define countof(a) (sizeof(a) / sizeof((a)[0])) #endif //- IsArray #define IsIndexable(a) (sizeof(a[0]) != 0) #define IsArray(a) (IsIndexable(a) && (((void *)&a) == ((void *)a))) //- offsetof #if !IsCompilerMsvc #ifdef _CRT_USE_BUILTIN_OFFSETOF #define offsetof(type, field) __builtin_offsetof(type, field) #else #define offsetof(type, field) ((u64)&(((type *)0)->field)) #endif #endif //- struct region #define BeginFieldRegion(name) i8 __begfieldreg__##name #define EndFieldRegion(name) i8 __endfieldreg__##name #define CopyFieldRegion(dst, src, r) CopyBytes(&dst->__begfieldreg__##r, &src->__begfieldreg__##r, (u8 *)&dst->__endfieldreg__##r - (u8 *)&dst->__begfieldreg__##r) #define ZeroFieldRegion(dst, src, r) ZeroBytes(&dst->__begfieldreg__##r, &src->__begfieldreg__##r, (u8 *)&dst->__endfieldreg__##r - (u8 *)&dst->__begfieldreg__##r) //- Packed #if IsCompilerMsvc #define Packed(s) __pragma(pack(push, 1)) s __pragma(pack(pop)) #elif IsCompilerClang #define Packed(s) s __attribute((__packed__)) #elif IsLanguageG #define Packed(s) s #endif //- alignas #if (IsCompilerMsvc && IsLanguageC) || (IsLanguageC && __STDC_VERSION__ < 202311L) #if IsCompilerMsvc #define alignas(n) __declspec(align(n)) #else #define alignas(n) __attribute__((aligned(n))) #endif #endif //////////////////////////////////////////////////////////// //~ Scalar types #if IsLanguageC 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; Struct(U128) { u64 hi; u64 lo; }; #elif IsLanguageG 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 IsLanguageC 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 IsLanguageC //- 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, CachelineSize) { Atomic8 v; }; AlignedStruct(Atomic16Padded, CachelineSize) { Atomic16 v; }; AlignedStruct(Atomic32Padded, CachelineSize) { Atomic32 v; }; AlignedStruct(Atomic64Padded, CachelineSize) { Atomic64 v; }; StaticAssert(alignof(Atomic8Padded) == CachelineSize && sizeof(Atomic8Padded) % CachelineSize == 0); StaticAssert(alignof(Atomic16Padded) == CachelineSize && sizeof(Atomic16Padded) % CachelineSize == 0); StaticAssert(alignof(Atomic32Padded) == CachelineSize && sizeof(Atomic32Padded) % CachelineSize == 0); StaticAssert(alignof(Atomic64Padded) == CachelineSize && sizeof(Atomic64Padded) % CachelineSize == 0); #if IsPlatformWindows && IsArchX64 //- 8 bit atomic ops ForceInline i8 Atomic8Fetch (Atomic8 *x) { CompilerBarrier(); i8 result = x->_v; CompilerBarrier(); return result; } ForceInline void Atomic8Set (Atomic8 *x, i8 e) { CompilerBarrier(); x->_v = e; CompilerBarrier(); } ForceInline i8 Atomic8FetchSet (Atomic8 *x, i8 e) { return (i8)_InterlockedExchange8((volatile char *)&x->_v, e); } ForceInline i8 Atomic8FetchTestSet (Atomic8 *x, i8 c, i8 e) { return (i8)_InterlockedCompareExchange8((volatile char *)&x->_v, e, c); } ForceInline i8 Atomic8FetchXor (Atomic8 *x, i8 c) { return (i8)_InterlockedXor8((volatile char *)&x->_v, c); } ForceInline i8 Atomic8FetchAdd (Atomic8 *x, i8 a) { return (i8)_InterlockedExchangeAdd8((volatile char *)&x->_v, a); } //- 16 bit atomic ops ForceInline i16 Atomic16Fetch (Atomic16 *x) { CompilerBarrier(); i16 result = x->_v; CompilerBarrier(); return result; } ForceInline void Atomic16Set (Atomic16 *x, i16 e) { CompilerBarrier(); x->_v = e; CompilerBarrier(); } 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 Atomic16FetchXor (Atomic16 *x, i16 c) { return (i16)_InterlockedXor16(&x->_v, c); } ForceInline i16 Atomic16FetchAdd (Atomic16 *x, i16 a) { return (i16)_InterlockedExchangeAdd16(&x->_v, a); } //- 32 bit atomic ops ForceInline i32 Atomic32Fetch (Atomic32 *x) { CompilerBarrier(); i32 result = x->_v; CompilerBarrier(); return result; } ForceInline void Atomic32Set (Atomic32 *x, i32 e) { CompilerBarrier(); x->_v = e; CompilerBarrier(); } 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 ops ForceInline i64 Atomic64Fetch (Atomic64 *x) { CompilerBarrier(); i64 result = x->_v; CompilerBarrier(); return result; } ForceInline void Atomic64Set (Atomic64 *x, i64 e) { CompilerBarrier(); x->_v = e; CompilerBarrier(); } 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 IsLanguageC 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) { /* TODO: Atomic set w/ known ticket + 1 */ Atomic64FetchAdd(&tm->serving.v, 1); } #endif //////////////////////////////////////////////////////////// //~ String types #if IsLanguageC #define STRING(size, data) ((String) { (size), (data) }) #define Zstr ((String) { 0, 0}) #define Lit(cstr_lit) (String) { (sizeof((cstr_lit)) - 1), (u8 *)(cstr_lit) } #define CompLit(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, ArenaFirst(arena, u8))) /* 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; }; #endif //////////////////////////////////////////////////////////// //~ Arena types #if IsLanguageC Struct(Arena) { u64 pos; u64 committed; u64 reserved; }; Struct(TempArena) { Arena *arena; u64 start_pos; }; #endif //////////////////////////////////////////////////////////// //~ Resource types #if IsLanguageC #define ResourceEmbeddedMagic 0xfc060937194f4406 Struct(ResourceStore) { u64 v; }; Struct(ResourceKey) { u64 v; }; #endif //////////////////////////////////////////////////////////// //~ Cpu topology types #if IsLanguageC Struct(CpuTopologyInfo) { i32 num_logical_cores; /* Includes P cores, Non-P cores, SMT siblings */ i32 num_physical_cores; /* Includes P Cores, Non-P Cores */ i32 num_physical_performance_cores; /* Includes P Cores */ i32 num_physical_non_performance_cores; /* Includes Non-P cores */ }; #endif //////////////////////////////////////////////////////////// //~ C <-> Shader interop types //- Shader linkage #if IsLanguageC Struct(VertexShader) { ResourceKey resource; }; Struct(PixelShader) { ResourceKey resource; }; Struct(ComputeShader) { ResourceKey resource; }; #elif IsLanguageG #define Semantic(t, n) t n : n #define ComputeShader(name, x) [numthreads(x, 1, 1)] void name(Semantic(u32, SV_DispatchThreadID)) #define ComputeShader2D(name, x, y) [numthreads(x, y, 1)] void name(Semantic(Vec2U32, SV_DispatchThreadID)) #define ComputeShader3D(name, x, y, z) [numthreads(x, y, z)] void name(Semantic(Vec3U32, SV_DispatchThreadID)) #define VertexShader(name, return_type) return_type name(Semantic(u32, SV_InstanceID), Semantic(u32, SV_VertexID)) #define PixelShader(name, return_type, ...) return_type name(__VA_ARGS__) #endif //- Shader resource handles Enum(ShaderHandleKind) { ShaderHandleKind_StructuredBuffer, ShaderHandleKind_RWStructuredBuffer, ShaderHandleKind_ByteAddressBuffer, ShaderHandleKind_RWByteAddressBuffer, ShaderHandleKind_Texture1D, ShaderHandleKind_RWTexture1D, ShaderHandleKind_Texture2D, ShaderHandleKind_RWTexture2D, ShaderHandleKind_Texture3D, ShaderHandleKind_RWTexture3D, ShaderHandleKind_SamplerState, }; Struct(StructuredBufferHandle) { u32 v; }; Struct(RWStructuredBufferHandle) { u32 v; }; Struct(ByteAddressBufferHandle) { u32 v; }; Struct(RWByteAddressBufferHandle) { u32 v; }; Struct(Texture1DHandle) { u32 v; }; Struct(RWTexture1DHandle) { u32 v; }; Struct(Texture2DHandle) { u32 v; }; Struct(RWTexture2DHandle) { u32 v; }; Struct(Texture3DHandle) { u32 v; }; Struct(RWTexture3DHandle) { u32 v; }; Struct(SamplerStateHandle) { u32 v; }; #define IsShaderHandleNil(h) ((h).v == 0) //- Shader constants /* * NOTE: D3d12 exposes 64 root constants, and vulkan 32 push constants. * Other constants past the max can be used by the graphics * implementation backend layer. */ #define NumGeneralPurposeShaderConstants (8) #if IsLanguageC #define ForceShaderConstant(type, name, slot) \ Enum(name##__shaderconstantenum) { name = slot }; \ Struct(name##__shaderconstanttype) { type v; } #define ShaderConstant(type, name, slot) \ StaticAssert(sizeof(type) <= 4); \ StaticAssert(slot < NumGeneralPurposeShaderConstants); \ ForceShaderConstant(type, name, slot) #elif IsLanguageG #define ForceShaderConstant(type, name, slot) cbuffer name : register(b##slot) { type name; } #define ShaderConstant(type, name, slot) ForceShaderConstant(type, name, slot) #endif //////////////////////////////////////////////////////////// //~ Exit callback types #if IsLanguageC #define ExitFuncDef(name) void name(void) typedef ExitFuncDef(ExitFunc); #endif //////////////////////////////////////////////////////////// //~ @hookdecl Core api #if IsLanguageC StringList GetRawCommandline(void); void Echo(String msg); b32 Panic(String msg); b32 IsRunningInDebugger(void); i64 TimeNs(void); void TrueRand(String buffer); CpuTopologyInfo GetCpuTopologyInfo(void); #endif //////////////////////////////////////////////////////////// //~ @hookdecl Swap #if IsLanguageC b32 IsSwappedIn(void); b32 IsSwappingOut(void); String SwappedStateFromName(Arena *arena, String name); void WriteSwappedState(String name, String data); #endif //////////////////////////////////////////////////////////// //~ @hookdecl Exit #if IsLanguageC void OnExit(ExitFunc *func); void SignalExit(i32 code); void ExitNow(i32 code); #endif //////////////////////////////////////////////////////////// //~ @hookdecl Bootstrap layers #if IsLanguageC void BootstrapLayers(void); #endif //////////////////////////////////////////////////////////// //~ Config #include "../config.h"