866 lines
28 KiB
C
866 lines
28 KiB
C
////////////////////////////////////////////////////////////
|
|
//~ 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 HotSwappingIsEnabled
|
|
# error Missing compile time definition for 'HotSwappingIsEnabled'
|
|
#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
|
|
|
|
//- Architecture
|
|
# if defined(_M_AMD64) || defined(__amd64__)
|
|
# define ArchIsX64 1
|
|
# define ArchIsArm64 0
|
|
# elif defined(_M_ARM64) || defined(__aarch64__)
|
|
# define ArchIsX64 0
|
|
# define ArchIsArm64 1
|
|
# elif LanguageIsGpu
|
|
# define ArchIsX64 0
|
|
# define ArchIsArm64 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 CompilerIsMsvc
|
|
# define NTDDI_WIN11_DT 0x0C0A0000
|
|
# define NTDDI_VERSION 0x0A000000
|
|
# if RtcIsEnabled
|
|
# define _ALLOW_RTCc_IN_STL 1
|
|
# endif
|
|
#endif
|
|
#endif
|
|
|
|
////////////////////////////////////////////////////////////
|
|
//~ Platform headers
|
|
|
|
//- Windows headers
|
|
#if PlatformIsWindows
|
|
# define COBJMACROS
|
|
# define WIN32_LEAN_AND_MEAN
|
|
# define UNICODE
|
|
# pragma warning(push, 0)
|
|
# include <Windows.h>
|
|
# include <combaseapi.h>
|
|
# include <dcommon.h>
|
|
# include <initguid.h>
|
|
# include <unknwn.h>
|
|
# include <objbase.h>
|
|
# include <uuids.h>
|
|
# include <Knownfolders.h>
|
|
# pragma warning(pop)
|
|
#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 RtcIsEnabled
|
|
# if CompilerIsMsvc
|
|
# 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; 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 PERSIST static
|
|
#define Global 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 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 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
|
|
#define AlignedBlock(n) struct alignas(n)
|
|
|
|
//- Enum
|
|
#if LanguageIsC
|
|
# define Enum(name) typedef enum name name; enum name
|
|
#else
|
|
# define Enum(name) enum name
|
|
#endif
|
|
|
|
//- alignof
|
|
#if LanguageIsC && (CompilerIsMsvc || __STDC_VERSION__ < 202311L)
|
|
# define alignof(type) __alignof(type)
|
|
#endif
|
|
|
|
//- field sizeof
|
|
#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 !CompilerIsMsvc
|
|
# 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 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
|
|
|
|
|
|
////////////////////////////////////////////////////////////
|
|
//~ 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;
|
|
|
|
#elif LanguageIsGpu
|
|
|
|
//- Gpu scalar types
|
|
typedef int i32;
|
|
typedef int2 i64;
|
|
typedef uint u32;
|
|
typedef uint2 u64;
|
|
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, 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 PlatformIsWindows && ArchIsX64
|
|
//- Memory barriers
|
|
# define CompilerMemoryBarrier() _ReadWriteBarrier()
|
|
# define HardwareMemoryBarrier() MemoryBarrier()
|
|
//- 8 bit atomic operations
|
|
ForceInline i8 Atomic8Fetch (Atomic8 *x) { i8 result = (x)->_v; CompilerMemoryBarrier(); return result; }
|
|
ForceInline void Atomic8Set (Atomic8 *x, i8 e) { CompilerMemoryBarrier(); (x)->_v = e; }
|
|
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 operations
|
|
ForceInline i16 Atomic16Fetch (Atomic16 *x) { i16 result = (x)->_v; CompilerMemoryBarrier(); return result; }
|
|
ForceInline void Atomic16Set (Atomic16 *x, i16 e) { CompilerMemoryBarrier(); (x)->_v = e; }
|
|
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 operations
|
|
ForceInline i32 Atomic32Fetch (Atomic32 *x) { i32 result = (x)->_v; CompilerMemoryBarrier(); return result; }
|
|
ForceInline void Atomic32Set (Atomic32 *x, i32 e) { CompilerMemoryBarrier(); (x)->_v = e; }
|
|
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) { i64 result = (x)->_v; CompilerMemoryBarrier(); return result; }
|
|
ForceInline void Atomic64Set (Atomic64 *x, i64 e) { CompilerMemoryBarrier(); (x)->_v = e; }
|
|
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)
|
|
{
|
|
/* TODO: Atomic set w/ known ticket + 1 */
|
|
Atomic64FetchAdd(&tm->serving.v, 1);
|
|
}
|
|
#endif
|
|
|
|
////////////////////////////////////////////////////////////
|
|
//~ String types
|
|
|
|
#if LanguageIsC
|
|
|
|
#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, 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;
|
|
};
|
|
|
|
#endif
|
|
|
|
////////////////////////////////////////////////////////////
|
|
//~ U128 types
|
|
|
|
Struct(U128)
|
|
{
|
|
u64 hi;
|
|
u64 lo;
|
|
};
|
|
|
|
////////////////////////////////////////////////////////////
|
|
//~ Resource types
|
|
|
|
#if LanguageIsC
|
|
|
|
#define ResourceEmbeddedMagic 0xfc060937194f4406
|
|
|
|
Struct(ResourceStore)
|
|
{
|
|
u64 hash;
|
|
};
|
|
|
|
Struct(ResourceKey)
|
|
{
|
|
u64 hash;
|
|
};
|
|
|
|
#endif
|
|
|
|
////////////////////////////////////////////////////////////
|
|
//~ Shader types
|
|
|
|
#if LanguageIsC
|
|
|
|
|
|
Struct(VertexShader) { ResourceKey resource; };
|
|
Struct(PixelShader) { ResourceKey resource; };
|
|
Struct(ComputeShader) { ResourceKey resource; };
|
|
|
|
# define VSDecl(name) extern VertexShader name;
|
|
# define PSDecl(name) extern PixelShader name;
|
|
# define CSDecl(name) extern ComputeShader name;
|
|
|
|
//- Resource descriptor index types
|
|
Struct(StructuredBufferRid) { u32 v; };
|
|
Struct(RWStructuredBufferRid) { u32 v; };
|
|
Struct(Texture1DRid) { u32 v; };
|
|
Struct(Texture2DRid) { u32 v; };
|
|
Struct(Texture3DRid) { u32 v; };
|
|
Struct(RWTexture1DRid) { u32 v; };
|
|
Struct(RWTexture2DRid) { u32 v; };
|
|
Struct(RWTexture3DRid) { u32 v; };
|
|
Struct(SamplerStateRid) { u32 v; };
|
|
|
|
#elif LanguageIsGpu
|
|
|
|
//- Resource descriptor index types
|
|
typedef uint StructuredBufferRid;
|
|
typedef uint RWStructuredBufferRid;
|
|
typedef uint Texture1DRid;
|
|
typedef uint Texture2DRid;
|
|
typedef uint Texture3DRid;
|
|
typedef uint RWTexture1DRid;
|
|
typedef uint RWTexture2DRid;
|
|
typedef uint RWTexture3DRid;
|
|
typedef uint SamplerStateRid;
|
|
|
|
//- Shader declaration
|
|
# define VSDecl(name)
|
|
# define PSDecl(name)
|
|
# define CSDecl(name)
|
|
|
|
# define VSDef(name, ...) name(__VA_ARGS__)
|
|
# define PSDef(name, ...) name(__VA_ARGS__)
|
|
# define CSDef(name, ...) name(__VA_ARGS__)
|
|
|
|
//- Semantic declaration
|
|
# define Semantic(t, n) t n : n
|
|
|
|
//- Descriptor heap index
|
|
# define UniformResourceFromRid(rid) ResourceDescriptorHeap[rid]
|
|
# define UniformSamplerFromRid(rid) SamplerDescriptorHeap[rid]
|
|
# define NonUniformResourceFromRid(rid) ResourceDescriptorHeap[NonUniformResourceIndex(rid)]
|
|
# define NonUniformSamplerFromRid(rid) SamplerDescriptorHeap[NonUniformResourceIndex(rid)]
|
|
|
|
#endif
|
|
|
|
////////////////////////////////////////////////////////////
|
|
//~ Fibers
|
|
|
|
# define MaxFibers 4096
|
|
StaticAssert(MaxFibers < I16Max); /* MaxFibers should fit in FiberId */
|
|
|
|
#if LanguageIsC
|
|
# if PlatformIsWindows
|
|
# define FiberId() (*(volatile i16 *)__readgsqword(0x20))
|
|
# else
|
|
# error FiberId not implemented
|
|
# endif
|
|
#endif
|
|
|
|
////////////////////////////////////////////////////////////
|
|
//~ Exit callback types
|
|
|
|
#if LanguageIsC
|
|
# define ExitFuncDef(name) void name(void)
|
|
typedef ExitFuncDef(ExitFunc);
|
|
#endif
|
|
|
|
////////////////////////////////////////////////////////////
|
|
//~ @hookdecl Api hooks
|
|
|
|
#if LanguageIsC
|
|
|
|
//- Core hooks
|
|
StringList GetRawCommandline(void);
|
|
void Echo(String msg);
|
|
b32 Panic(String msg);
|
|
b32 IsRunningInDebugger(void);
|
|
i64 TimeNs(void);
|
|
u32 GetNumHardwareThreads(void);
|
|
void TrueRand(String buffer);
|
|
void OnExit(ExitFunc *func);
|
|
void SignalExit(i32 code);
|
|
void ExitNow(i32 code);
|
|
|
|
//- Meta hooks
|
|
void StartupLayers(void);
|
|
|
|
#endif
|
|
|
|
////////////////////////////////////////////////////////////
|
|
//~ Config
|
|
|
|
#include "../config.h"
|