power_play/src/base/base.cgh

833 lines
28 KiB
Plaintext

////////////////////////////////////////////////////////////
//~ 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 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
#ifndef DefaultAppName
#error Default application name not defined
#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
// C standard library
#include <stdint.h>
#include <stdarg.h>
#include <memory.h>
#include <math.h>
//- Intrinsics
#if IsArchX64
// Intrinsic headers:
// -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
#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
//- Zero initialization
#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)
//- Busy-wait
#if IsArchX64
#define YieldCpu()
#else
#endif
////////////////////////////////////////////////////////////
//~ 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)
////////////////////////////////////////////////////////////
//~ 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)
//- Union
#define Union(name) typedef union name name; union name
//- 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
//- IsFixedArray
#define IsIndexable(a) (sizeof(a[0]) != 0)
#define IsFixedArray(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;
#elif IsLanguageG
typedef int i32;
typedef int64_t i64;
typedef uint u32;
typedef uint64_t u64;
typedef float f32;
typedef bool b32; // bool has 32-bit size & alignment in HLSL
#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
#if IsLanguageC
#define Inf INFINITY
#define Nan NAN
#elif IsLanguageG
#define Inf (1.0 / 0.0)
#define Nan (0.0 / 0.0)
#endif
#define IsInf(x) isinf(x)
#define IsNan(x) isnan(x)
//- u128
#if IsLanguageC
Struct(u128) { u64 lo; u64 hi; };
#define U128(_hi, _lo) ((u128) { .hi = (_hi), .lo = (_lo) })
#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); }
#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 StringFromStructs(ptr, count) ((String) { sizeof(*(ptr)) * (count), (u8 *)(ptr) })
#define StringFromArena(arena) (STRING((arena)->pos, ArenaFirst(arena, u8)))
#define StringFromFixedArray(a) \
( \
Assert(IsFixedArray(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
////////////////////////////////////////////////////////////
//~ Debug types
#if IsLanguageC
Struct(Callstack)
{
u64 count;
void *frames[32];
};
#endif
////////////////////////////////////////////////////////////
//~ Shader linkage types
#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
////////////////////////////////////////////////////////////
//~ Exit callback types
#if IsLanguageC
#define ExitFuncDef(name) void name(void)
typedef ExitFuncDef(ExitFunc);
#endif
////////////////////////////////////////////////////////////
//~ Basic mixing/hashing
// Based on Jon Maiga's "mx3"
// https://jonkagstrom.com/mx3/mx3_rev2.html
u64 MixU64(u64 seed)
{
seed = (seed ^ (seed >> 32)) * 0xbea225f9eb34556d;
seed = (seed ^ (seed >> 29)) * 0xbea225f9eb34556d;
seed = (seed ^ (seed >> 32)) * 0xbea225f9eb34556d;
seed = (seed ^ (seed >> 29));
return seed;
}
u64 MixU64s(u64 seed_a, u64 seed_b)
{
return MixU64((seed_a * 3) + seed_b);
}
#if IsLanguageC
// FNV-1a parameters for different hash sizes:
// https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function#FNV_hash_parameters
Inline u64 HashFnv64(u64 seed, String s)
{
u64 hash = seed;
for (u64 i = 0; i < s.len; ++i)
{
hash ^= (u8)s.text[i];
hash *= 0x100000001B3;
}
return hash;
}
#endif
////////////////////////////////////////////////////////////
//~ @hookdecl Core api
#if IsLanguageC
StringList GetRawCommandline(void);
String GetAppDirectory(void);
void Echo(String msg);
b32 Panic(String msg);
Callstack CaptureCallstack(u64 skip_frames);
b32 IsRunningInDebugger(void);
i64 TimeNs(void);
void TrueRand(String buffer);
CpuTopologyInfo GetCpuTopologyInfo(void);
void SleepSeconds(f64 seconds);
#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"