diff --git a/build.bat b/build.bat index 3363547e..952d6f4b 100644 --- a/build.bat +++ b/build.bat @@ -4,8 +4,9 @@ cd /D "%~dp0" if not exist build mkdir build pushd build +for %%a in (%*) do set "%%a=1" set program_build_cmd=meta.exe %* -set meta_build_cmd=cl.exe ../src/meta/meta.c /Od /Z7 /nologo /diagnostics:column /link /DEBUG:FULL /INCREMENTAL:NO +set meta_build_cmd=cl.exe ../src/meta/meta.c /Od /Z7 /nologo /diagnostics:column /WX /link /DEBUG:FULL /INCREMENTAL:NO set meta_rebuild_code=1317212284 ::- Meta build @@ -20,13 +21,15 @@ if not exist meta.exe ( ) ::- Program build -echo ======== Build ======== -%program_build_cmd% -set "rc=!errorlevel!" -if !rc! NEQ 0 ( - if !rc! EQU %meta_rebuild_code% ( - del meta.exe - goto meta_build +if not "%norun%"=="1" ( + echo ======== Build ======== + %program_build_cmd% + set "rc=!errorlevel!" + if !rc! NEQ 0 ( + if !rc! EQU %meta_rebuild_code% ( + del meta.exe + goto meta_build + ) + exit /b !rc! ) - exit /b !rc! ) diff --git a/src/ase/ase.c b/src/ase/ase.c index aa4ceff4..5ee39053 100644 --- a/src/ase/ase.c +++ b/src/ase/ase.c @@ -489,7 +489,7 @@ ASE_DecodedImage ASE_DecodeImage(Arena *arena, String encoded) TempArena scratch = BeginScratch(arena); ASE_DecodedImage result = ZI; - BB_Buff bb = BitbuffFromString(encoded); + BB_Buff bb = BB_BuffFromString(encoded); BB_Reader br = BB_ReaderFromBuffNoDebug(&bb); ASE_Header ase_header; BB_ReadBytes(&br, StringFromStruct(&ase_header)); @@ -559,7 +559,7 @@ ASE_DecodedImage ASE_DecodeImage(Arena *arena, String encoded) { default: { - BB_SeekToByte(&br, chunk_end_pos); + BB_ReadSeekToByte(&br, chunk_end_pos); } break; //- Decode layer @@ -574,7 +574,7 @@ ASE_DecodedImage ASE_DecodeImage(Arena *arena, String encoded) layer->child_level = BB_ReadUBits(&br, 16); /* Ignoring layer default width & height */ - BB_SeekBytes(&br, sizeof(u16) * 2); + BB_ReadSeekBytes(&br, sizeof(u16) * 2); layer->blend_mode = BB_ReadUBits(&br, 16); if (layer->blend_mode != 0) @@ -591,7 +591,7 @@ ASE_DecodedImage ASE_DecodeImage(Arena *arena, String encoded) layer->opacity = 255; } - BB_SeekBytes(&br, sizeof(u8) * 3); + BB_ReadSeekBytes(&br, sizeof(u8) * 3); u16 str_len = BB_ReadUBits(&br, 16); layer->name = (String) { str_len, PushStructsNoZero(scratch.arena, u8, str_len) }; @@ -625,7 +625,7 @@ ASE_DecodedImage ASE_DecodeImage(Arena *arena, String encoded) cel->opacity = BB_ReadUBits(&br, 8); cel->type = BB_ReadUBits(&br, 16); cel->z_index = BB_ReadIBits(&br, 16); - BB_SeekBytes(&br, sizeof(u8) * 5); + BB_ReadSeekBytes(&br, sizeof(u8) * 5); cel->frame_index = num_frames; @@ -634,7 +634,7 @@ ASE_DecodedImage ASE_DecodeImage(Arena *arena, String encoded) case ASE_CelKind_RawImage: { /* Unsupported */ - BB_SeekToByte(&br, chunk_end_pos); + BB_ReadSeekToByte(&br, chunk_end_pos); } break; case ASE_CelKind_Linked: @@ -783,7 +783,7 @@ ASE_DecodedSheet ASE_DecodeSheet(Arena *arena, String encoded) ASE_DecodedSheet result = ZI; - BB_Buff bb = BitbuffFromString(encoded); + BB_Buff bb = BB_BuffFromString(encoded); BB_Reader br = BB_ReaderFromBuffNoDebug(&bb); ASE_Header ase_header; BB_ReadBytes(&br, StringFromStruct(&ase_header)); @@ -857,14 +857,14 @@ ASE_DecodedSheet ASE_DecodeSheet(Arena *arena, String encoded) { default: { - BB_SeekToByte(&br, chunk_end_pos); + BB_ReadSeekToByte(&br, chunk_end_pos); } break; //- Decode tags case ASE_ChunkKind_Tags: { u16 frame_span_count = BB_ReadUBits(&br, 16); - BB_SeekBytes(&br, 8); + BB_ReadSeekBytes(&br, 8); for (u16 k = 0; k < frame_span_count; ++k) { @@ -874,7 +874,7 @@ ASE_DecodedSheet ASE_DecodeSheet(Arena *arena, String encoded) span->start = BB_ReadUBits(&br, 16); span->end = BB_ReadUBits(&br, 16); - BB_SeekBytes(&br, 13); + BB_ReadSeekBytes(&br, 13); u16 str_len = BB_ReadUBits(&br, 16); span->name = (String) { str_len, PushStructsNoZero(arena, u8, str_len) }; @@ -896,7 +896,7 @@ ASE_DecodedSheet ASE_DecodeSheet(Arena *arena, String encoded) slice_key->num_slices = num_slices; u32 flags = BB_ReadUBits(&br, 32); - BB_SeekBytes(&br, 4); + BB_ReadSeekBytes(&br, 4); u16 str_len = BB_ReadUBits(&br, 16); slice_key->name = (String) { str_len, PushStructsNoZero(arena, u8, str_len) }; @@ -916,12 +916,12 @@ ASE_DecodedSheet ASE_DecodeSheet(Arena *arena, String encoded) if (flags & 0x01) { /* Skip 9-patches info */ - BB_SeekBytes(&br, 128); + BB_ReadSeekBytes(&br, 128); } if (flags & 0x02) { /* Skip pivot info */ - BB_SeekBytes(&br, 64); + BB_ReadSeekBytes(&br, 64); } slice->start = start; diff --git a/src/ase/ase.lay b/src/ase/ase.lay index 70eb6aa8..6da6ae03 100644 --- a/src/ase/ase.lay +++ b/src/ase/ase.lay @@ -1,8 +1,5 @@ @Layer ase -//- Dependencies -@Dep bitbuff - //- Api @IncludeC ase.h diff --git a/src/base/base.h b/src/base/base.h index 36ad33f8..e68d839b 100644 --- a/src/base/base.h +++ b/src/base/base.h @@ -63,24 +63,35 @@ //- Platform system #if defined(_WIN32) # define PlatformIsWindows 1 -# define PlatformIsMac 0 -# define PlatformIsLinux 0 +# define PlatformIsMac 0 +# define PlatformIsLinux 0 #elif defined(__APPLE__) && defined(__MACH__) # define PlatformIsWindows 0 -# define PlatformIsMac 1 -# define PlatformIsLinux 0 +# define PlatformIsMac 1 +# define PlatformIsLinux 0 #elif defined(__gnu_linux__) # define PlatformIsWindows 0 -# define PlatformIsMac 0 -# define PlatformIsLinux 1 +# define PlatformIsMac 0 +# define PlatformIsLinux 1 #elif LanguageIsGpu # define PlatformIsWindows 0 -# define PlatformIsMac 0 -# define PlatformIsLinux 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 +# else +# error Unknown architecture +# endif + //- Windows NTDDI version /* TODO: Remove this */ #if 0 @@ -118,8 +129,7 @@ //- 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 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)) @@ -268,44 +278,52 @@ void __asan_unpoison_memory_region(void const volatile *add, size_t); #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) + +#define StackPush_N(f,n,next) ((n)->next=(f), (f)=(n)) +#define StackPop_N(f,next) ((f)=(f)->next) +#define StackPush(f,n) StackPush_N(f,n,next) +#define StackPop(f) StackPop_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)):\ + +#define QueuePush_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)):\ + +#define QueuePushFront_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)):\ + +#define QueuePop_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) + +#define QueuePush_N(f,l,n,next) QueuePush_NZ(0,f,l,n,next) +#define QueuePushFront_N(f,l,n,next) QueuePushFront_NZ(0,f,l,n,next) +#define QueuePop_N(f,l,next) QueuePop_NZ(0,f,l,next) +#define QueuePush(f,l,n) QueuePush_NZ(0,f,l,n,next) +#define QueuePushFront(f,l,n) QueuePushFront_NZ(0,f,l,n,next) +#define QueuePop(f,l) QueuePop_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)) :\ + +#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 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 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) @@ -368,8 +386,8 @@ void __asan_unpoison_memory_region(void const volatile *add, size_t); * wmmintrin.h AES * immintrin.h AVX, AVX2, FMA */ -#include "intrin.h" -#include "nmmintrin.h" /* SSE4.2 */ +#include +#include /* SSE4.2 */ #endif //////////////////////////////// @@ -512,27 +530,27 @@ StaticAssert(sizeof(Atomic16Padded) == 64 && alignof(Atomic16Padded) == 64); StaticAssert(sizeof(Atomic32Padded) == 64 && alignof(Atomic32Padded) == 64); StaticAssert(sizeof(Atomic64Padded) == 64 && alignof(Atomic64Padded) == 64); -#if PlatformIsWindows +#if PlatformIsWindows && ArchIsX64 //- 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); } +ForceInline i8 Atomic8Fetch(Atomic8 *x) { return x->_v; } +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) { return (i16)_InterlockedCompareExchange16(&x->_v, 0, 0); } +ForceInline i16 Atomic16Fetch(Atomic16 *x) { return x->_v; } 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 Atomic32Fetch(Atomic32 *x) { return x->_v; } 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 Atomic64Fetch(Atomic64 *x) { return x->_v; } 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); } @@ -627,7 +645,7 @@ Struct(StringList) //~ Fiber id #if PlatformIsWindows -# define FiberId (*(i16 *)(void *)(volatile u64)__readgsqword(32)) +# define FiberId() (*(i16 *)(void *)(volatile u64)__readgsqword(32)) #else # error FiberId not implemented #endif diff --git a/src/base/base_arena.h b/src/base/base_arena.h index c663a052..36794e14 100644 --- a/src/base/base_arena.h +++ b/src/base/base_arena.h @@ -194,7 +194,7 @@ Inline ArenaCtx *ArenaCtxFromFiberId(i16 fiber_id) return ctx; } -#define PermArena (ArenaCtxFromFiberId(FiberId)->perm_arena) +#define PermArena (ArenaCtxFromFiberId(FiberId())->perm_arena) //////////////////////////////// //~ Scratch helpers @@ -215,7 +215,7 @@ Inline TempArena BeginScratch(Arena *potential_conflict) /* Use `BeginScratchNoConflict` if no conflicts are present */ Assert(potential_conflict != 0); - ArenaCtx *ctx = ArenaCtxFromFiberId(FiberId); + ArenaCtx *ctx = ArenaCtxFromFiberId(FiberId()); Arena *scratch_arena = ctx->scratch_arenas[0]; if (scratch_arena == potential_conflict) { @@ -239,7 +239,7 @@ Inline TempArena BeginScratch(Arena *potential_conflict) Inline TempArena BeginScratchNoConflict_(void) { - ArenaCtx *ctx = ArenaCtxFromFiberId(FiberId); + ArenaCtx *ctx = ArenaCtxFromFiberId(FiberId()); Arena *scratch_arena = ctx->scratch_arenas[0]; TempArena temp = BeginTempArena(scratch_arena); return temp; diff --git a/src/bitbuff/bitbuff.c b/src/base/base_bitbuff.c similarity index 92% rename from src/bitbuff/bitbuff.c rename to src/base/base_bitbuff.c index 30b90aeb..39433af6 100644 --- a/src/bitbuff/bitbuff.c +++ b/src/base/base_bitbuff.c @@ -3,7 +3,7 @@ //////////////////////////////// //~ Buff management -BB_Buff AcquireBitbuff(u64 arena_reserve) +BB_Buff BB_AcquireBuff(u64 arena_reserve) { BB_Buff result = ZI; result.arena = AcquireArena(arena_reserve); @@ -11,7 +11,7 @@ BB_Buff AcquireBitbuff(u64 arena_reserve) return result; } -void ReleaseBitbuff(BB_Buff *bb) +void BB_ReleaseBuff(BB_Buff *bb) { /* Only arena bitbuffs need to be released */ if (bb->is_backed_by_arena) @@ -20,7 +20,7 @@ void ReleaseBitbuff(BB_Buff *bb) } } -BB_Buff BitbuffFromString(String s) +BB_Buff BB_BuffFromString(String s) { BB_Buff result = ZI; result.fixed_buffer = s; @@ -112,7 +112,7 @@ b32 BB_CheckWriterOverflowBits(BB_Writer *bw, u64 num_bits) else { u64 max_len = bb->fixed_buffer.len; - if (bytes_needed >= max_len) + if (bytes_needed > max_len) { /* Writer overflowed fixed buffer */ Assert(0); @@ -129,17 +129,34 @@ b32 BB_CheckWriterOverflowBits(BB_Writer *bw, u64 num_bits) //~ Align writer /* Align the pos to the next byte */ -void BB_AlignWriter(BB_Writer *bw) +void BB_WriteAlignToNextByte(BB_Writer *bw) { #if BITBUFF_DEBUG if ((bw->cur_bit & 7) != 0) { - BB_WriteDebugMagic(bw, BB_DebugMagicKind_Align, 0); + BB_WriteDebugMagic(bw, BB_DebugMagicKind_AlignNextByte, 0); } #endif bw->cur_bit += (8 - (bw->cur_bit & 7)) & 7; } +void BB_WriteAlign(BB_Writer *bw, u64 align) +{ + BB_WriteAlignToNextByte(bw); + BB_WriteDebugMagic(bw, BB_DebugMagicKind_Align, align); + if (align > 0) + { + u64 new_pos = (bw->cur_bit >> 3); + new_pos += (align - 1); + new_pos -= new_pos % align; + if (BB_CheckWriterOverflowBits(bw, new_pos << 3)) + { + return; + } + bw->cur_bit = new_pos << 3; + } +} + //////////////////////////////// //~ Write bits @@ -301,7 +318,7 @@ void BB_WriteString(BB_Writer *bw, String s) void BB_WriteBytes(BB_Writer *bw, String bytes) { /* Align start of bytes */ - BB_AlignWriter(bw); + BB_WriteAlignToNextByte(bw); u64 num_bits = bytes.len << 3; if (BB_CheckWriterOverflowBits(bw, num_bits)) @@ -314,6 +331,19 @@ void BB_WriteBytes(BB_Writer *bw, String bytes) bw->cur_bit += num_bits; } +void BB_WriteSeekBytes(BB_Writer *bw, u64 num_bytes) +{ + BB_WriteAlignToNextByte(bw); + + u64 num_bits = num_bytes << 3; + if (BB_CheckWriterOverflowBits(bw, num_bits)) + { + return; + } + + bw->cur_bit += num_bits; +} + //////////////////////////////// //~ Writer debug @@ -430,17 +460,34 @@ b32 BB_CheckReaderOverflowBits(BB_Reader *br, u64 num_bits) //~ Align reader /* Align the pos to the next byte */ -void BB_AlignReader(BB_Reader *br) +void BB_ReadAlignToNextByte(BB_Reader *br) { #if BITBUFF_DEBUG if ((br->cur_bit & 7) != 0) { - BB_ReadDebugMagic(br, BB_DebugMagicKind_Align, 0); + BB_ReadDebugMagic(br, BB_DebugMagicKind_AlignNextByte, 0); } #endif br->cur_bit += (8 - (br->cur_bit & 7)) & 7; } +void BB_ReadAlign(BB_Reader *br, u64 align) +{ + BB_ReadAlignToNextByte(br); + BB_ReadDebugMagic(br, BB_DebugMagicKind_Align, align); + if (align > 0) + { + u64 new_pos = (br->cur_bit >> 3); + new_pos += (align - 1); + new_pos -= new_pos % align; + if (BB_CheckReaderOverflowBits(br, new_pos << 3)) + { + return; + } + br->cur_bit = new_pos << 3; + } +} + //////////////////////////////// //~ Read bits @@ -629,7 +676,7 @@ void BB_ReadBytes(BB_Reader *br, String out) /* Will return 0 on bitbuff overflow. Result should be checked. */ u8 *BB_ReadBytesRaw(BB_Reader *br, u64 num_bytes) { - BB_AlignReader(br); + BB_ReadAlignToNextByte(br); u64 num_bits = num_bytes << 3; if (BB_CheckReaderOverflowBits(br, num_bits)) @@ -643,9 +690,9 @@ u8 *BB_ReadBytesRaw(BB_Reader *br, u64 num_bytes) return raw; } -void BB_SeekBytes(BB_Reader *br, u64 num_bytes) +void BB_ReadSeekBytes(BB_Reader *br, u64 num_bytes) { - BB_AlignReader(br); + BB_ReadAlignToNextByte(br); u64 num_bits = num_bytes << 3; if (BB_CheckReaderOverflowBits(br, num_bits)) @@ -656,12 +703,12 @@ void BB_SeekBytes(BB_Reader *br, u64 num_bytes) br->cur_bit += num_bits; } -void BB_SeekToByte(BB_Reader *br, u64 pos) +void BB_ReadSeekToByte(BB_Reader *br, u64 pos) { u64 cur_byte_pos = br->cur_bit >> 3; if (pos >= cur_byte_pos) { - BB_SeekBytes(br, pos - cur_byte_pos); + BB_ReadSeekBytes(br, pos - cur_byte_pos); } else { @@ -670,7 +717,6 @@ void BB_SeekToByte(BB_Reader *br, u64 pos) br->overflowed = 1; br->cur_bit = (br->base_len << 3); } - } //////////////////////////////// @@ -809,7 +855,7 @@ void BB_Test(void) String encoded = ZI; { - BB_Buff bb = AcquireBitbuff(Gibi(64)); + BB_Buff bb = BB_AcquireBuff(Gibi(64)); BB_Writer bw = BB_WriterFromBuff(&bb); for (u64 i = 0; i < countof(cases); ++i) { @@ -843,7 +889,7 @@ void BB_Test(void) } { - BB_Buff bb = BitbuffFromString(encoded); + BB_Buff bb = BB_BuffFromString(encoded); BB_Reader br = BB_ReaderFromBuff(&bb); for (u64 i = 0; i < countof(cases); ++i) { diff --git a/src/bitbuff/bitbuff.h b/src/base/base_bitbuff.h similarity index 79% rename from src/bitbuff/bitbuff.h rename to src/base/base_bitbuff.h index ec367b08..214d0738 100644 --- a/src/bitbuff/bitbuff.h +++ b/src/base/base_bitbuff.h @@ -47,15 +47,16 @@ Struct(BB_Reader) /* Magic numbers inserted to verify read/write type & length */ Enum(BB_DebugMagicKind) { - BB_DebugMagicKind_Align = 0x20A4, - BB_DebugMagicKind_UBits = 0xCB4A, - BB_DebugMagicKind_IBits = 0xB30D, - BB_DebugMagicKind_UV = 0xE179, - BB_DebugMagicKind_IV = 0x981f, - BB_DebugMagicKind_F32 = 0x56F9, - BB_DebugMagicKind_F64 = 0x7053, - BB_DebugMagicKind_Uid = 0xA24E, - BB_DebugMagicKind_String = 0x7866 + BB_DebugMagicKind_Align = 0x20A4, + BB_DebugMagicKind_AlignToNextByte = 0x379A, + BB_DebugMagicKind_UBits = 0xCB4A, + BB_DebugMagicKind_IBits = 0xB30D, + BB_DebugMagicKind_UV = 0xE179, + BB_DebugMagicKind_IV = 0x981f, + BB_DebugMagicKind_F32 = 0x56F9, + BB_DebugMagicKind_F64 = 0x7053, + BB_DebugMagicKind_Uid = 0xA24E, + BB_DebugMagicKind_String = 0x7866 }; #endif @@ -63,10 +64,12 @@ Enum(BB_DebugMagicKind) //////////////////////////////// //~ Buff management -BB_Buff AcquireBitbuff(u64 arena_reserve); -void ReleaseBitbuff(BB_Buff *bitbuff); +//- Growable-arena backed bitbuff +BB_Buff BB_AcquireBuff(u64 arena_reserve); +void BB_ReleaseBuff(BB_Buff *bitbuff); -BB_Buff BitbuffFromString(String s); +//- Fixed-buffer backed bitbuff +BB_Buff BB_BuffFromString(String s); //////////////////////////////// //~ Writer management @@ -86,7 +89,8 @@ b32 BB_CheckWriterOverflowBits(BB_Writer *bw, u64 num_bits); //~ Writer ops //- Align -void BB_AlignWriter(BB_Writer *bw); +void BB_WriteAlignToNextByte(BB_Writer *bw); +void BB_WriteAlign(BB_Writer *bw, u64 align); //- Bits void BB_WriteUBitsNoMagic(BB_Writer *bw, u64 value, u8 num_bits); @@ -108,6 +112,7 @@ void BB_WriteUid(BB_Writer *bw, Uid value); //- Raw data void BB_WriteString(BB_Writer *bw, String s); void BB_WriteBytes(BB_Writer *bw, String bytes); +void BB_WriteSeekBytes(BB_Writer *bw, u64 num_bytes); //////////////////////////////// //~ Writer debug @@ -138,7 +143,8 @@ b32 BB_CheckReaderOverflowBits(BB_Reader *br, u64 num_bits); //~ Reader ops //- Align -void BB_AlignReader(BB_Reader *br); +void BB_ReadAlignToNextByte(BB_Reader *br); +void BB_ReadAlign(BB_Reader *br, u64 align); //- Bits u64 BB_ReadUBitsNoMagic(BB_Reader *br, u8 num_bits); @@ -161,8 +167,8 @@ Uid BB_ReadUid(BB_Reader *br); String BB_ReadString(Arena *arena, BB_Reader *br); void BB_ReadBytes(BB_Reader *br, String dst); u8 *BB_ReadBytesRaw(BB_Reader *br, u64 num_bytes); -void BB_SeekBytes(BB_Reader *br, u64 num_bytes); -void BB_SeekToByte(BB_Reader *br, u64 pos); +void BB_ReadSeekBytes(BB_Reader *br, u64 num_bytes); +void BB_ReadSeekToByte(BB_Reader *br, u64 pos); //////////////////////////////// //~ Reader debug diff --git a/src/base/base_inc.h b/src/base/base_inc.h index 7bb7c35f..ad78719d 100644 --- a/src/base/base_inc.h +++ b/src/base/base_inc.h @@ -19,6 +19,8 @@ # include "base_rand.h" # include "base_util.h" # include "base_entry.h" +# include "base_bitbuff.h" +# include "base_resource.h" #elif LanguageIsGpu # include "base_math_gpu.h" #endif @@ -35,9 +37,11 @@ # include "base_buddy.c" # include "base_math.c" # include "base_rand.c" +# include "base_bitbuff.c" +# include "base_resource.c" #endif -//- Win32 impl +//- Include base_win32 #if LanguageIsC && PlatformIsWindows # include "base_win32/base_win32_inc.h" #endif diff --git a/src/base/base_job.h b/src/base/base_job.h index cc3c6e6d..ca267b3a 100644 --- a/src/base/base_job.h +++ b/src/base/base_job.h @@ -55,8 +55,6 @@ void FutexWake(void *addr, i32 count); //////////////////////////////// //~ @hookdecl Job operations -#define EmptySig { i32 _; } - typedef void GenericJobFunc(void *, i32); Struct(GenericJobDesc) @@ -82,6 +80,11 @@ Struct(JobDescParams) Counter *counter; }; +#define EmptySig { i32 _; } + +#define PushJobDesc(job, ...) (job##_Desc *)PushJobDesc_(sizeof(job##_Sig), alignof(job##_Sig), job##_Generic, (JobDescParams) { .count = 1, .pool = JobPool_Inherit, .priority = JobPriority_Inherit, .counter = 0, __VA_ARGS__ }) +GenericJobDesc *PushJobDesc_(u64 sig_size, u64 sig_align, GenericJobFunc *func, JobDescParams params); + #define JobDecl(job, sigdef) \ typedef struct job##_Sig sigdef job##_Sig; \ Struct(job##_Desc) { Arena *arena; job##_Sig *sig; GenericJobFunc *func; i32 count; JobPool pool; JobPriority priority; Counter *counter; }; \ @@ -89,16 +92,28 @@ Struct(JobDescParams) inline void job##_Generic(void *sig, i32 id) { job((job##_Sig *)sig, id); } \ StaticAssert(1) -#define PushJobDesc(job, ...) (job##_Desc *)PushJobDesc_(sizeof(job##_Sig), alignof(job##_Sig), job##_Generic, (JobDescParams) { .count = 1, .pool = JobPool_Inherit, .priority = JobPriority_Inherit, .counter = 0, __VA_ARGS__ }) -GenericJobDesc *PushJobDesc_(u64 sig_size, u64 sig_align, GenericJobFunc *func, JobDescParams params); - #define JobDef(job, sig_arg, id_arg) void job(job##_Sig *sig_arg, i32 id_arg) -#define RunJob(_count, job, _pool, _priority, _counter, ...) do { \ +/* RunJob example usage: + * + * This example pushes a single 'LoadTextureJob' onto the background job + * pool, copying 'sprite' into the job signature. 'counter' is also passed + * and then immediately yielded on in this example, effectively making + * the operation synchronous as the caller will block until the job completes: + * { + * Counter counter = {0}; + * RunJob(1, LoadTextureJob, JobPool_Background, JobPriority_Low, &counter, .resource = sprite); + * YieldOnCounter(&counter); + * } + * + */ +#define RunJob(_count, job, _pool, _priority, _counter, ...) \ +do { \ job##_Desc *__job_desc = (job##_Desc *)PushJobDesc_(sizeof(job##_Sig), alignof(job##_Sig), job##_Generic, (JobDescParams) { .count = _count, .pool = _pool, .priority = _priority, .counter = _counter,}); \ *__job_desc->sig = (job##_Sig) { __VA_ARGS__ }; \ RunJobEx((GenericJobDesc *)__job_desc); \ } while (0) + void RunJobEx(GenericJobDesc *desc); //////////////////////////////// diff --git a/src/base/base_memory.c b/src/base/base_memory.c index a847a90d..17236419 100644 --- a/src/base/base_memory.c +++ b/src/base/base_memory.c @@ -45,7 +45,7 @@ void SetMemoryReadWrite(void *address, u64 size) #endif /* PlatformIsWindows */ //////////////////////////////// -//~ Crtlib memory.h stubs +//~ Crtlib mem op stubs #if !CrtlibIsEnabled diff --git a/src/base/base_resource.c b/src/base/base_resource.c new file mode 100644 index 00000000..6ad33979 --- /dev/null +++ b/src/base/base_resource.c @@ -0,0 +1,95 @@ +SharedResourceState shared_resource_state = ZI; + +//////////////////////////////// +//~ Startup + +void InitBaseResources(String archive) +{ + SharedResourceState *g = &shared_resource_state; + if (archive.len <= 0) return; + + BB_Buff bb = BB_BuffFromString(archive); + BB_Reader br = BB_ReaderFromBuff(&bb); + + u64 magic = BB_ReadUBits(&br, 64); + Assert(magic == ResourceEmbeddedMagic); + + /* Create & insert entries */ + u64 num_entries = BB_ReadUBits(&br, 64); + for (u64 i = 0; i < num_entries; ++i) + { + u64 name_start = BB_ReadUBits(&br, 64); + u64 name_len = BB_ReadUBits(&br, 64); + u64 data_start = BB_ReadUBits(&br, 64); + u64 data_len = BB_ReadUBits(&br, 64); + + ResourceEntry *entry = PushStruct(PermArena, ResourceEntry); + entry->name = STRING(name_len, archive.text + name_start); + entry->data = STRING(data_len, archive.text + data_start); + entry->hash = HashFnv64(Fnv64Basis, entry->name); + + ResourceEntryBin *bin = &g->bins[entry->hash % NumResourceEntryBins]; + QueuePush_N(bin->first, bin->last, entry, next_in_bin); + QueuePush_N(g->first_entry, g->last_entry, entry, next); + } + g->entries_count = num_entries; +} + +//////////////////////////////// +//~ Resource helpers + +b32 IsResourceNil(Resource resource) +{ + return resource.hash == 0; +} + +Resource ResourceFromStore(ResourceStore *store, String name) +{ + Resource result = ZI; + result.hash = HashFnv64(store->hash, name); + return result; +} + +//////////////////////////////// +//~ Resource cache operations + +ResourceEntry *ResourceEntryFromHash(u64 hash) +{ + ResourceEntry *result = 0; + SharedResourceState *g = &shared_resource_state; + ResourceEntryBin *bin = &g->bins[hash % NumResourceEntryBins]; + for (ResourceEntry *e = bin->first; e; e = e->next_in_bin) + { + if (e->hash == hash) + { + result = e; + break; + } + } + return result; +} + +//////////////////////////////// +//~ Resource operations + +String DataFromResource(Resource resource) +{ + String result = ZI; + ResourceEntry *entry = ResourceEntryFromHash(resource.hash); + if (entry) + { + result = entry->data; + } + return result; +} + +String NameFromResource(Resource resource) +{ + String result = ZI; + ResourceEntry *entry = ResourceEntryFromHash(resource.hash); + if (entry) + { + result = entry->name; + } + return result; +} diff --git a/src/base/base_resource.h b/src/base/base_resource.h new file mode 100644 index 00000000..d938dfc2 --- /dev/null +++ b/src/base/base_resource.h @@ -0,0 +1,72 @@ +//////////////////////////////// +//~ Resource types + +#define ResourceEmbeddedMagic 0xfc060937194f4406 + +#define DeclResourceStore(name) extern ResourceStore name + +Struct(ResourceStore) +{ + u64 hash; +}; + +Struct(Resource) +{ + u64 hash; +}; + +//////////////////////////////// +//~ Resource cache types + +Struct(ResourceEntry) +{ + ResourceEntry *next; + ResourceEntry *next_in_bin; + + u64 hash; + String name; + String data; +}; + +Struct(ResourceEntryBin) +{ + ResourceEntry *first; + ResourceEntry *last; +}; + +//////////////////////////////// +//~ Shared state + +#define NumResourceEntryBins 4096 + +Struct(SharedResourceState) +{ + ResourceEntry *first_entry; + ResourceEntry *last_entry; + u64 entries_count; + ResourceEntryBin bins[NumResourceEntryBins]; +}; + +extern SharedResourceState shared_resource_state; + +//////////////////////////////// +//~ Startup + +void InitBaseResources(String archive); + +//////////////////////////////// +//~ Resource operations + +b32 IsResourceNil(Resource resource); +Resource ResourceFromStore(ResourceStore *store, String name); + +//////////////////////////////// +//~ Resource cache operations + +ResourceEntry *ResourceEntryFromHash(u64 hash); + +//////////////////////////////// +//~ Resource data operations + +String DataFromResource(Resource resource); +String NameFromResource(Resource resource); diff --git a/src/base/base_snc.c b/src/base/base_snc.c index 7f985ba4..7a444d7f 100644 --- a/src/base/base_snc.c +++ b/src/base/base_snc.c @@ -56,7 +56,7 @@ Lock LockSpinE(Mutex *m, i32 spin) } #if RtcIsEnabled - Atomic32FetchSet(&m->exclusive_fiber_id, FiberId); + Atomic32FetchSet(&m->exclusive_fiber_id, FiberId()); #endif Lock lock = ZI; @@ -173,6 +173,11 @@ void SignalCv(Cv *cv, i32 count) //////////////////////////////// //~ Counter +u64 ValueFromCounter(Counter *counter) +{ + return Atomic64Fetch(&counter->v); +} + void AddCounter(Counter *counter, i64 x) { i64 old_v = Atomic64FetchAdd(&counter->v, x); diff --git a/src/base/base_snc.h b/src/base/base_snc.h index 9f5743d4..eae9c1ab 100644 --- a/src/base/base_snc.h +++ b/src/base/base_snc.h @@ -79,5 +79,6 @@ void SignalCv(Cv *cv, i32 count); //////////////////////////////// //~ Counter operations +u64 ValueFromCounter(Counter *counter); void AddCounter(Counter *counter, i64 x); void YieldOnCounter(Counter *counter); diff --git a/src/base/base_util.h b/src/base/base_util.h index ecd0a761..cffa444d 100644 --- a/src/base/base_util.h +++ b/src/base/base_util.h @@ -294,3 +294,10 @@ Inline u64 DictValueFromHash(Dict *dict, u64 hash) DictEntry *entry = DictEntryFromHash(dict, hash); return entry ? entry->value : 0; } + +Inline u64 DictValueOrNilFromHash(Dict *dict, u64 hash, u64 nil) +{ + __prof; + DictEntry *entry = DictEntryFromHash(dict, hash); + return entry ? entry->value : nil; +} diff --git a/src/base/base_win32/base_win32.c b/src/base/base_win32/base_win32.c index 04d2a78c..7a4fb042 100644 --- a/src/base/base_win32/base_win32.c +++ b/src/base/base_win32/base_win32.c @@ -1,5 +1,34 @@ W32_SharedState W32_shared_state = ZI; +//////////////////////////////// +//~ Win32 embedded data + +/* Find first resource with `type` and return the data in `udata`. */ +BOOL W32_FindEmbeddedRcData(HMODULE module, LPCWSTR type, LPWSTR wstr_entry_name, LONG_PTR udata) +{ + W32_SharedState *g = &W32_shared_state; + TempArena scratch = BeginScratchNoConflict(); + String *out = (String *)udata; + b32 found = 0; + String entry_name_lower = LowerString(scratch.arena, StringFromWstrNoLimit(scratch.arena, (LPWSTR)wstr_entry_name)); + if (EqString(entry_name_lower, Lit(Stringize(W32_EmbeddedDataName)))) + { + HRSRC hres = FindResourceW(module, wstr_entry_name, type); + if (hres) + { + HGLOBAL hg = LoadResource(module, hres); + if (hg) + { + found = 1; + out->len = SizeofResource(module, hres); + out->text = LockResource(hg); + } + } + } + EndScratch(scratch); + return !found; +} + //////////////////////////////// //~ @hookdef Core hooks @@ -187,9 +216,18 @@ i32 W32_Main(void) /* Query system info */ GetSystemInfo(&g->info); - //- Startup workers + /* Startup workers */ InitJobWorkers(); + /* Init resources */ + { + String embedded = ZI; + EnumResourceNamesW(0, RT_RCDATA, &W32_FindEmbeddedRcData, (LONG_PTR)&embedded); + InitBaseResources(embedded); + } + + //- App startup + /* Startup layers */ if (!Atomic32Fetch(&g->panicking)) { diff --git a/src/base/base_win32/base_win32.h b/src/base/base_win32/base_win32.h index 4062b14f..e1f209de 100644 --- a/src/base/base_win32/base_win32.h +++ b/src/base/base_win32/base_win32.h @@ -13,7 +13,7 @@ u32 BCryptGenRandom(void *algorithm, u8 *buffer, u32 buffer_size, u32 flags); //////////////////////////////// //~ Shared state -#define W32_MaxOnExitFuncs 1024 +#define W32_MaxOnExitFuncs 4096 Struct(W32_SharedState) { @@ -37,6 +37,12 @@ Struct(W32_SharedState) extern W32_SharedState W32_shared_state; +//////////////////////////////// +//~ Embedded data initialization + +#define W32_EmbeddedDataName embedded_resource_data +BOOL W32_FindEmbeddedRcData(HMODULE module, LPCWSTR type, LPWSTR wstr_entry_name, LONG_PTR udata); + //////////////////////////////// //~ Startup / shutdown jobs diff --git a/src/base/base_win32/base_win32_job.c b/src/base/base_win32/base_win32_job.c index 567a0a64..0209162d 100644 --- a/src/base/base_win32/base_win32_job.c +++ b/src/base/base_win32/base_win32_job.c @@ -19,7 +19,6 @@ void InitJobWorkers(void) g->timer_start_qpc = qpc.QuadPart; } - /* Init fibers */ g->num_fibers = 1; /* Fiber at index 0 always nil */ g->fiber_names_arena = AcquireArena(Gibi(64)); @@ -104,7 +103,6 @@ void InitJobWorkers(void) { name_fmt = Lit("Floating worker #%F"); pool->num_worker_threads = 8; - pool->thread_affinity_mask = 0x0000000000000FFFull; pool->thread_priority = THREAD_PRIORITY_NORMAL; } break; @@ -112,7 +110,6 @@ void InitJobWorkers(void) { name_fmt = Lit("Floating worker #%F"); pool->num_worker_threads = 8; - pool->thread_affinity_mask = 0x0000000000000FFFull; pool->thread_priority = THREAD_PRIORITY_HIGHEST; } break; } @@ -840,7 +837,7 @@ ForceNoInline void W32_FiberResume(W32_Fiber *fiber) void W32_YieldFiber(W32_Fiber *fiber, W32_Fiber *parent_fiber) { LAX fiber; - Assert(fiber->id == FiberId); + Assert(fiber->id == FiberId()); Assert(parent_fiber->id == fiber->parent_id); Assert(parent_fiber->id > 0); { @@ -959,7 +956,7 @@ W32_ThreadDef(W32_JobWorkerEntryFunc, worker_ctx_arg) } } - i32 worker_fiber_id = FiberId; + i32 worker_fiber_id = FiberId(); W32_Fiber *job_fiber = 0; b32 shutdown = 0; @@ -1354,7 +1351,7 @@ W32_ThreadDef(W32_JobSchedulerEntryFunc, UNUSED arg) void FutexYield(volatile void *addr, void *cmp, u32 size, i64 timeout_ns) { - W32_Fiber *fiber = W32_FiberFromId(FiberId); + W32_Fiber *fiber = W32_FiberFromId(FiberId()); i16 parent_id = fiber->parent_id; if (parent_id != 0) { @@ -1446,7 +1443,7 @@ void RunJobEx(GenericJobDesc *desc) { AddCounter(counter, 1); } - W32_Fiber *fiber = W32_FiberFromId(FiberId); + W32_Fiber *fiber = W32_FiberFromId(FiberId()); priority = ClampI32(priority, fiber->job_priority, JobPriority_Count - 1); /* A job cannot create a job with a higher priority than itself */ if (pool_kind == JobPool_Inherit) { diff --git a/src/bitbuff/bitbuff.lay b/src/bitbuff/bitbuff.lay deleted file mode 100644 index 68a625ea..00000000 --- a/src/bitbuff/bitbuff.lay +++ /dev/null @@ -1,7 +0,0 @@ -@Layer bitbuff - -//- Api -@IncludeC bitbuff.h - -//- Impl -@IncludeC bitbuff.c diff --git a/src/font/font.c b/src/font/font.c index 8d80a85c..e69627ee 100644 --- a/src/font/font.c +++ b/src/font/font.c @@ -25,8 +25,8 @@ JobDef(F_LoadJob, sig, _) 0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF }; - R_Tag resource = sig->resource; - String name = R_NameFromTag(resource); + Resource resource = sig->resource; + String name = NameFromResource(resource); f32 point_size = sig->point_size; AC_Asset *asset = sig->asset; @@ -37,7 +37,7 @@ JobDef(F_LoadJob, sig, _) Assert(countof(font_codes) < F_LookupTableSize); /* Decode */ - String resource_data = R_DataFromTag(resource); + String resource_data = DataFromResource(resource); if (resource_data.len == 0) { /* FIME: Load baked font instead of panicking */ @@ -104,11 +104,11 @@ JobDef(F_LoadJob, sig, _) //~ Load /* Returns the asset from the asset cache */ -AC_Asset *F_LoadAsset(R_Tag resource, f32 point_size, b32 wait) +AC_Asset *F_LoadAsset(Resource resource, f32 point_size, b32 wait) { __prof; TempArena scratch = BeginScratchNoConflict(); - String name = R_NameFromTag(resource); + String name = NameFromResource(resource); /* Concatenate point_size to name for key */ String key = StringF(scratch.arena, @@ -137,7 +137,7 @@ AC_Asset *F_LoadAsset(R_Tag resource, f32 point_size, b32 wait) return asset; } -F_Font *F_LoadFontAsync(R_Tag resource, f32 point_size) +F_Font *F_LoadFontAsync(Resource resource, f32 point_size) { __prof; AC_Asset *asset = F_LoadAsset(resource, point_size, 0); @@ -145,7 +145,7 @@ F_Font *F_LoadFontAsync(R_Tag resource, f32 point_size) return f; } -F_Font *F_LoadFontWait(R_Tag resource, f32 point_size) +F_Font *F_LoadFontWait(Resource resource, f32 point_size) { __prof; AC_Asset *asset = F_LoadAsset(resource, point_size, 1); diff --git a/src/font/font.h b/src/font/font.h index 076f2e43..472a87c7 100644 --- a/src/font/font.h +++ b/src/font/font.h @@ -27,14 +27,14 @@ Struct(F_Font) //////////////////////////////// //~ Font load job -JobDecl(F_LoadJob, { AC_Asset *asset; f32 point_size; R_Tag resource; }); +JobDecl(F_LoadJob, { AC_Asset *asset; f32 point_size; Resource resource; }); //////////////////////////////// //~ Font load operations -AC_Asset *F_LoadAsset(R_Tag resource, f32 point_size, b32 wait); -F_Font *F_LoadFontAsync(R_Tag resource, f32 point_size); -F_Font *F_LoadFontWait(R_Tag resource, f32 point_size); +AC_Asset *F_LoadAsset(Resource resource, f32 point_size, b32 wait); +F_Font *F_LoadFontAsync(Resource resource, f32 point_size); +F_Font *F_LoadFontWait(Resource resource, f32 point_size); //////////////////////////////// //~ Font data operations diff --git a/src/font/font.lay b/src/font/font.lay index 89a9c5ec..09c200f7 100644 --- a/src/font/font.lay +++ b/src/font/font.lay @@ -4,7 +4,6 @@ @Dep ttf @Dep gpu @Dep asset_cache -@Dep res //- Api @IncludeC font.h diff --git a/src/gpu/gpu.lay b/src/gpu/gpu.lay index 680600a7..3e96aa06 100644 --- a/src/gpu/gpu.lay +++ b/src/gpu/gpu.lay @@ -2,7 +2,6 @@ //- Dependencies @Dep platform -@Dep res //- Api @IncludeC gpu.h diff --git a/src/meta/meta.c b/src/meta/meta.c index e4cffa01..b543202e 100644 --- a/src/meta/meta.c +++ b/src/meta/meta.c @@ -48,15 +48,30 @@ //////////////////////////////// //~ Includes +//- Header files #include "../base/base_inc.h" #include "meta_os/meta_os_inc.h" #include "meta_file/meta_file_inc.h" +#include "meta_lay.h" #include "meta.h" +//- Source files +#include "meta_lay.c" + //////////////////////////////// //~ Util +/* TODO: Move this to OS layer */ void Echo(String msg) +{ + HANDLE console_handle = GetStdHandle(STD_OUTPUT_HANDLE); + if (console_handle != INVALID_HANDLE_VALUE) + { + WriteFile(console_handle, msg.text, msg.len, 0, 0); + } +} + +void EchoLine(String msg) { HANDLE console_handle = GetStdHandle(STD_OUTPUT_HANDLE); if (console_handle != INVALID_HANDLE_VALUE) @@ -72,11 +87,10 @@ Struct(LineCol) i64 col; }; -LineCol LineColFromFilePos(String file, i64 pos) +LineCol LineColFromPos(String data, i64 pos) { TempArena scratch = BeginScratchNoConflict(); LineCol result = ZI; - String data = F_DataFromFile(scratch.arena, file); for (u64 cur = 0; cur < data.len && cur <= pos; ++cur) { u8 c = data.text[cur]; @@ -95,718 +109,19 @@ LineCol LineColFromFilePos(String file, i64 pos) return result; } -//////////////////////////////// -//~ Lay tokenizer - -Struct(L_Token) -{ - b32 bof; - b32 eof; - i64 pos; - String s; - L_Token *prev; - L_Token *next; -}; - -Struct(L_TokenList) -{ - L_Token *first; - L_Token *last; -}; - -Enum(L_TokenizerMode) -{ - L_TokenizerMode_None, - L_TokenizerMode_SingleLineComment, - L_TokenizerMode_MultiLineComment -}; - -/* FIXME: Ignore comments */ -L_TokenList L_TokensFromString(Arena *arena, String s) -{ - L_TokenList result = ZI; - /* Push start nil token */ - { - L_Token *beginning = PushStruct(arena, L_Token); - beginning->prev = beginning; /* Self link */ - beginning->pos = -1; - result.first = beginning; - result.last = beginning; - beginning->bof = 1; - } - - /* Tokenize */ - u64 pos = 0; - String cur_text = ZI; - cur_text.text = s.text; - L_TokenizerMode mode = L_TokenizerMode_None; - while (pos < s.len) - { - u8 c = s.text[pos]; - switch (mode) - { - case L_TokenizerMode_None: - { - if (c == ' ' || c == '\n' || c == 0 || pos == s.len - 1) - { /* Whitespace */ - if (cur_text.len > 0) - { - L_Token *t = PushStruct(arena, L_Token); - t->s = PushString(arena, cur_text); - t->pos = (cur_text.text - s.text); - if (result.last) - { - result.last->next = t; - } - else - { - result.first = t; - } - t->prev = result.last; - result.last = t; - cur_text.len = 0; - } - pos += 1; - } - else if (c == '/' && (pos + 1) < s.len && s.text[pos + 1] == '/') - { /* Start single line comment */ - mode = L_TokenizerMode_SingleLineComment; - pos += 2; - } - else if (c == '/' && (pos + 1) < s.len && s.text[pos + 1] == '*') - { /* Start multi line comment */ - mode = L_TokenizerMode_MultiLineComment; - pos += 2; - } - else - { - if (cur_text.len == 0) - { - cur_text.text = &s.text[pos]; - } - ++cur_text.len; - pos += 1; - } - } break; - - case L_TokenizerMode_SingleLineComment: - { - if (c == '\n') - { /* End single line comment */ - mode = L_TokenizerMode_None; - pos += 1; - } - else - { - pos += 1; - } - } break; - - case L_TokenizerMode_MultiLineComment: - { - if (c == '*' && (pos + 1) < s.len && s.text[pos + 1] == '/') - { /* End multi line comment */ - mode = L_TokenizerMode_None; - pos += 2; - } - else - { - pos += 1; - } - } break; - }; - } - - /* Push end nil token */ - { - L_Token *ending = PushStruct(arena, L_Token); - ending->next = ending; /* Self link */ - ending->prev = result.last; - ending->pos = s.len; - result.last->next = ending; - result.last = ending; - ending->eof = 1; - } - return result; -} - -//////////////////////////////// -//~ Blob - -Enum(L_ParseMode) -{ - L_ParseMode_None, - L_ParseMode_LayerName, - L_ParseMode_Dep, - L_ParseMode_IncludeC, - L_ParseMode_IncludeGpu, - L_ParseMode_ShaderVS, - L_ParseMode_ShaderPS, - L_ParseMode_ShaderCS, - L_ParseMode_Startup, - L_ParseMode_EmbedDir_StoreName, - L_ParseMode_EmbedDir_DirName, - L_ParseMode_DefaultWindowsImpl, -}; - -Enum(L_BlobTopoColor) -{ - L_BlobTopoColor_None, - L_BlobTopoColor_Queued, - L_BlobTopoColor_Visiting, - L_BlobTopoColor_Finished, -}; - -Struct(L_BlobItem) -{ - L_BlobItem *next; - String s; - String store_name; - String token_file; - i64 token_pos; -}; - -Struct(L_BlobItemList) -{ - L_BlobItem *first; - L_BlobItem *last; - i64 count; -}; - -Struct(L_Blob) -{ - i64 id; - L_Blob *next; - - L_BlobItemList names; - L_BlobItemList deps; - L_BlobItemList c_includes; - L_BlobItemList gpu_includes; - L_BlobItemList vertex_shaders; - L_BlobItemList pixel_shaders; - L_BlobItemList compute_shaders; - L_BlobItemList startup_functions; - L_BlobItemList embed_dirs; - L_BlobItemList default_windows_impls; - - L_BlobItemList errors; -}; - -Struct(L_ParseResult) -{ - L_Blob *first_blob; - L_Blob *last_blob; - Dict *blobs_dict; - u64 blobs_count; -}; - -L_BlobItem *L_PushBlobItem(Arena *arena, L_BlobItemList *list, String token_file, i64 token_pos, String item_string) -{ - L_BlobItem *item = PushStruct(arena, L_BlobItem); - item->s = item_string; - item->token_file = token_file; - item->token_pos = token_pos; - SllQueuePush(list->first, list->last, item); - ++list->count; - return item; -} - -L_ParseResult L_ParseBlobsFromPaths(Arena *arena, StringList paths) -{ - TempArena scratch = BeginScratch(arena); - L_ParseResult result = ZI; - result.blobs_dict = InitDict(arena, 1024); - - for (StringListNode *dir_node = paths.first; dir_node; dir_node = dir_node->next) - { - String dir = dir_node->s; - StringList files = ZI; - F_FilesFromDir(scratch.arena, &files, dir, F_IterFlag_Recurse); - for (StringListNode *file_node = files.first; file_node; file_node = file_node->next) - { - if (EqString(F_ExtensionFromFile(file_node->s), Lit("lay"))) - { - String file = PushString(arena, file_node->s); - String data = F_DataFromFile(scratch.arena, file); - L_TokenList tokens = L_TokensFromString(scratch.arena, data); - L_ParseMode mode = L_ParseMode_None; - L_Blob *blob = PushStruct(arena, L_Blob); - SllQueuePush(result.first_blob, result.last_blob, blob); - blob->id = result.blobs_count++; - String store_name = Lit(""); - for (L_Token *token = tokens.first->next; token; token = token->next) - { - String s = token->s; - if (token->eof) - { - if (mode != L_ParseMode_None) - { - L_PushBlobItem(arena, &blob->errors, file, token->pos, Lit("Unexpected end of file")); - } - break; - } - if (mode == L_ParseMode_None) - { - if (EqString(s, Lit("@Layer"))) mode = L_ParseMode_LayerName; - else if (EqString(s, Lit("@Dep"))) mode = L_ParseMode_Dep; - else if (EqString(s, Lit("@IncludeC"))) mode = L_ParseMode_IncludeC; - else if (EqString(s, Lit("@IncludeGpu"))) mode = L_ParseMode_IncludeGpu; - else if (EqString(s, Lit("@ShaderVS"))) mode = L_ParseMode_ShaderVS; - else if (EqString(s, Lit("@ShaderPS"))) mode = L_ParseMode_ShaderPS; - else if (EqString(s, Lit("@ShaderCS"))) mode = L_ParseMode_ShaderCS; - else if (EqString(s, Lit("@Startup"))) mode = L_ParseMode_Startup; - else if (EqString(s, Lit("@EmbedDir"))) mode = L_ParseMode_EmbedDir_StoreName; - else if (EqString(s, Lit("@DefaultWindowsImpl"))) mode = L_ParseMode_DefaultWindowsImpl; - else - { - /* Encountered unexpected token, stop parsing */ - L_PushBlobItem(arena, &blob->errors, file, token->pos, StringF(arena, "Unexpected token '%F'", FmtString(s))); - break; - } - } - else - { - switch (mode) - { - case L_ParseMode_None: - { - if (EqString(s, Lit("@Layer"))) mode = L_ParseMode_LayerName; - else if (EqString(s, Lit("@Dep"))) mode = L_ParseMode_Dep; - else - { - L_PushBlobItem(arena, &blob->names, file, token->pos, s); - } - } break; - case L_ParseMode_LayerName: - { - L_PushBlobItem(arena, &blob->names, file, token->pos, s); - mode = L_ParseMode_None; - } break; - case L_ParseMode_Dep: - { - L_PushBlobItem(arena, &blob->deps, file, token->pos, s); - mode = L_ParseMode_None; - } break; - case L_ParseMode_IncludeC: - { - L_PushBlobItem(arena, &blob->c_includes, file, token->pos, s); - mode = L_ParseMode_None; - } break; - case L_ParseMode_IncludeGpu: - { - L_PushBlobItem(arena, &blob->gpu_includes, file, token->pos, s); - mode = L_ParseMode_None; - } break; - case L_ParseMode_ShaderVS: - { - L_PushBlobItem(arena, &blob->vertex_shaders, file, token->pos, s); - mode = L_ParseMode_None; - } break; - case L_ParseMode_ShaderPS: - { - L_PushBlobItem(arena, &blob->pixel_shaders, file, token->pos, s); - mode = L_ParseMode_None; - } break; - case L_ParseMode_ShaderCS: - { - L_PushBlobItem(arena, &blob->compute_shaders, file, token->pos, s); - mode = L_ParseMode_None; - } break; - case L_ParseMode_Startup: - { - L_PushBlobItem(arena, &blob->startup_functions, file, token->pos, s); - mode = L_ParseMode_None; - } break; - case L_ParseMode_EmbedDir_StoreName: - { - store_name = s; - mode = L_ParseMode_EmbedDir_DirName; - } break; - case L_ParseMode_EmbedDir_DirName: - { - String embed_dir_name = s; - L_BlobItem *item = L_PushBlobItem(arena, &blob->embed_dirs, file, token->pos, embed_dir_name); - item->store_name = PushString(arena, store_name); - store_name = Lit(""); - mode = L_ParseMode_None; - } break; - case L_ParseMode_DefaultWindowsImpl: - { - L_PushBlobItem(arena, &blob->default_windows_impls, file, token->pos, s); - mode = L_ParseMode_None; - } break; - } - } - } - if (mode != L_ParseMode_None) - { - L_PushBlobItem(arena, &blob->errors, file, tokens.last->pos, Lit("Unexpected end of file")); - } - if (blob->names.count == 1) - { - String name = blob->names.first->s; - u64 hash = HashFnv64(Fnv64Basis, name); - DictEntry *entry = EnsureDictEntry(arena, result.blobs_dict, hash); - if (entry->value == 0) - { - entry->value = (u64)blob; - } - else - { - L_PushBlobItem(arena, &blob->errors, file, blob->names.first->token_pos, StringF(arena, "Layer '%F' already exists", FmtString(name))); - } - } - else if (blob->names.count == 0) - { - L_PushBlobItem(arena, &blob->errors, file, tokens.first->pos, Lit("Mising layer name")); - } - else - { - for (L_BlobItem *item = blob->names.first; item; item = item->next) - { - L_PushBlobItem(arena, &blob->errors, item->token_file, item->token_pos, Lit("Layer contains multiple names")); - } - } - } - } - } - - EndScratch(scratch); - return result; -} - -//////////////////////////////// -//~ Topo - -Struct(L_TopoItem) -{ - L_TopoItem *next; - String s; - String store_name; - String token_file; - i64 token_pos; -}; - -Struct(L_TopoItemList) -{ - L_TopoItem *first; - L_TopoItem *last; - u64 count; -}; - -Struct(L_Topo) -{ - L_TopoItemList c_includes; - L_TopoItemList startup_functions; - L_TopoItemList embed_dirs; - L_TopoItemList errors; -}; - -L_TopoItem *L_PushTopoItem(Arena *arena, L_TopoItemList *list, String token_file, i64 token_pos, String item_string) -{ - L_TopoItem *item = PushStruct(arena, L_TopoItem); - item->s = item_string; - item->token_file = token_file; - item->token_pos = token_pos; - SllQueuePush(list->first, list->last, item); - ++list->count; - return item; -} - -L_Topo L_TopoFromLayerName(Arena *arena, StringList starting_layer_names, StringList paths) -{ - TempArena scratch = BeginScratch(arena); - L_Topo result = ZI; - - /* Parse blobs */ - L_ParseResult parsed = L_ParseBlobsFromPaths(scratch.arena, paths); - - Struct(Node) - { - Node *next; - L_Blob *blob; - i32 state; /* 0 = enter, 1 = exit */ - }; - - /* Topological sort via post-order DFS */ - Node *first_stack = 0; - Node *first_post = 0; - Node *last_post = 0; - i8 *seen_blobs = PushStructs(scratch.arena, i8, parsed.blobs_count); - i8 *entered_blobs = PushStructs(scratch.arena, i8, parsed.blobs_count); - { - for (StringListNode *n = starting_layer_names.first; n; n = n->next) - { - String s = n->s; - L_Blob *starting_blob = (L_Blob *)DictValueFromHash(parsed.blobs_dict, HashFnv64(Fnv64Basis, s)); - if (starting_blob) - { - Node *n = PushStruct(scratch.arena, Node); - n->blob = starting_blob; - n->state = 0; - SllStackPush(first_stack, n); - } - else - { - L_PushTopoItem(arena, &result.errors, Lit(""), 0, StringF(arena, "Starting layer not found with name '%F'", FmtString(s))); - } - } - while (first_stack) - { - L_Blob *blob = 0; - Node *stack_node = first_stack; - blob = stack_node->blob; - SllStackPop(first_stack); - - if (stack_node->state == 0) - { /* Enter */ - if (!seen_blobs[blob->id]) - { - if (entered_blobs[blob->id]) - { /* Cycle detected */ - Node *first_cycle = 0; - { - i8 *cycle_blobs_seen = PushStructs(scratch.arena, i8, parsed.blobs_count); - { - Node *cycle_node = PushStruct(scratch.arena, Node); - cycle_node->blob = blob; - SllStackPush(first_cycle, cycle_node); - } - for (Node *n = first_stack; n; n = n->next) - { - if (entered_blobs[n->blob->id]) - { - if (!cycle_blobs_seen[n->blob->id]) - { - Node *cycle_node = PushStruct(scratch.arena, Node); - cycle_node->blob = n->blob; - SllStackPush(first_cycle, cycle_node); - cycle_blobs_seen[n->blob->id] = 1; - } - } - if (n->blob == blob) break; - } - } - StringList cycle_names_list = ZI; - for (Node *cycle = first_cycle; cycle; cycle = cycle->next) - { - String name = ZI; - if (cycle->blob->names.count > 0) name = cycle->blob->names.first->s; - PushStringToList(scratch.arena, &cycle_names_list, name); - } - String cycle_names_str = StringFromList(scratch.arena, cycle_names_list, Lit(" -> ")); - String name = ZI; - String token_file = ZI; - i64 token_pos = 0; - if (blob->names.count > 0) - { - name = blob->names.first->s; - token_file = PushString(arena, blob->names.first->token_file); - token_pos = blob->names.first->token_pos; - } - if (cycle_names_list.count > 1) - { - L_PushTopoItem(arena, &result.errors, token_file, token_pos, StringF(arena, - "Cyclic dependency detected while processing dependencies for layer '%F' (%F)", - FmtString(name), - FmtString(cycle_names_str))); - } - else - { - L_PushTopoItem(arena, &result.errors, token_file, token_pos, StringF(arena, - "Cyclic dependency detected while processing dependencies for layer '%F'", - FmtString(name))); - } - } - else - { - /* Push platform impls */ - { - L_BlobItemList platform_impls = ZI; - if (PlatformIsWindows) - { - platform_impls = blob->default_windows_impls; - } - for (L_BlobItem *impl_item = platform_impls.first; impl_item; impl_item = impl_item->next) - { - String impl_name = impl_item->s; - u64 impl_hash = HashFnv64(Fnv64Basis, impl_name); - L_Blob *impl = (L_Blob *)DictValueFromHash(parsed.blobs_dict, impl_hash); - if (impl) - { - if (!seen_blobs[impl->id]) - { - Node *n = PushStruct(scratch.arena, Node); - n->blob = impl; - n->state = 0; - SllStackPush(first_stack, n); - } - } - else - { - String file = PushString(arena, impl_item->token_file); - L_PushTopoItem(arena, &result.errors, file, impl_item->token_pos, StringF(arena, "Layer '%F' not found", FmtString(impl_name))); - } - } - } - /* Push blob exit */ - { - entered_blobs[blob->id] = 1; - Node *n = PushStruct(scratch.arena, Node); - n->blob = blob; - n->state = 1; - SllStackPush(first_stack, n); - } - /* Push blob deps */ - for (L_BlobItem *dep_item = blob->deps.first; dep_item; dep_item = dep_item->next) - { - String dep_name = dep_item->s; - u64 dep_hash = HashFnv64(Fnv64Basis, dep_name); - L_Blob *dep = (L_Blob *)DictValueFromHash(parsed.blobs_dict, dep_hash); - if (dep) - { - if (!seen_blobs[dep->id]) - { - Node *n = PushStruct(scratch.arena, Node); - n->blob = dep; - n->state = 0; - SllStackPush(first_stack, n); - } - } - else - { - String file = PushString(arena, dep_item->token_file); - L_PushTopoItem(arena, &result.errors, file, dep_item->token_pos, StringF(arena, "Layer '%F' not found", FmtString(dep_name))); - } - } - } - } - } - else - { /* Exit */ - entered_blobs[blob->id] = 0; - seen_blobs[blob->id] = 1; - SllQueuePush(first_post, last_post, stack_node); - } - } - } - - /* Process post blobs into result */ - for (Node *n = first_post; n; n = n->next) - { - L_Blob *blob = n->blob; - /* Errors */ - for (L_BlobItem *bitem = blob->errors.first; bitem; bitem = bitem->next) - { - String file = PushString(arena, bitem->token_file); - String s = PushString(arena, bitem->s); - L_PushTopoItem(arena, &result.errors, file, bitem->token_pos, s); - } - /* C includes */ - for (L_BlobItem *bitem = blob->c_includes.first; bitem; bitem = bitem->next) - { - String file = PushString(arena, bitem->token_file); - String s = PushString(arena, bitem->s); - L_PushTopoItem(arena, &result.c_includes, file, bitem->token_pos, s); - } - /* Startup funcs */ - for (L_BlobItem *bitem = blob->startup_functions.first; bitem; bitem = bitem->next) - { - String file = PushString(arena, bitem->token_file); - String s = PushString(arena, bitem->s); - L_PushTopoItem(arena, &result.startup_functions, file, bitem->token_pos, s); - } - /* Embed dirs */ - for (L_BlobItem *bitem = blob->embed_dirs.first; bitem; bitem = bitem->next) - { - String file = PushString(arena, bitem->token_file); - String s = PushString(arena, bitem->s); - L_TopoItem *titem = L_PushTopoItem(arena, &result.embed_dirs, file, bitem->token_pos, s); - titem->store_name = PushString(arena, bitem->store_name); - } - } - - /* Process errors of untouched blobs */ - for (L_Blob *blob = parsed.first_blob; blob; blob = blob->next) - { - if (!seen_blobs[blob->id] && blob->errors.count > 0) - { - for (L_BlobItem *bitem = blob->errors.first; bitem; bitem = bitem->next) - { - String file = PushString(arena, bitem->token_file); - String s = PushString(arena, bitem->s); - L_PushTopoItem(arena, &result.errors, file, bitem->token_pos, s); - } - } - } - - EndScratch(scratch); - return result; -} - -//////////////////////////////// -//~ Error - -Struct(Error) -{ - String s; - String file; - i64 pos; - Error *next; -}; - -Struct(ErrorList) -{ - Error *first; - Error *last; - i64 count; -}; - -Error *PushError(Arena *arena, ErrorList *list, String file, i64 pos, String s) -{ - Error *e = PushStruct(arena, Error); - e->s = s; - e->file = file; - e->pos = pos; - SllQueuePush(list->first, list->last, e); - ++list->count; - return e; -} - -//////////////////////////////// -//~ Task - -JobDecl(TaskJob, {i32 _;}); - -JobDef(TaskJob, sig, id) -{ - -} - - - - - - - - //////////////////////////////// //~ Build void StartupMeta(void) { Arena *arena = AcquireArena(Gibi(64)); + M_ErrorList errors = ZI; + i32 ret = 0; - ErrorList errors = ZI; + //////////////////////////////// + //~ Dirty check - //- Unpack args - StringList args = GetCommandLineArgs(); - for (StringListNode *n = args.first; n; n = n->next) - { - String arg = n->s; - } - - //- Return if metaprogram is dirty + //- Return rebuild code if metaprogram is dirty { /* Read old metahash */ u64 old_metahash = 0; @@ -842,127 +157,19 @@ void StartupMeta(void) } else { - Echo(Lit("Metaprogram is dirty")); + EchoLine(Lit("Metaprogram is dirty")); ExitNow(MetaRebuildCode); } } - //- Extract layer topography - StringList src_dirs = ZI; - StringList starting_layer_names = ZI; - PushStringToList(arena, &src_dirs, Lit("../src")); - PushStringToList(arena, &starting_layer_names, Lit("pp")); - L_Topo topo = L_TopoFromLayerName(arena, starting_layer_names, src_dirs); + //////////////////////////////// + //~ Args - //- Process topo errors - if (topo.errors.count > 0) + //- Unpack args + StringList args = GetCommandLineArgs(); + for (StringListNode *n = args.first; n; n = n->next) { - StringList topo_errors = ZI; - u64 max_topo_errors = 50; - for (L_TopoItem *item = topo.errors.first; item && topo_errors.count < max_topo_errors; item = item->next) - { - PushError(arena, &errors, item->token_file, item->token_pos, item->s); - } - } - - //- Generate C file - String c_out_file = F_GetFull(arena, Lit("pp_gen.c")); - if (errors.count <= 0) - { - StringList c_out_lines = ZI; - PushStringToList(arena, &c_out_lines, Lit("// Auto generated file")); - /* Include base layer */ - { - String base_inc_path = F_GetFull(arena, Lit("../src/base/base_inc.h")); - PushStringToList(arena, &c_out_lines, Lit("")); - PushStringToList(arena, &c_out_lines, Lit("//- Include base layer")); - String line = StringF(arena, "#include \"%F\"", FmtString(base_inc_path)); - PushStringToList(arena, &c_out_lines, line); - } - /* Include dependency layers */ - { - PushStringToList(arena, &c_out_lines, Lit("")); - PushStringToList(arena, &c_out_lines, Lit("//- Include dependencies")); - for (L_TopoItem *item = topo.c_includes.first; item; item = item->next) - { - String parent = F_GetParentDir(item->token_file); - String file = StringF(arena, "%F%F", FmtString(parent), FmtString(item->s)); - if (F_IsFile(file)) - { - String full = F_GetFull(arena, file); - String line = StringF(arena, "#include \"%F\"", FmtString(full)); - PushStringToList(arena, &c_out_lines, line); - } - else - { - String e = StringF(arena, "File '%F' not found", FmtString(file)); - PushError(arena, &errors, item->token_file, item->token_pos, e); - } - } - } - /* Define StartupLayers */ - { - PushStringToList(arena, &c_out_lines, Lit("")); - PushStringToList(arena, &c_out_lines, Lit("//- Startup")); - PushStringToList(arena, &c_out_lines, Lit("void StartupLayers(void)")); - PushStringToList(arena, &c_out_lines, Lit("{")); - for (L_TopoItem *item = topo.startup_functions.first; item; item = item->next) - { - String line = StringF(arena, " %F();", FmtString(item->s)); - PushStringToList(arena, &c_out_lines, line); - } - PushStringToList(arena, &c_out_lines, Lit("}")); - PushStringToList(arena, &c_out_lines, Lit("")); - } - /* Write to file */ - String c_out = StringFromList(arena, c_out_lines, Lit("\n")); - F_ClearWrite(c_out_file, c_out); - } - - //- Generate archive file - String archive_out_file = F_GetFull(arena, Lit("embeds.arc")); - { - for (L_TopoItem *item = topo.embed_dirs.first; item; item = item->next) - { - String parent = F_GetParentDir(item->token_file); - String dir = StringF(arena, "%F%F", FmtString(parent), FmtString(item->s)); - if (F_IsDir(dir)) - { - String full = F_GetFull(arena, dir); - String line = StringF(arena, "#include \"%F\"", FmtString(full)); - // PushStringToList(arena, &c_out_lines, line); - } - else - { - String e = StringF(arena, "Dir '%F' not found", FmtString(dir)); - PushError(arena, &errors, item->token_file, item->token_pos, e); - } - } - } - - //- Echo meta errors - i32 ret = errors.count > 0; - for (Error *e = errors.first; e; e = e->next) - { - String s = e->s; - String file = e->file; - i64 pos = e->pos; - String error = ZI; - if (file.len > 0) - { - LineCol line_col = LineColFromFilePos(file, pos); - error = StringF(arena, - "%F:%F:%F: error: %F", - FmtString(file), - FmtSint(line_col.line), - FmtSint(line_col.col), - FmtString(s)); - } - else - { - error = StringF(arena, "error: %F", FmtString(s)); - } - Echo(error); + String arg = n->s; } //- Generate compiler flags @@ -989,8 +196,9 @@ void StartupMeta(void) //- Msvc { - PushStringToList(arena, &flags_msvc, Lit("-nologo")); PushStringToList(arena, &compiler_flags_msvc, Lit("-diagnostics:column")); + PushStringToList(arena, &flags_msvc, Lit("-INCREMENTAL:NO")); + PushStringToList(arena, &flags_msvc, Lit("-nologo")); /* Debug info */ PushStringToList(arena, &flags_msvc, Lit("-DEBUG:FULL")); @@ -1038,11 +246,377 @@ void StartupMeta(void) } } + //////////////////////////////// + //~ Parse + + //- Lex layers + M_TokenFileList lexed = ZI; + { + StringList src_dirs = ZI; + PushStringToList(arena, &src_dirs, Lit("../src")); + lexed = M_TokensFromSrcDirs(arena, src_dirs); + } + + //- Parse layers + M_LayerList parsed = ZI; + { + parsed = M_LayersFromTokenFiles(arena, lexed); + } + + //- Flatten layers + M_Layer flattened = ZI; + { + StringList starting_layer_names = ZI; + PushStringToList(arena, &starting_layer_names, Lit("pp")); + flattened = M_GetFlattenedEntries(arena, parsed, starting_layer_names); + } + M_AppendErrors(arena, &errors, flattened.errors); + + //- Process flattened layers + StringList c_include_lines = ZI; + StringList gpu_include_lines = ZI; + StringList c_startup_lines = ZI; + StringList c_store_lines = ZI; + Struct(EmbeddedDir) { EmbeddedDir *next; String store_name; String dir_name; }; + EmbeddedDir *first_dir_embed = 0; + EmbeddedDir *last_dir_embed = 0; + u64 num_dir_embeds = 0; + if (errors.count <= 0) + { + for (M_Entry *entry = flattened.first; entry->valid; entry = entry->next) + { + M_EntryKind kind = entry->kind; + M_Token *entry_tok = entry->name_token; + M_Token *arg0_tok = entry->arg_tokens[0]; + M_Token *arg1_tok = entry->arg_tokens[1]; + switch(kind) + { + case M_EntryKind_Unknown: + { + M_PushError(arena, &errors, entry_tok, StringF(arena, "Unknown entry kind \"%F\"", FmtString(entry_tok->s))); + } break; + + case M_EntryKind_IncludeC: + case M_EntryKind_IncludeGpu: + { + if (arg0_tok->valid) + { + String token_file = arg0_tok->file->name; + String token_parent_dir = F_GetParentDir(token_file); + String arg_file = arg0_tok->s; + String full = F_GetFull(arena, StringF(arena, "%F/%F", FmtString(token_parent_dir), FmtString(arg_file))); + if (F_IsFile(full)) + { + String line = StringF(arena, "#include \"%F\"", FmtString(full)); + if (kind == M_EntryKind_IncludeC) + { + PushStringToList(arena, &c_include_lines, line); + } + else + { + PushStringToList(arena, &gpu_include_lines, line); + } + } + else + { + String err = StringF(arena, "File '%F' not found", FmtString(full)); + M_PushError(arena, &errors, arg0_tok, err); + } + } + else + { + M_PushError(arena, &errors, entry_tok, Lit("Expected file name")); + } + } break; + + case M_EntryKind_Startup: + { + if (arg0_tok->valid) + { + String startup = arg0_tok->s; + String line = StringF(arena, " %F();", FmtString(startup)); + PushStringToList(arena, &c_startup_lines, line); + } + else + { + M_PushError(arena, &errors, entry_tok, Lit("Expected startup function name")); + } + } break; + + case M_EntryKind_EmbedDir: + { + if (arg0_tok->valid && arg1_tok->valid) + { + String store_name = arg0_tok->s; + String token_file = arg1_tok->file->name; + String token_parent_dir = F_GetParentDir(token_file); + String arg_dir = arg1_tok->s; + String full = F_GetFullCrossPlatform(arena, StringF(arena, "%F/%F", FmtString(token_parent_dir), FmtString(arg_dir))); + if (F_IsDir(full)) + { + u64 hash = HashFnv64(Fnv64Basis, StringF(arena, "%F/", FmtString(store_name))); + String line = StringF(arena, "ResourceStore %F = { 0x%F };", FmtString(store_name), FmtHex(hash)); + PushStringToList(arena, &c_store_lines, line); + + EmbeddedDir *ed = PushStruct(arena, EmbeddedDir); + ed->store_name = store_name; + ed->dir_name = full; + QueuePush(first_dir_embed, last_dir_embed, ed); + ++num_dir_embeds; + } + else + { + String err = StringF(arena, "Directory '%F' not found", FmtString(full)); + M_PushError(arena, &errors, arg1_tok, err); + } + } + else + { + M_PushError(arena, &errors, entry_tok, Lit("Expected resource store & directory name")); + } + } break; + } + } + } + + //- Echo meta errors + if (ret == 0) + { + ret = errors.count > 0; + } + for (M_Error *e = errors.first; e; e = e->next) + { + String msg = ZI; + M_Token *token = e->token; + String token_file = token->file->name; + String token_file_data = token->file->data; + if (token_file.len > 0) + { + i64 token_pos = -1; + if (token->s.len > 0 + && token_file_data.len > 0 + && token->s.text > token_file_data.text + && token->s.text < (token_file_data.text + token_file_data.len)) + { + token_pos = token->s.text - token_file_data.text; + } + LineCol line_col = ZI; + if (token_pos >= 0) + { + line_col = LineColFromPos(token_file_data, token_pos); + } + msg = StringF(arena, + "%F:%F:%F: error: %F", + FmtString(token_file), + FmtSint(line_col.line), + FmtSint(line_col.col), + FmtString(e->msg)); + } + else + { + msg = StringF(arena, "error: %F", FmtString(e->msg)); + } + EchoLine(msg); + } + + //////////////////////////////// + //~ Generate + + //- Generate C file + String c_out_file = F_GetFull(arena, Lit("pp_gen.c")); + if (errors.count <= 0) + { + StringList c_out_lines = ZI; + PushStringToList(arena, &c_out_lines, Lit("// Auto generated file")); + /* Include ase layer */ + { + String base_inc_path = F_GetFull(arena, Lit("../src/base/base_inc.h")); + PushStringToList(arena, &c_out_lines, Lit("")); + PushStringToList(arena, &c_out_lines, Lit("//- Base layer includes")); + String line = StringF(arena, "#include \"%F\"", FmtString(base_inc_path)); + PushStringToList(arena, &c_out_lines, line); + } + /* Include dependency layers */ + if (c_out_lines.count > 0) + { + PushStringToList(arena, &c_out_lines, Lit("")); + PushStringToList(arena, &c_out_lines, Lit("//- Dependency includes")); + for (StringListNode *n = c_include_lines.first; n; n = n->next) + { + PushStringToList(arena, &c_out_lines, n->s); + } + } + /* Define resource stores */ + if (c_store_lines.count > 0) + { + PushStringToList(arena, &c_out_lines, Lit("")); + PushStringToList(arena, &c_out_lines, Lit("//- Resource stores")); + for (StringListNode *n = c_store_lines.first; n; n = n->next) + { + PushStringToList(arena, &c_out_lines, n->s); + } + } + + /* Define StartupLayers */ + { + PushStringToList(arena, &c_out_lines, Lit("")); + PushStringToList(arena, &c_out_lines, Lit("//- Startup")); + PushStringToList(arena, &c_out_lines, Lit("void StartupLayers(void)")); + PushStringToList(arena, &c_out_lines, Lit("{")); + for (StringListNode *n = c_startup_lines.first; n; n = n->next) + { + PushStringToList(arena, &c_out_lines, n->s); + } + PushStringToList(arena, &c_out_lines, Lit("}")); + PushStringToList(arena, &c_out_lines, Lit("")); + } + /* Write to file */ + String c_out = StringFromList(arena, c_out_lines, Lit("\n")); + F_ClearWrite(c_out_file, c_out); + } + + //- Generate archive file + String arc_out_file = F_GetFull(arena, Lit("resources.arc")); + { + EchoLine(Lit("[Building ARC]")); + Struct(EntryNode) + { + EntryNode *next; + String entry_name; + String file_name; + }; + + EntryNode *first_entry = 0; + EntryNode *last_entry = 0; + u64 entries_count = 0; + + for (EmbeddedDir *ed = first_dir_embed; ed; ed = ed->next) + { + String store_name = ed->store_name; + String embed_dir = ed->dir_name; + + StringList files = ZI; + F_FilesFromDir(arena, &files, embed_dir, F_IterFlag_Recurse); + for (StringListNode *file_node = files.first; file_node; file_node = file_node->next) + { + String file_name = file_node->s; + if (F_IsFile(file_name)) + { + String entry_name = file_name; + if (entry_name.len > (embed_dir.len + 1)) + { + entry_name.len -= embed_dir.len + 1; + entry_name.text += embed_dir.len + 1; + } + entry_name = StringF(arena, "%F/%F", FmtString(store_name), FmtString(entry_name)); + for (u64 i = 0; i < entry_name.len; ++i) + { + if (entry_name.text[i] == '\\') + { + entry_name.text[i] = '/'; + } + } + + EntryNode *en = PushStruct(arena, EntryNode); + en->entry_name = entry_name; + en->file_name = file_name; + QueuePush(first_entry, last_entry, en); + ++entries_count; + } + } + + } + + BB_Buff bb = BB_AcquireBuff(Gibi(64)); + BB_Writer bw = BB_WriterFromBuff(&bb); + + /* Write magic */ + BB_WriteUBits(&bw, ResourceEmbeddedMagic, 64); + + /* Write header */ + BB_WriteUBits(&bw, entries_count, 64); + + /* Reserve entries space */ + u64 entry_size = 8 /* Name start */ + + 8 /* Name end */ + + 8 /* Data start */ + + 8; /* Data end */ + u8 *entries_start = BB_GetWrittenRaw(&bw) + BB_GetNumBytesWritten(&bw); + u64 entries_size = entry_size * entries_count; + String entries_str = STRING(entries_size, entries_start); + BB_WriteSeekBytes(&bw, entries_size); + BB_Buff entries_bb = BB_BuffFromString(entries_str); + BB_Writer entries_bw = BB_WriterFromBuff(&entries_bb); + + /* Write entries */ + for (EntryNode *en = first_entry; en; en = en->next) + { + /* TODO: Copy file data directly into archive file */ + String file_data = F_DataFromFile(arena, en->file_name); + + /* Write name */ + BB_WriteAlign(&bw, 64); + u64 name_start = BB_GetNumBytesWritten(&bw) + 1; + BB_WriteString(&bw, en->entry_name); + u64 name_len = BB_GetNumBytesWritten(&bw) - name_start; + + /* Write data */ + BB_WriteAlign(&bw, 64); + u64 data_start = BB_GetNumBytesWritten(&bw) + 1; + BB_WriteBytes(&bw, file_data); + u64 data_len = BB_GetNumBytesWritten(&bw) - data_start; + + /* Write entry */ + BB_WriteUBits(&entries_bw, name_start, 64); + BB_WriteUBits(&entries_bw, name_len, 64); + BB_WriteUBits(&entries_bw, data_start, 64); + BB_WriteUBits(&entries_bw, data_len, 64); + } + + /* Write to file */ + String arc_out = ZI; + arc_out.len = BB_GetNumBytesWritten(&bw); + arc_out.text = BB_GetWrittenRaw(&bw); + F_ClearWrite(arc_out_file, arc_out); + EchoLine(StringF(arena, "Built %F (%F mb)", FmtString(F_GetFileName(arc_out_file)), FmtFloatP((f32)arc_out.len / 1024 / 1024, 3))); + } + + //- Generate rc file + String rc_out_file = F_GetFull(arena, Lit("resources.rc")); + { + StringList rc_out_lines = ZI; + String arc_file_cp = F_GetFullCrossPlatform(arena, arc_out_file); + String line = StringF(arena, "%F RCDATA \"%F\"", FmtString(Lit(Stringize(W32_EmbeddedDataName))), FmtString(arc_file_cp)); + PushStringToList(arena, &rc_out_lines, line); + /* Write to file */ + String rc_out = StringFromList(arena, rc_out_lines, Lit("\n")); + F_ClearWrite(rc_out_file, rc_out); + } + + //////////////////////////////// + //~ Compile + + //- Compile RC + String res_out_file = F_GetFull(arena, Lit("resources.res")); + if (ret == 0) + { + EchoLine(Lit("[Compiling RC]")); + String cmd = StringF(arena, "rc -nologo -fo %F %F", FmtString(res_out_file), FmtString(rc_out_file)); + OS_CommandResult result = OS_RunCommand(arena, cmd); + String output = TrimWhitespace(result.output); + EchoLine(F_GetFileName(rc_out_file)); + if (output.len > 0) + { + EchoLine(output); + } + ret = result.code; + } + //- Compile C String c_out_obj_file = Lit("pp_gen.obj"); if (ret == 0) { - Echo(Lit("[Compiling]")); + EchoLine(Lit("[Compiling C]")); String cmd = StringF(arena, "cl /c %F -Fo:%F %F %F %F %F", FmtString(c_out_file), @@ -1053,24 +627,31 @@ void StartupMeta(void) FmtString(StringFromList(arena, compiler_defs, Lit(" ")))); OS_CommandResult result = OS_RunCommand(arena, cmd); String output = TrimWhitespace(result.output); - Echo(output); + EchoLine(output); ret = result.code; } + //////////////////////////////// + //~ Link + //- Link String exe_file = Lit("pp.exe"); if (ret == 0) { - Echo(Lit("[Linking]")); + EchoLine(Lit("[Linking]")); String cmd = StringF(arena, - "link %F /OUT:%F %F %F", + "link %F %F /OUT:%F %F %F", FmtString(c_out_obj_file), + FmtString(res_out_file), FmtString(exe_file), FmtString(StringFromList(arena, flags_msvc, Lit(" "))), FmtString(StringFromList(arena, linker_flags_msvc, Lit(" ")))); OS_CommandResult result = OS_RunCommand(arena, cmd); String output = TrimWhitespace(result.output); - Echo(output); + if (output.len > 0) + { + EchoLine(output); + } ret = result.code; } @@ -1105,7 +686,7 @@ void StartupMeta(void) //- Compile C if (ret == 0) { - Echo(Lit("Compiling")); + EchoLine(Lit("Compiling")); String cmd_str = msvc_cmd_str; // String cmd_str = clang_cmd_str; OS_CommandResult result = OS_RunCommand(arena, cmd_str); @@ -1113,14 +694,14 @@ void StartupMeta(void) output = Trim(output, Lit("\n")); output = Trim(output, Lit("\r")); output = Trim(output, Lit("\n")); - Echo(output); + EchoLine(output); if (result.code == 0) { - Echo(Lit("Compilation succeeded")); + EchoLine(Lit("Compilation succeeded")); } else { - Echo(Lit("Compilation failed")); + EchoLine(Lit("Compilation failed")); } ret = result.code; } diff --git a/src/meta/meta_file/meta_file.c b/src/meta/meta_file/meta_file.c index 552110ec..a7faa59f 100644 --- a/src/meta/meta_file/meta_file.c +++ b/src/meta/meta_file/meta_file.c @@ -6,6 +6,19 @@ String F_GetFull(Arena *arena, String path) return OS_GetFullPath(arena, path); } +String F_GetFullCrossPlatform(Arena *arena, String path) +{ + String result = OS_GetFullPath(arena, path); + for (u64 i = 0; i < result.len; ++i) + { + if (result.text[i] == '\\') + { + result.text[i] = '/'; + } + } + return result; +} + String F_GetFileName(String path) { String result = ZI; diff --git a/src/meta/meta_file/meta_file.h b/src/meta/meta_file/meta_file.h index 8b25088e..a80f5120 100644 --- a/src/meta/meta_file/meta_file.h +++ b/src/meta/meta_file/meta_file.h @@ -11,6 +11,7 @@ Enum(F_IterFlag) //~ Path helpers String F_GetFull(Arena *arena, String path); +String F_GetFullCrossPlatform(Arena *arena, String path); String F_GetFileName(String path); String F_GetParentDir(String path); String F_ExtensionFromFile(String path); diff --git a/src/meta/meta_lay.c b/src/meta/meta_lay.c new file mode 100644 index 00000000..da05d750 --- /dev/null +++ b/src/meta/meta_lay.c @@ -0,0 +1,541 @@ +Readonly M_Token M_NilToken = { + .next = &M_NilToken, + .file = &M_NilTokenFile, +}; + +Readonly M_TokenFile M_NilTokenFile = { + .next = &M_NilTokenFile, + .first_token = &M_NilToken, + .last_token = &M_NilToken, +}; + +Readonly M_Entry M_NilEntry = { + .next = &M_NilEntry, + .name_token = &M_NilToken, + .arg_tokens[0] = &M_NilToken, + .arg_tokens[1] = &M_NilToken, +}; +StaticAssert(countof(M_NilEntry.arg_tokens) == 2); /* NilEntry must define point args to nil tokens */ + +Readonly M_Layer M_NilLayer = { + .next = &M_NilLayer, + .file = &M_NilTokenFile, + .first = &M_NilEntry, + .last = &M_NilEntry, +}; + +//////////////////////////////// +//~ Error helpers + +M_Error *M_PushError(Arena *arena, M_ErrorList *l, M_Token *token, String msg) +{ + M_Error *e = PushStruct(arena, M_Error); + e->msg = msg; + e->token = token ? token : &M_NilToken; + QueuePush(l->first, l->last, e); + ++l->count; + return e; +} + +void M_AppendErrors(Arena *arena, M_ErrorList *dst, M_ErrorList src) +{ + for (M_Error *e = src.first; e; e = e->next) + { + M_PushError(arena, dst, e->token, e->msg); + } +} + +//////////////////////////////// +//~ Lexer operations + +M_TokenFile *M_PushTokenFile(Arena *arena, M_TokenFileList *l, String name, String data) +{ + M_TokenFile *tf = PushStruct(arena, M_TokenFile); + *tf = M_NilTokenFile; + tf->valid = 1; + tf->name = name; + tf->data = data; + M_PushToken(arena, tf, Lit(""), M_TokenKind_Eol); + QueuePush_NZ(&M_NilTokenFile, l->first, l->last, tf, next); + ++l->count; + return tf; +} + +M_Token *M_PushToken(Arena *arena, M_TokenFile *file, String s, M_TokenKind kind) +{ + M_Token *t = PushStruct(arena, M_Token); + *t = M_NilToken; + t->valid = 1; + t->s = s; + t->kind = kind; + if (file) + { + t->file = file; + } + QueuePush_NZ(&M_NilToken, file->first_token, file->last_token, t, next); + ++file->tokens_count; + return t; +} + +M_TokenFileList M_TokensFromSrcDirs(Arena *arena, StringList src_dirs) +{ + TempArena scratch = BeginScratch(arena); + M_TokenFileList result = ZI; + + /* Build token file list from src dirs */ + Dict *dedup_dict = InitDict(scratch.arena, 1021); + for (StringListNode *dir_name_node = src_dirs.first; dir_name_node; dir_name_node = dir_name_node->next) + { + String dir_name = dir_name_node->s; + StringList files = ZI; + F_FilesFromDir(arena, &files, dir_name, F_IterFlag_Recurse); + for (StringListNode *file_name_node = files.first; file_name_node; file_name_node = file_name_node->next) + { + String file_name = file_name_node->s; + if (StringEndsWith(file_name, Lit(".lay"))) + { + String tmp_full = F_GetFull(scratch.arena, file_name); + u64 hash = HashFnv64(Fnv64Basis, tmp_full); + if (DictValueFromHash(dedup_dict, hash) == 0) + { + SetDictValue(scratch.arena, dedup_dict, hash, 1); + String full = PushString(arena, tmp_full); + String data = F_DataFromFile(arena, full); + M_PushTokenFile(arena, &result, full, data); + } + } + } + } + + for (M_TokenFile *tf = result.first; tf->valid; tf = tf->next) + { + Enum(TokenizerMode) + { + TokenizerMode_None, + TokenizerMode_SingleLineComment, + TokenizerMode_MultiLineComment, + }; + TokenizerMode mode = TokenizerMode_None; + + u8 *t = tf->data.text; + u64 l = tf->data.len; + u64 p = 0; + String cur_ident = STRING(0, t); + while (p < l) + { + switch (mode) + { + case TokenizerMode_None: + { + u8 c = t[p]; + b32 is_eol = c == '\r' || c == '\n' || c == 0 || (p + 1) >= l; + b32 is_whitespace = is_eol || c == ' '; + if (is_whitespace) + { /* Whitespace */ + if (cur_ident.len > 0) + { + M_PushToken(arena, tf, cur_ident, M_TokenKind_Ident); + cur_ident.len = 0; + } + if (is_eol) + { + M_PushToken(arena, tf, STRING(1, &t[p]), M_TokenKind_Eol); + } + p += 1; + } + else if (c == '/' && (p + 1) < l && t[p + 1] == '/') + { /* Start single line comment */ + mode = TokenizerMode_SingleLineComment; + p += 2; + } + else if (c == '/' && (p + 1) < l && t[p + 1] == '*') + { /* Start multi line comment */ + mode = TokenizerMode_MultiLineComment; + p += 2; + } + else + { + if (cur_ident.len == 0) + { + cur_ident.text = &t[p]; + } + ++cur_ident.len; + p += 1; + } + } break; + + case TokenizerMode_SingleLineComment: + { + if (t[p] == '\n') + { /* End single line comment */ + mode = TokenizerMode_None; + p += 1; + } + else + { + p += 1; + } + } break; + + case TokenizerMode_MultiLineComment: + { + if (t[p] == '*' && (p + 1) < l && t[p + 1] == '/') + { /* End multi line comment */ + mode = TokenizerMode_None; + p += 2; + } + else + { + p += 1; + } + } break; + } + } + } + + + return result; +} + +//////////////////////////////// +//~ Parser operations + +M_Layer *M_PushLayer(Arena *arena, M_LayerList *list, M_TokenFile *file) +{ + M_Layer *layer = PushStruct(arena, M_Layer); + *layer = M_NilLayer; + layer->valid = 1; + layer->file = file; + QueuePush_NZ(&M_NilLayer, list->first, list->last, layer, next); + ++list->count; + return layer; +} + +M_Entry *M_PushEntry(Arena *arena, M_Layer *l, M_EntryKind kind, M_Token *entry_token, u64 args_count, M_Token **args) +{ + M_Entry *e = PushStruct(arena, M_Entry); + *e = M_NilEntry; + e->valid = 1; + e->kind = kind; + if (entry_token) e->name_token = entry_token; + for (u64 i = 0; i < MinU64(args_count, countof(e->arg_tokens)); ++i) + { + e->arg_tokens[i] = args[i]; + } + e->args_count = args_count; + QueuePush_NZ(&M_NilEntry, l->first, l->last, e, next); + ++l->count; + return e; +} + +M_LayerList M_LayersFromTokenFiles(Arena *arena, M_TokenFileList lexed) +{ + TempArena scratch = BeginScratch(arena); + M_LayerList result = ZI; + result.first = &M_NilLayer; + result.last = &M_NilLayer; + + /* Copy errors */ + b32 lexer_errors_present = 0; + for (M_TokenFile *lf = lexed.first; lf->valid; lf = lf->next) + { + if (lf->errors.count > 0) + { + M_Layer *layer = M_PushLayer(arena, &result, lf); + M_AppendErrors(arena, &layer->errors, lf->errors); + lexer_errors_present = 1; + } + } + + if (!lexer_errors_present) + { + Dict *rules_dict = InitDict(scratch.arena, 1024); + for (u64 i = 0; i < countof(M_entry_kind_rules); ++i) + { + char *rule_cstr = M_entry_kind_rules[i]; + u64 rule_hash = HashFnv64(Fnv64Basis, StringFromCstrNoLimit(rule_cstr)); + SetDictValue(scratch.arena, rules_dict, rule_hash, i + 1); + } + + for (M_TokenFile *lf = lexed.first; lf->valid; lf = lf->next) + { + M_Layer *layer = M_PushLayer(arena, &result, lf); + + M_Token *entry_token = &M_NilToken; + M_Token *arg_tokens[countof(M_NilEntry.arg_tokens) + 1]; + u64 args_count = 0; + for (u64 i = 0; i < countof(arg_tokens); ++i) + { + arg_tokens[i] = &M_NilToken; + } + + M_Token *token = lf->first_token; + while (token->valid) + { + if (token->kind == M_TokenKind_Eol) + { + if (entry_token->valid) + { + M_Entry *entry = M_PushEntry(arena, layer, M_EntryKind_Unknown, entry_token, args_count, arg_tokens); + { + u64 entry_hash = HashFnv64(Fnv64Basis, entry_token->s); + u64 kind_plus_1 = DictValueFromHash(rules_dict, entry_hash); + if (kind_plus_1 > 0) + { + entry->kind = kind_plus_1 - 1; + } + } + } + token = token->next; + entry_token = &M_NilToken; + args_count = 0; + for (u64 i = 0; i < countof(arg_tokens); ++i) + { + arg_tokens[i] = &M_NilToken; + } + } + else + { + /* Parse entry */ + entry_token = token; + token = token->next; + /* Parse args */ + while (token->kind != M_TokenKind_Eol) + { + if (args_count < countof(arg_tokens)) + { + arg_tokens[args_count++] = token; + } + token = token->next; + } + } + } + } + } + + EndScratch(scratch); + return result; +} + +//////////////////////////////// +//~ Flatten operations + +M_Layer M_GetFlattenedEntries(Arena *arena, M_LayerList unflattened, StringList starting_layer_names) +{ + TempArena scratch = BeginScratch(arena); + M_Layer result = M_NilLayer; + + /* Copy errors */ + b32 unflattened_errors_present = 0; + for (M_Layer *layer = unflattened.first; layer->valid; layer = layer->next) + { + if (layer->errors.count > 0) + { + M_AppendErrors(arena, &result.errors, layer->errors); + unflattened_errors_present = 1; + } + } + + if (!unflattened_errors_present) + { + Enum(IterStateMode) + { + IterStateMode_None, + IterStateMode_Entered, + IterStateMode_Exited + }; + Struct(IterState) + { + M_Layer *layer; + b32 is_entered; + b32 is_exited; + } NilIterState = { + .layer = &M_NilLayer + }; + + /* Construct state lookups */ + Dict *layer_ptr_to_state = InitDict(scratch.arena, 1021); + Dict *layer_name_to_state = InitDict(scratch.arena, 1021); + for (M_Layer *layer = unflattened.first; layer->valid; layer = layer->next) + { + M_Entry *name_entry = &M_NilEntry; + u64 num_name_entries = 0; + for (M_Entry *entry = layer->first; entry->valid; entry = entry->next) + { + if (entry->kind == M_EntryKind_Layer) + { + if (num_name_entries == 0) + { + name_entry = entry; + } + else + { + String err = StringF(arena, "Layer already has name \"%F\"", FmtString(name_entry->arg_tokens[0]->s)); + M_PushError(arena, &result.errors, entry->name_token, err); + } + ++num_name_entries; + } + } + if (num_name_entries == 1 && name_entry->arg_tokens[0]->s.len > 0) + { + IterState *state = PushStruct(scratch.arena, IterState); + state->layer = layer; + + String name = name_entry->arg_tokens[0]->s; + + u64 name_hash = HashFnv64(Fnv64Basis, name); + DictEntry *ptr_dict_entry = EnsureDictEntry(scratch.arena, layer_ptr_to_state, (u64)layer); + DictEntry *name_dict_entry = EnsureDictEntry(scratch.arena, layer_name_to_state, name_hash); + + ptr_dict_entry->value = (u64)state; + if (name_dict_entry->value == 0) + { + name_dict_entry->value = (u64)state; + } + else + { + String err = StringF(arena, "Layer with name \"%F\" already exists", FmtString(name)); + M_PushError(arena, &result.errors, name_entry->arg_tokens[0], err); + } + } + else if (num_name_entries == 0) + { + M_PushError(arena, &result.errors, layer->file->first_token, Lit("Layer is missing a name")); + } + } + + Struct(StackNode) { StackNode *next; IterState *state; b32 exit; }; + StackNode *stack = 0; + + /* Init stack with starting layers */ + for (StringListNode *sln = starting_layer_names.first; sln; sln = sln->next) + { + String name = sln->s; + u64 name_hash = HashFnv64(Fnv64Basis, name); + IterState *state = (IterState *)DictValueOrNilFromHash(layer_name_to_state, name_hash, (u64)&NilIterState); + M_Layer *layer = state->layer; + if (layer->valid) + { + StackNode *n = PushStruct(scratch.arena, StackNode); + n->state = state; + StackPush(stack, n); + } + else + { + String err = StringF(arena, "Starting layer \"%F\" not found", FmtString(name)); + M_PushError(arena, &result.errors, 0, err); + } + } + + /* Flatten via post-order DFS */ + while (stack) + { + StackNode *stack_node = stack; + IterState *state = stack->state; + M_Layer *layer = state->layer; + StackPop(stack); + + if (stack_node->exit) + { + /* Push items to sorted root */ + state->is_entered = 0; + state->is_exited = 1; + for (M_Entry *entry = layer->first; entry->valid; entry = entry->next) + { + M_PushEntry(arena, &result, entry->kind, entry->name_token, entry->args_count, entry->arg_tokens); + } + } + else + { + if (state->is_entered) + { + /* Cyclic dependency */ + /* FIXME: Handle cyclic dependency error */ + Assert(0); + } + else if (!state->is_exited) + { + state->is_entered = 1; + + /* Push downstream impl enters to stack */ + for (M_Entry *entry = layer->first; entry->valid; entry = entry->next) + { + b32 include = (PlatformIsWindows && entry->kind == M_EntryKind_DefaultWindowsImpl); + if (include) + { + M_Token *impl_token = entry->arg_tokens[0]; + if (impl_token->valid) + { + String impl_name = impl_token->s; + u64 hash = HashFnv64(Fnv64Basis, impl_name); + IterState *impl_layer_state = (IterState *)DictValueOrNilFromHash(layer_name_to_state, hash, (u64)&NilIterState); + M_Layer *impl_layer = impl_layer_state->layer; + if (impl_layer->valid) + { + if (!impl_layer_state->is_exited) + { + StackNode *n = PushStruct(scratch.arena, StackNode); + n->state = impl_layer_state; + StackPush(stack, n); + } + } + else + { + String err = StringF(arena, "Layer \"%F\" not found", FmtString(impl_name)); + M_PushError(arena, &result.errors, impl_token, err); + } + } + else + { + M_PushError(arena, &result.errors, entry->name_token, Lit("Expected layer argument")); + } + } + } + + /* Push node exit to stack */ + { + stack_node->exit = 1; + StackPush(stack, stack_node); + } + + /* Push upstream dep enters to stack */ + for (M_Entry *entry = layer->first; entry->valid; entry = entry->next) + { + if (entry->kind == M_EntryKind_Dep) + { + M_Token *dep_token = entry->arg_tokens[0]; + if (dep_token->valid) + { + String dep_name = dep_token->s; + u64 hash = HashFnv64(Fnv64Basis, dep_name); + IterState *dep_layer_state = (IterState *)DictValueOrNilFromHash(layer_name_to_state, hash, (u64)&NilIterState); + M_Layer *dep_layer = dep_layer_state->layer; + if (dep_layer->valid) + { + if (!dep_layer_state->is_exited) + { + StackNode *n = PushStruct(scratch.arena, StackNode); + n->state = dep_layer_state; + StackPush(stack, n); + } + } + else + { + String err = StringF(arena, "Layer \"%F\" not found", FmtString(dep_name)); + M_PushError(arena, &result.errors, dep_token, err); + } + } + else + { + M_PushError(arena, &result.errors, entry->name_token, Lit("Expected layer argument")); + } + } + } + } + } + } + } + + EndScratch(scratch); + return result; +} diff --git a/src/meta/meta_lay.h b/src/meta/meta_lay.h new file mode 100644 index 00000000..a76d3cbe --- /dev/null +++ b/src/meta/meta_lay.h @@ -0,0 +1,154 @@ +//////////////////////////////// +//~ Error types + +Struct(M_Error) +{ + M_Error *next; + String msg; + struct M_Token *token; +}; + +Struct(M_ErrorList) +{ + M_Error *first; + M_Error *last; + u64 count; +}; + +//////////////////////////////// +//~ File types + +Struct(M_File) +{ + String name; + String data; +}; + +//////////////////////////////// +//~ Token types + +Enum(M_TokenKind) +{ + M_TokenKind_Ident, + M_TokenKind_Eol, /* End of line */ +}; + +Struct(M_Token) +{ + b32 valid; + M_Token *next; + + M_TokenKind kind; + struct M_TokenFile *file; + + String s; +} extern Readonly M_NilToken; + +Struct(M_TokenFile) +{ + b32 valid; + M_TokenFile *next; + + String name; + String data; + + M_Token *first_token; + M_Token *last_token; + u64 tokens_count; + + M_ErrorList errors; +} extern Readonly M_NilTokenFile; + +Struct(M_TokenFileList) +{ + M_TokenFile *first; + M_TokenFile *last; + u64 count; +}; + +//////////////////////////////// +//~ Entry types + +Enum(M_EntryKind) +{ + M_EntryKind_Unknown, + M_EntryKind_Layer, + M_EntryKind_Dep, + M_EntryKind_IncludeC, + M_EntryKind_IncludeGpu, + M_EntryKind_DefaultWindowsImpl, + M_EntryKind_Startup, + M_EntryKind_EmbedDir, +}; + +Struct(M_EntryKindMatch) +{ + char *match_cstr; + u64 max_args; +}; + +Global Readonly char *M_entry_kind_rules[] = { + [M_EntryKind_Layer] = "@Layer", + [M_EntryKind_Dep] = "@Dep", + [M_EntryKind_IncludeC] = "@IncludeC", + [M_EntryKind_IncludeGpu] = "@IncludeGpu", + [M_EntryKind_DefaultWindowsImpl] = "@DefaultWindowsImpl", + [M_EntryKind_Startup] = "@Startup", + [M_EntryKind_EmbedDir] = "@EmbedDir", +}; + +Struct(M_Entry) +{ + b32 valid; + M_Entry *next; + + M_EntryKind kind; + M_Token *name_token; + + M_Token *arg_tokens[2]; + u64 args_count; +} extern Readonly M_NilEntry; + +Struct(M_Layer) +{ + b32 valid; + M_Layer *next; + + M_TokenFile *file; + + M_Entry *first; + M_Entry *last; + u64 count; + M_ErrorList errors; +} extern Readonly M_NilLayer; + +Struct(M_LayerList) +{ + M_Layer *first; + M_Layer *last; + u64 count; +}; + +//////////////////////////////// +//~ Error helpers + +M_Error *M_PushError(Arena *arena, M_ErrorList *l, M_Token *token, String msg); +void M_AppendErrors(Arena *arena, M_ErrorList *dst, M_ErrorList src); + +//////////////////////////////// +//~ Lexer operations + +M_Token *M_PushToken(Arena *arena, M_TokenFile *file, String s, M_TokenKind kind); +M_TokenFileList M_TokensFromSrcDirs(Arena *arena, StringList src_dirs); + +//////////////////////////////// +//~ Parser operations + +M_Layer *M_PushLayer(Arena *arena, M_LayerList *list, M_TokenFile *file); +M_Entry *M_PushEntry(Arena *arena, M_Layer *l, M_EntryKind kind, M_Token *entry_token, u64 args_count, M_Token **args); +M_LayerList M_LayersFromTokenFiles(Arena *arena, M_TokenFileList token_files); + +//////////////////////////////// +//~ Flatten operations + +M_Layer M_GetFlattenedEntries(Arena *arena, M_LayerList unflattened, StringList starting_layer_names); diff --git a/src/net/net.c b/src/net/net.c index c147d912..6d925ab9 100644 --- a/src/net/net.c +++ b/src/net/net.c @@ -582,7 +582,7 @@ N_EventList N_BeginUpdate(Arena *arena, N_Host *host) { //struct sock *sock = packet->sock; P_Address address = packet->address; - BB_Buff bb = BitbuffFromString(packet->data); + BB_Buff bb = BB_BuffFromString(packet->data); BB_Reader br = BB_ReaderFromBuff(&bb); u32 magic = BB_ReadUBits(&br, 32); /* TODO: implicitly encode magic into crc32 */ if (magic == N_PacketMagic) @@ -874,7 +874,7 @@ void N_EndUpdate(N_Host *host) { u8 packet_flags = 0; N_SndPacket *packet = N_PushSndPacket(channel, 0); - BB_Buff bb = BitbuffFromString(StringFromArray(packet->data)); + BB_Buff bb = BB_BuffFromString(StringFromArray(packet->data)); BB_Writer bw = BB_WriterFromBuff(&bb); BB_WriteUBits(&bw, N_PacketMagic, 32); /* TODO: implicitly encode magic into crc32 */ BB_WriteIBits(&bw, N_PacketKind_TryConnect, 8); @@ -887,7 +887,7 @@ void N_EndUpdate(N_Host *host) { u8 packet_flags = 0; N_SndPacket *packet = N_PushSndPacket(channel, 0); - BB_Buff bb = BitbuffFromString(StringFromArray(packet->data)); + BB_Buff bb = BB_BuffFromString(StringFromArray(packet->data)); BB_Writer bw = BB_WriterFromBuff(&bb); BB_WriteUBits(&bw, N_PacketMagic, 32); /* TODO: implicitly encode magic into crc32 */ BB_WriteIBits(&bw, N_PacketKind_ConnectSuccess, 8); @@ -900,7 +900,7 @@ void N_EndUpdate(N_Host *host) { u8 packet_flags = 0; N_SndPacket *packet = N_PushSndPacket(channel, 0); - BB_Buff bb = BitbuffFromString(StringFromArray(packet->data)); + BB_Buff bb = BB_BuffFromString(StringFromArray(packet->data)); BB_Writer bw = BB_WriterFromBuff(&bb); BB_WriteUBits(&bw, N_PacketMagic, 32); /* TODO: implicitly encode magic into crc32 */ BB_WriteIBits(&bw, N_PacketKind_Disconnect, 8); @@ -913,7 +913,7 @@ void N_EndUpdate(N_Host *host) { u8 packet_flags = 0; N_SndPacket *packet = N_PushSndPacket(channel, 0); - BB_Buff bb = BitbuffFromString(StringFromArray(packet->data)); + BB_Buff bb = BB_BuffFromString(StringFromArray(packet->data)); BB_Writer bw = BB_WriterFromBuff(&bb); BB_WriteUBits(&bw, N_PacketMagic, 32); /* TODO: implicitly encode magic into crc32 */ BB_WriteIBits(&bw, N_PacketKind_Heartbeat, 8); @@ -951,7 +951,7 @@ void N_EndUpdate(N_Host *host) } } N_SndPacket *packet = N_PushSndPacket(channel, is_reliable); - BB_Buff bb = BitbuffFromString(StringFromArray(packet->data)); + BB_Buff bb = BB_BuffFromString(StringFromArray(packet->data)); BB_Writer bw = BB_WriterFromBuff(&bb); BB_WriteUBits(&bw, N_PacketMagic, 32); /* TODO: implicitly encode magic into crc32 */ BB_WriteIBits(&bw, N_PacketKind_MsgChunk, 8); diff --git a/src/net/net.lay b/src/net/net.lay index c7e2ddf6..dcf33e5a 100644 --- a/src/net/net.lay +++ b/src/net/net.lay @@ -2,7 +2,6 @@ //- Dependencies @Dep platform -@Dep bitbuff //- Api @IncludeC net.h diff --git a/src/pp/pp.c b/src/pp/pp.c index 283dd02a..f269db8b 100644 --- a/src/pp/pp.c +++ b/src/pp/pp.c @@ -1150,9 +1150,9 @@ void UpdateUser(P_Window *window) { Entity *ent = sorted[sorted_index]; if (!IsValidAndActive(ent)) continue; - //if (S_IsTagNil(ent->sprite)) continue; + //if (S_IsNil(ent->sprite)) continue; - R_Tag sprite = ent->sprite; + Resource sprite = ent->sprite; Entity *parent = EntityFromId(g->ss_blended, ent->parent); @@ -1214,7 +1214,7 @@ void UpdateUser(P_Window *window) #endif /* Draw sprite */ - if (!R_IsTagNil(sprite)) + if (!IsResourceNil(sprite)) { S_Sheet *sheet = S_SheetFromResourceAsync(sprite); S_Texture *texture = S_TextureFromResourceAsync(sprite); @@ -1244,7 +1244,7 @@ void UpdateUser(P_Window *window) if (HasProp(ent, Prop_TileChunk)) { Vec2I32 chunk_index = ent->tile_chunk_index; - R_Tag tile_sprite = R_TagFromStore(&GameResources, Lit("sprite/tile.ase")); + Resource tile_sprite = ResourceFromStore(&GameResources, Lit("sprite/tile.ase")); S_Texture *tile_texture = S_TextureFromResourceAsync(tile_sprite); if (tile_texture->loaded) { @@ -1323,7 +1323,7 @@ void UpdateUser(P_Window *window) #if 0 /* Draw slices */ - if (!S_IsTagNil(ent->sprite)) + if (!S_IsNil(ent->sprite)) { S_Sheet *sheet = S_SheetFromResourceAsync(sprite); @@ -1754,7 +1754,7 @@ void UpdateUser(P_Window *window) { __profn("Draw crosshair"); Vec2 crosshair_pos = g->ui_cursor; - R_Tag crosshair = R_TagFromStore(GameResources, Lit("sprite/crosshair.ase")); + Resource crosshair = ResourceFromStore(GameResources, Lit("sprite/crosshair.ase")); S_Texture *t = S_TextureFromResourceAsync(crosshair); Vec2 size = VEC2(t->width, t->height); Xform xf = XformFromTrs(TRS(.t = crosshair_pos, .s = size)); @@ -1773,7 +1773,7 @@ void UpdateUser(P_Window *window) } else { - S_Texture *t = S_TextureFromResourceAsync(R_TagFromStore(GameResources, Lit("sprite/crosshair.ase"))); + S_Texture *t = S_TextureFromResourceAsync(ResourceFromStore(GameResources, Lit("sprite/crosshair.ase"))); Vec2 size = VEC2(t->width, t->height); Rect cursor_clip = RectFromVec2(g->ui_screen_offset, g->ui_size); cursor_clip.pos = AddVec2(cursor_clip.pos, MulVec2(size, 0.5f)); @@ -2536,8 +2536,8 @@ JobDef(SimJob, UNUSED sig, UNUSED id) is_master = 1; } - BB_Buff msg_writer_bb = AcquireBitbuff(Gibi(64)); - BB_Buff snapshot_writer_bb = AcquireBitbuff(Gibi(64)); + BB_Buff msg_writer_bb = BB_AcquireBuff(Gibi(64)); + BB_Buff snapshot_writer_bb = BB_AcquireBuff(Gibi(64)); SimAccel accel = AcquireSimAccel(); ClientStore *store = AcquireClientStore(); @@ -2646,7 +2646,7 @@ JobDef(SimJob, UNUSED sig, UNUSED id) { if (client->valid) { - BB_Buff msg_bb = BitbuffFromString(event->msg); + BB_Buff msg_bb = BB_BuffFromString(event->msg); BB_Reader msg_br = BB_ReaderFromBuff(&msg_bb); u64 ack = BB_ReadUV(&msg_br); @@ -2667,7 +2667,7 @@ JobDef(SimJob, UNUSED sig, UNUSED id) u8 *tmp_encoded_bytes = BB_ReadBytesRaw(&msg_br, tmp_encoded_len); if (!tmp_encoded_bytes) break; - BB_Buff decoder_bb = BitbuffFromString(STRING(tmp_encoded_len, tmp_encoded_bytes)); + BB_Buff decoder_bb = BB_BuffFromString(STRING(tmp_encoded_len, tmp_encoded_bytes)); BB_Reader decoder_br = BB_ReaderFromBuff(&decoder_bb); u64 base_tick = BB_ReadUV(&decoder_br); u64 tick = BB_ReadUV(&decoder_br); @@ -2762,7 +2762,7 @@ JobDef(SimJob, UNUSED sig, UNUSED id) Snapshot *base_ss = SnapshotFromTick(client, base_tick); if (base_ss->tick == base_tick) { - BB_Buff bb = BitbuffFromString(n->tmp_encoded); + BB_Buff bb = BB_BuffFromString(n->tmp_encoded); BB_Reader br = BB_ReaderFromBuff(&bb); /* Acquire & decode snapshot */ @@ -3203,7 +3203,7 @@ JobDef(SimJob, UNUSED sig, UNUSED id) ReleaseClientStore(store); ReleaseSimAccel(&accel); - ReleaseBitbuff(&snapshot_writer_bb); - ReleaseBitbuff(&msg_writer_bb); + BB_ReleaseBuff(&snapshot_writer_bb); + BB_ReleaseBuff(&msg_writer_bb); N_ReleaseHost(host); } diff --git a/src/pp/pp.h b/src/pp/pp.h index 51a50027..dbd2f2e1 100644 --- a/src/pp/pp.h +++ b/src/pp/pp.h @@ -273,7 +273,7 @@ extern SharedUserState shared_user_state; //////////////////////////////// //~ Resources -R_DeclStore(GameResources); +DeclResourceStore(GameResources); //////////////////////////////// //~ Startup diff --git a/src/pp/pp.lay b/src/pp/pp.lay index a323c55b..a33ee1de 100644 --- a/src/pp/pp.lay +++ b/src/pp/pp.lay @@ -7,7 +7,6 @@ @Dep collider @Dep net @Dep mixer -@Dep bitbuff @Dep rendertest @Dep playback diff --git a/src/pp/pp_ent.h b/src/pp/pp_ent.h index cb9a8ea4..bd18f2a8 100644 --- a/src/pp/pp_ent.h +++ b/src/pp/pp_ent.h @@ -247,7 +247,7 @@ Struct(Entity) //- Sprite - R_Tag sprite; + Resource sprite; String sprite_span_name; u32 sprite_tint; Vec3 sprite_emittance; diff --git a/src/pp/pp_sim.h b/src/pp/pp_sim.h index b87706aa..6b375c24 100644 --- a/src/pp/pp_sim.h +++ b/src/pp/pp_sim.h @@ -114,11 +114,11 @@ Inline b32 EqClientHandle(ClientHandle a, ClientHandle b) //~ Layer types /* Absolute layers */ -#define Layer_FloorDecals (-300) -#define Layer_Bullets (-200) -#define Layer_Tracers (-100) -#define Layer_Shoulders (0) -#define Layer_Walls (100) +#define Layer_FloorDecals (-300) +#define Layer_Bullets (-200) +#define Layer_Tracers (-100) +#define Layer_Shoulders (0) +#define Layer_Walls (100) /* Relative layers */ #define Layer_DefaultRelative (0) @@ -129,21 +129,21 @@ Inline b32 EqClientHandle(ClientHandle a, ClientHandle b) Enum(ControlFlag) { - ControlFlag_Fire = 1 << 0, - ControlFlag_AltFire = 1 << 1, + ControlFlag_Fire = 1 << 0, + ControlFlag_AltFire = 1 << 1, /* Testing */ - ControlFlag_Drag = 1 << 2, - ControlFlag_Delete = 1 << 3, - ControlFlag_ClearAll = 1 << 4, - ControlFlag_SpawnTest1 = 1 << 5, - ControlFlag_SpawnTest2 = 1 << 6, - ControlFlag_SpawnTest3 = 1 << 7, - ControlFlag_SpawnTest4 = 1 << 8, - ControlFlag_TestWalls = 1 << 9, - ControlFlag_TestTiles = 1 << 10, - ControlFlag_TestExplode = 1 << 11, - ControlFlag_TestTeleport = 1 << 12, + ControlFlag_Drag = 1 << 2, + ControlFlag_Delete = 1 << 3, + ControlFlag_ClearAll = 1 << 4, + ControlFlag_SpawnTest1 = 1 << 5, + ControlFlag_SpawnTest2 = 1 << 6, + ControlFlag_SpawnTest3 = 1 << 7, + ControlFlag_SpawnTest4 = 1 << 8, + ControlFlag_TestWalls = 1 << 9, + ControlFlag_TestTiles = 1 << 10, + ControlFlag_TestExplode = 1 << 11, + ControlFlag_TestTeleport = 1 << 12, }; Struct(ControlData) @@ -179,7 +179,7 @@ StaticAssert(TileKind_Count < 256); /* Tile kind must fit in 8 bits */ Enum(SyncFlag) { - SyncFlag_NoSyncPredictables = 1 << 0 + SyncFlag_NoSyncPredictables = 1 << 0 }; Struct(Snapshot) diff --git a/src/pp/pp_step.c b/src/pp/pp_step.c index c0e4f5ad..c4f82418 100644 --- a/src/pp/pp_step.c +++ b/src/pp/pp_step.c @@ -36,7 +36,7 @@ void ResetSimAccel(Snapshot *ss, SimAccel *accel) Entity *SpawnTestSmg(Entity *parent) { Entity *e = AcquireSyncSrc(parent); - e->sprite = R_TagFromStore(&GameResources, Lit("sprite/gun.ase")); + e->sprite = ResourceFromStore(&GameResources, Lit("sprite/gun.ase")); EnableProp(e, Prop_Attached); e->attach_slice = Lit("attach.wep"); @@ -52,7 +52,7 @@ Entity *SpawnTestSmg(Entity *parent) Entity *SpawnTestLauncher(Entity *parent) { Entity *e = AcquireSyncSrc(parent); - e->sprite = R_TagFromStore(&GameResources, Lit("sprite/gun.ase")); + e->sprite = ResourceFromStore(&GameResources, Lit("sprite/gun.ase")); EnableProp(e, Prop_Attached); e->attach_slice = Lit("attach.wep"); @@ -68,7 +68,7 @@ Entity *SpawnTestLauncher(Entity *parent) Entity *SpawnTestChucker(Entity *parent) { Entity *chucker = AcquireSyncSrc(parent); - chucker->sprite = R_TagFromStore(&GameResources, Lit("sprite/gun.ase")); + chucker->sprite = ResourceFromStore(&GameResources, Lit("sprite/gun.ase")); EnableProp(chucker, Prop_Attached); chucker->attach_slice = Lit("attach.wep"); @@ -119,12 +119,12 @@ Entity *SpawnTestEmployee(Entity *parent) { EnableProp(e, Prop_Test); - e->sprite = R_TagFromStore(&GameResources, Lit("sprite/tim.ase")); + e->sprite = ResourceFromStore(&GameResources, Lit("sprite/tim.ase")); e->mass_unscaled = 10; e->inertia_unscaled = 5; } - //e->sprite = R_TagFromStore(GameResources, Lit("sprite/box_rounded.ase")); + //e->sprite = ResourceFromStore(GameResources, Lit("sprite/box_rounded.ase")); //e->sprite_span_name = Lit("idle.unarmed"); //e->sprite_span_name = Lit("idle.one_handed"); e->sprite_span_name = Lit("idle.two_handed"); @@ -257,7 +257,7 @@ void SpawnTestEntities2(Entity *parent, Vec2 pos) Xform xf = XformFromTrs(TRS(.t = pos, .r = rot, .s = size)); SetXform(e, xf); - e->sprite = R_TagFromStore(&GameResources, Lit("sprite/tile.ase")); + e->sprite = ResourceFromStore(&GameResources, Lit("sprite/tile.ase")); e->layer = Layer_Shoulders; //e->sprite_tint = Alpha32F(ColorBlue, 0.75); @@ -299,7 +299,7 @@ void SpawnTestEntities2(Entity *parent, Vec2 pos) Xform xf = XformFromTrs(.t = pos, .r = r, .s = size); SetXform(e, xf); - e->sprite = R_TagFromStore(GameResources, Lit("sprite/bullet.ase")); + e->sprite = ResourceFromStore(GameResources, Lit("sprite/bullet.ase")); e->sprite_collider_slice = Lit("shape"); e->layer = Layer_Shoulders; @@ -327,7 +327,7 @@ void SpawnTestEntities3(Entity *parent, Vec2 pos) Xform xf = XformFromTrs(TRS(.t = pos, .r = r, .s = size)); SetXform(e, xf); - e->sprite = R_TagFromStore(&GameResources, Lit("sprite/box.ase")); + e->sprite = ResourceFromStore(&GameResources, Lit("sprite/box.ase")); e->layer = Layer_Shoulders; e->sprite_tint = ColorRed; @@ -350,8 +350,8 @@ void SpawnTestEntities4(Entity *parent, Vec2 pos) Xform xf = XformFromTrs(TRS(.t = pos, .r = r, .s = size)); SetXform(e, xf); - //e->sprite = R_TagFromStore(GameResources, Lit("sprite/box.ase")); - e->sprite = R_TagFromStore(&GameResources, Lit("sprite/tile.ase")); + //e->sprite = ResourceFromStore(GameResources, Lit("sprite/box.ase")); + e->sprite = ResourceFromStore(&GameResources, Lit("sprite/tile.ase")); e->layer = Layer_Shoulders; EnableProp(e, Prop_LightTest); @@ -380,10 +380,10 @@ void SpawnTestTile(Snapshot *world, Vec2 world_pos) SetXform(e, xf); e->layer = Layer_Walls; - e->sprite = R_TagFromStore(GameResources, Lit("sprite/tile.ase")); + e->sprite = ResourceFromStore(GameResources, Lit("sprite/tile.ase")); e->sprite_tint = ColorRed; - S_Sheet *sheet = S_SheetFromResourceAwait(e->sprite); + S_Sheet *sheet = S_SheetFromResource(e->sprite); e->sprite_local_xform = XformFromTrs(.s = DivVec2(sheet->frame_size, PIXELS_PER_UNIT)); EnableProp(e, Prop_Solid); @@ -783,7 +783,7 @@ CollisionCallbackFuncDef(OnEntityCollision, data, step_ctx) { Xform xf = XformFromTrs(TRS(.t = point, .r = RandF64FromState(&step_ctx->rand, 0, Tau))); Entity *decal = AcquireSyncSrc(root); - decal->sprite = R_TagFromStore(&GameResources, Lit("sprite/blood.ase")); + decal->sprite = ResourceFromStore(&GameResources, Lit("sprite/blood.ase")); decal->sprite_tint = Rgba32F(1, 1, 1, 0.25f); decal->layer = Layer_FloorDecals; SetXform(decal, xf); @@ -1249,9 +1249,9 @@ void StepSim(SimStepCtx *ctx) { Entity *ent = &world->ents[ent_index]; if (!ShouldSimulate(ent)) continue; - if (R_IsTagNil(ent->sprite)) continue; + if (IsResourceNil(ent->sprite)) continue; - S_Sheet *sheet = S_SheetFromResourceAwait(ent->sprite); + S_Sheet *sheet = S_SheetFromResource(ent->sprite); /* Update animation */ { @@ -1359,8 +1359,8 @@ void StepSim(SimStepCtx *ctx) if (!HasProp(ent, Prop_Attached)) continue; Entity *parent = EntityFromId(world, ent->parent); - R_Tag parent_sprite = parent->sprite; - S_Sheet *parent_sheet = S_SheetFromResourceAwait(parent_sprite); + Resource parent_sprite = parent->sprite; + S_Sheet *parent_sheet = S_SheetFromResource(parent_sprite); Xform parent_sprite_xf = parent->sprite_local_xform; @@ -1450,9 +1450,9 @@ void StepSim(SimStepCtx *ctx) { if (primary_triggered) { - R_Tag sprite = ent->sprite; + Resource sprite = ent->sprite; u32 animation_frame = ent->animation_frame; - S_Sheet *sheet = S_SheetFromResourceAwait(sprite); + S_Sheet *sheet = S_SheetFromResource(sprite); Xform sprite_local_xform = ent->sprite_local_xform; S_Slice out_slice = S_SliceFromName(sheet, Lit("out"), animation_frame); Vec2 rel_pos = MulXformV2(sprite_local_xform, out_slice.center); @@ -1477,7 +1477,7 @@ void StepSim(SimStepCtx *ctx) bullet->local_collider.points[0] = VEC2(0, 0); bullet->local_collider.count = 1; #else - bullet->sprite = R_TagFromStore(GameResources, Lit("sprite/bullet.ase")); + bullet->sprite = ResourceFromStore(GameResources, Lit("sprite/bullet.ase")); bullet->sprite_collider_slice = Lit("shape"); #endif } @@ -1499,9 +1499,9 @@ void StepSim(SimStepCtx *ctx) { if (primary_triggered) { - R_Tag sprite = ent->sprite; + Resource sprite = ent->sprite; u32 animation_frame = ent->animation_frame; - S_Sheet *sheet = S_SheetFromResourceAwait(sprite); + S_Sheet *sheet = S_SheetFromResource(sprite); Xform sprite_local_xform = ent->sprite_local_xform; S_Slice out_slice = S_SliceFromName(sheet, Lit("out"), animation_frame); Vec2 rel_pos = MulXformV2(sprite_local_xform, out_slice.center); @@ -1673,7 +1673,7 @@ void StepSim(SimStepCtx *ctx) Vec2 sprite_hold_pos; Vec2 sprite_hold_dir; { - S_Sheet *sheet = S_SheetFromResourceAwait(ent->sprite); + S_Sheet *sheet = S_SheetFromResource(ent->sprite); S_Slice slice = S_SliceFromName(sheet, Lit("attach.wep"), ent->animation_frame); sprite_hold_pos = slice.center; sprite_hold_dir = slice.dir; diff --git a/src/res/res.c b/src/res/res.c deleted file mode 100644 index 9403be86..00000000 --- a/src/res/res.c +++ /dev/null @@ -1,29 +0,0 @@ - -//////////////////////////////// -//~ Tag helpers - -b32 R_IsTagNil(R_Tag tag) -{ - return tag.hash == 0; -} - -R_Tag R_TagFromStore(R_Store *store, String name) -{ - R_Tag result = ZI; - return result; -} - -//////////////////////////////// -//~ Resource operations - -String R_DataFromTag(R_Tag tag) -{ - String result = ZI; - return result; -} - -String R_NameFromTag(R_Tag tag) -{ - String result = ZI; - return result; -} diff --git a/src/res/res.h b/src/res/res.h deleted file mode 100644 index cfdae0a2..00000000 --- a/src/res/res.h +++ /dev/null @@ -1,29 +0,0 @@ -//////////////////////////////// -//~ Tag types - -Struct(R_Tag) -{ - u64 hash; -}; - -//////////////////////////////// -//~ Store types - -#define R_DeclStore(name) extern R_Store name - -Struct(R_Store) -{ - i32 _; -}; - -//////////////////////////////// -//~ Tag helpers - -b32 R_IsTagNil(R_Tag tag); -R_Tag R_TagFromStore(R_Store *store, String name); - -//////////////////////////////// -//~ Resource operations - -String R_DataFromTag(R_Tag tag); -String R_NameFromTag(R_Tag tag); diff --git a/src/res/res.lay b/src/res/res.lay deleted file mode 100644 index 6f18a60a..00000000 --- a/src/res/res.lay +++ /dev/null @@ -1,7 +0,0 @@ -@Layer res - -//- Api -@IncludeC res.h - -//- Impl -@IncludeC res.c diff --git a/src/sound/sound.c b/src/sound/sound.c index 45a6f54d..e431a0dd 100644 --- a/src/sound/sound.c +++ b/src/sound/sound.c @@ -5,8 +5,8 @@ JobDef(SND_LoadJob, sig, UNUSED id) { __prof; TempArena scratch = BeginScratchNoConflict(); - R_Tag resource = sig->resource; - String name = R_NameFromTag(resource); + Resource resource = sig->resource; + String name = NameFromResource(resource); AC_Asset *asset = sig->asset; SND_SoundFlag flags = sig->flags; @@ -17,7 +17,7 @@ JobDef(SND_LoadJob, sig, UNUSED id) /* Decode */ MP3_Result decoded = ZI; - String resource_data = R_DataFromTag(resource); + String resource_data = DataFromResource(resource); if (resource_data.len > 0) { u64 decode_flags = 0; @@ -80,13 +80,13 @@ JobDef(SND_LoadJob, sig, UNUSED id) //////////////////////////////// //~ Load sound -AC_Asset *SND_LoadAsset(R_Tag resource, SND_SoundFlag flags, b32 wait) +AC_Asset *SND_LoadAsset(Resource resource, SND_SoundFlag flags, b32 wait) { __prof; TempArena scratch = BeginScratchNoConflict(); /* Generate and append sound flags to name key */ - String name = R_NameFromTag(resource); + String name = NameFromResource(resource); String key = StringF(scratch.arena, "%F%F_sound", FmtString(name), @@ -113,7 +113,7 @@ AC_Asset *SND_LoadAsset(R_Tag resource, SND_SoundFlag flags, b32 wait) return asset; } -SND_Sound *SND_LoadSoundAsync(R_Tag resource, SND_SoundFlag flags) +SND_Sound *SND_LoadSoundAsync(Resource resource, SND_SoundFlag flags) { __prof; AC_Asset *asset = SND_LoadAsset(resource, flags, 0); @@ -121,7 +121,7 @@ SND_Sound *SND_LoadSoundAsync(R_Tag resource, SND_SoundFlag flags) return sound; } -SND_Sound *SND_LoadSoundWait(R_Tag resource, SND_SoundFlag flags) +SND_Sound *SND_LoadSoundWait(Resource resource, SND_SoundFlag flags) { __prof; AC_Asset *asset = SND_LoadAsset(resource, flags, 1); diff --git a/src/sound/sound.h b/src/sound/sound.h index 9ada08fd..48f78a49 100644 --- a/src/sound/sound.h +++ b/src/sound/sound.h @@ -19,7 +19,7 @@ Struct(SND_Sound) //////////////////////////////// //~ Sound load operations -JobDecl(SND_LoadJob, { SND_SoundFlag flags; AC_Asset *asset; R_Tag resource; }); -AC_Asset *SND_LoadAsset(R_Tag resource, SND_SoundFlag flags, b32 wait); -SND_Sound *SND_LoadSoundAsync(R_Tag resource, SND_SoundFlag flags); -SND_Sound *SND_LoadSoundWait(R_Tag resource, SND_SoundFlag flags); +JobDecl(SND_LoadJob, { SND_SoundFlag flags; AC_Asset *asset; Resource resource; }); +AC_Asset *SND_LoadAsset(Resource resource, SND_SoundFlag flags, b32 wait); +SND_Sound *SND_LoadSoundAsync(Resource resource, SND_SoundFlag flags); +SND_Sound *SND_LoadSoundWait(Resource resource, SND_SoundFlag flags); diff --git a/src/sound/sound.lay b/src/sound/sound.lay index 6a1c38c6..772231e0 100644 --- a/src/sound/sound.lay +++ b/src/sound/sound.lay @@ -4,7 +4,6 @@ @Dep platform @Dep mp3 @Dep asset_cache -@Dep res //- Api @IncludeC sound.h diff --git a/src/sprite/sprite.c b/src/sprite/sprite.c index 5b96b620..2c60bffb 100644 --- a/src/sprite/sprite.c +++ b/src/sprite/sprite.c @@ -10,34 +10,132 @@ void S_Startup(void) } //////////////////////////////// -//~ Texture operations +//~ Load texture job -S_Texture *S_TextureFromResourceAwait(R_Tag resource) +JobDef(S_LoadTextureJob, sig, _) +{ + S_Entry *entry = sig->entry; + AddCounter(&entry->texture_load_counter, -1); +} + +JobDef(S_LoadSheetJob, sig, _) +{ + S_Entry *entry = sig->entry; + AddCounter(&entry->sheet_load_counter, -1); +} + +//////////////////////////////// +//~ Cache + +S_Entry *S_FetchEntry(Resource resource, JobPool pool, S_FetchFlag flags) +{ + S_SharedState *g = &S_shared_state; + S_Entry *entry = 0; + { + S_EntryBin *bin = &g->entry_bins[resource.hash % S_EntryBinsCount]; + /* Search for entry */ + entry = bin->first; + { + Lock lock = LockS(&bin->mutex); + { + for (; entry; entry = entry->next_in_bin) + { + if (entry->resource.hash == resource.hash) + { + entry = entry; + break; + } + } + } + Unlock(&lock); + } + /* Entry not found, re-check & create */ + if (!entry) + { + Lock lock = LockE(&bin->mutex); + { + /* Re-check */ + entry = bin->first; + for (; entry; entry = entry->next_in_bin) + { + if (entry->resource.hash == resource.hash) + { + entry = entry; + break; + } + } + /* Create */ + if (!entry) + { + entry = PushStruct(PermArena, S_Entry); + entry->resource = resource; + entry->texture = &S_NilTexture; + entry->sheet = &S_NilSheet; + AddCounter(&entry->texture_load_counter, 1); + AddCounter(&entry->sheet_load_counter, 1); + QueuePush_N(bin->first, bin->last, entry, next_in_bin); + } + } + Unlock(&lock); + } + } + /* Launch load jobs */ + if ((flags & S_FetchFlag_Texture) + && !Atomic32Fetch(&entry->texture_touched) + && !Atomic32FetchTestSet(&entry->texture_touched, 0, 1)) + { + RunJob(1, S_LoadTextureJob, pool, JobPriority_Inherit, 0, .entry = entry); + } + if ((flags & S_FetchFlag_Sheet) + && !Atomic32Fetch(&entry->sheet_touched) + && !Atomic32FetchTestSet(&entry->sheet_touched, 0, 1)) + { + RunJob(1, S_LoadSheetJob, pool, JobPriority_Inherit, 0, .entry = entry); + } + return entry; +} + +//////////////////////////////// +//~ Sprite data retrieval operations + +S_Texture *S_TextureFromResource(Resource resource) +{ + S_Entry *entry = S_FetchEntry(resource, JobPool_Inherit, S_FetchFlag_Texture); + YieldOnCounter(&entry->texture_load_counter); + return entry->texture; +} + +S_Texture *S_TextureFromResourceAsync(Resource resource) { S_Texture *result = &S_NilTexture; + S_Entry *entry = S_FetchEntry(resource, JobPool_Inherit, S_FetchFlag_Texture); + if (ValueFromCounter(&entry->texture_load_counter) <= 0) + { + result = entry->texture; + } return result; } -S_Texture *S_TextureFromResourceAsync(R_Tag resource) +S_Sheet *S_SheetFromResource(Resource resource) { - S_Texture *result = &S_NilTexture; + S_Entry *entry = S_FetchEntry(resource, JobPool_Inherit, S_FetchFlag_Sheet); + YieldOnCounter(&entry->sheet_load_counter); + return entry->sheet; +} + +S_Sheet *S_SheetFromResourceAsync(Resource resource) +{ + S_Sheet *result = &S_NilSheet; + S_Entry *entry = S_FetchEntry(resource, JobPool_Inherit, S_FetchFlag_Sheet); + if (ValueFromCounter(&entry->sheet_load_counter) <= 0) + { + result = entry->sheet; + } return result; } //////////////////////////////// -//~ Sheet operations - -S_Sheet *S_SheetFromResourceAwait(R_Tag resource) -{ - S_Sheet *result = &S_NilSheet; - return result; -} - -S_Sheet *S_SheetFromResourceAsync(R_Tag resource) -{ - S_Sheet *result = &S_NilSheet; - return result; -} +//~ Sheet access operations S_Span S_SpanFromName(S_Sheet *sheet, String name) { diff --git a/src/sprite/sprite.h b/src/sprite/sprite.h index e35d4dc5..1bb1b383 100644 --- a/src/sprite/sprite.h +++ b/src/sprite/sprite.h @@ -1,3 +1,28 @@ +//////////////////////////////// +//~ Cache types + +Struct(S_Entry) +{ + S_Entry *next_in_bin; + + struct S_Texture *texture; + struct S_Sheet *sheet; + + Atomic32 texture_touched; + Atomic32 sheet_touched; + + Resource resource; + Counter texture_load_counter; + Counter sheet_load_counter; +}; + +Struct(S_EntryBin) +{ + S_Entry *first; + S_Entry *last; + Mutex mutex; +}; + //////////////////////////////// //~ Texture types @@ -88,9 +113,11 @@ extern Readonly S_Sheet S_NilSheet; //////////////////////////////// //~ Shared state +#define S_EntryBinsCount 1024 + Struct(S_SharedState) { - i32 _; + S_EntryBin entry_bins[S_EntryBinsCount]; }; extern S_SharedState S_shared_state; @@ -101,16 +128,34 @@ extern S_SharedState S_shared_state; void S_Startup(void); //////////////////////////////// -//~ Texture operations +//~ Load jobs -S_Texture *S_TextureFromResource(R_Tag resource); -S_Texture *S_TextureFromResourceAsync(R_Tag resource); +JobDecl(S_LoadTextureJob, { S_Entry *entry; }); +JobDecl(S_LoadSheetJob, { S_Entry *entry; }); //////////////////////////////// -//~ Sheet operations +//~ Cache operations -S_Sheet *S_SheetFromResourceAwait(R_Tag resource); -S_Sheet *S_SheetFromResourceAsync(R_Tag resource); +Enum(S_FetchFlag) +{ + S_FetchFlag_None = 0, + S_FetchFlag_Texture = (1 << 0), + S_FetchFlag_Sheet = (1 << 1), +}; + +S_Entry *S_FetchEntry(Resource resource, JobPool pool, S_FetchFlag flags); + +//////////////////////////////// +//~ Sprite data retrieval operations + +S_Texture *S_TextureFromResource(Resource resource); +S_Texture *S_TextureFromResourceAsync(Resource resource); + +S_Sheet *S_SheetFromResource(Resource resource); +S_Sheet *S_SheetFromResourceAsync(Resource resource); + +//////////////////////////////// +//~ Sheet access operations S_Span S_SpanFromName(S_Sheet *sheet, String name); S_Frame S_FrameFromIndex(S_Sheet *sheet, u64 index);