convert indentation to 2 spaces

This commit is contained in:
jacob 2025-12-18 18:42:53 -06:00
parent c1b768282f
commit 3377e3f94c
133 changed files with 30495 additions and 31007 deletions

View File

@ -11,7 +11,7 @@ set meta_build_cmd=cl.exe ../src/meta/meta.c -Od -Z7 -nologo -diagnostics:column
set meta_rebuild_code=1317212284 set meta_rebuild_code=1317212284
if "%--force_meta_build%"=="1" ( if "%--force_meta_build%"=="1" (
if exist meta.exe del meta.exe if exist meta.exe del meta.exe
) )
echo build_cmd: %program_build_cmd% echo build_cmd: %program_build_cmd%
@ -19,48 +19,48 @@ echo build_cmd: %program_build_cmd%
::- Try to activate Visual Studio if devenv not detected ::- Try to activate Visual Studio if devenv not detected
:: Taken from wcap: https://github.com/mmozeiko/wcap/blob/aa25ccb806d7a6e1c0bfdcca863aabcd8e9badfa/build.cmd#L21-L29 :: Taken from wcap: https://github.com/mmozeiko/wcap/blob/aa25ccb806d7a6e1c0bfdcca863aabcd8e9badfa/build.cmd#L21-L29
if "%PROCESSOR_ARCHITECTURE%" equ "AMD64" ( if "%PROCESSOR_ARCHITECTURE%" equ "AMD64" (
set HOST_ARCH=x64 set HOST_ARCH=x64
) else if "%PROCESSOR_ARCHITECTURE%" equ "ARM64" ( ) else if "%PROCESSOR_ARCHITECTURE%" equ "ARM64" (
set HOST_ARCH=arm64 set HOST_ARCH=arm64
) )
where /Q cl.exe || ( where /Q cl.exe || (
echo ************************************************************************** echo **************************************************************************
echo WARNING: cl.exe not found, attempting to locate Visual Studio installation echo WARNING: cl.exe not found, attempting to locate Visual Studio installation
set __VSCMD_ARG_NO_LOGO=1 set __VSCMD_ARG_NO_LOGO=1
for /f "tokens=*" %%i in ('"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe" -latest -requires Microsoft.VisualStudio.Workload.NativeDesktop -property installationPath') do set VS=%%i for /f "tokens=*" %%i in ('"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe" -latest -requires Microsoft.VisualStudio.Workload.NativeDesktop -property installationPath') do set VS=%%i
if "!VS!" equ "" ( if "!VS!" equ "" (
echo ERROR: Visual Studio installation not found echo ERROR: Visual Studio installation not found
exit /b 1 exit /b 1
) )
echo Visual Studio installation located, activating development environment... echo Visual Studio installation located, activating development environment...
call "!VS!\Common7\Tools\VsDevCmd.bat" -arch=%HOST_ARCH% -host_arch=%HOST_ARCH% -startdir=none -no_logo || exit /b 1 call "!VS!\Common7\Tools\VsDevCmd.bat" -arch=%HOST_ARCH% -host_arch=%HOST_ARCH% -startdir=none -no_logo || exit /b 1
echo Visual studio development environment activated echo Visual studio development environment activated
echo ************************************************************************** echo **************************************************************************
) )
::- Meta build ::- Meta build
:meta_build :meta_build
if not exist meta.exe ( if not exist meta.exe (
echo ====== Meta build ===== echo ====== Meta build =====
%meta_build_cmd% %meta_build_cmd%
set "rc=!errorlevel!" set "rc=!errorlevel!"
if !rc! NEQ 0 ( if !rc! NEQ 0 (
if exist meta.exe del meta.exe if exist meta.exe del meta.exe
exit /b !rc! exit /b !rc!
) )
) )
::- Program build ::- Program build
if not "%--no_program_build%"=="1" ( if not "%--no_program_build%"=="1" (
echo ======== Build ======== echo ======== Build ========
%program_build_cmd% %program_build_cmd%
set "rc=!errorlevel!" set "rc=!errorlevel!"
if !rc! NEQ 0 ( if !rc! NEQ 0 (
if !rc! EQU %meta_rebuild_code% ( if !rc! EQU %meta_rebuild_code% (
del meta.exe del meta.exe
goto meta_build goto meta_build
)
exit /b !rc!
) )
exit /b !rc!
)
) )

File diff suppressed because it is too large Load Diff

View File

@ -3,33 +3,33 @@
Struct(ASE_Slice) Struct(ASE_Slice)
{ {
u32 start; u32 start;
Rng2I32 rect; Rng2I32 rect;
ASE_Slice *next; ASE_Slice *next;
}; };
Struct(ASE_Span) Struct(ASE_Span)
{ {
String name; String name;
u32 start; u32 start;
u32 end; u32 end;
ASE_Span *next; ASE_Span *next;
}; };
Struct(ASE_Frame) Struct(ASE_Frame)
{ {
u32 index; u32 index;
Rng2I32 rect; Rng2I32 rect;
f64 duration; f64 duration;
ASE_Frame *next; ASE_Frame *next;
}; };
Struct(ASE_SliceKey) Struct(ASE_SliceKey)
{ {
String name; String name;
u32 num_slices; u32 num_slices;
ASE_Slice *first_slice; ASE_Slice *first_slice;
ASE_SliceKey *next; ASE_SliceKey *next;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -37,38 +37,38 @@ Struct(ASE_SliceKey)
Struct(ASE_Error) Struct(ASE_Error)
{ {
String msg; String msg;
ASE_Error *next; ASE_Error *next;
}; };
Struct(ASE_ErrorList) Struct(ASE_ErrorList)
{ {
u64 count; u64 count;
ASE_Error *first; ASE_Error *first;
ASE_Error *last; ASE_Error *last;
}; };
Struct(ASE_DecodedImage) Struct(ASE_DecodedImage)
{ {
u32 width; u32 width;
u32 height; u32 height;
u32 *pixels; /* Array of [width * height] pixels */ u32 *pixels; /* Array of [width * height] pixels */
ASE_ErrorList errors; ASE_ErrorList errors;
b32 ok; b32 ok;
}; };
Struct(ASE_DecodedSheet) Struct(ASE_DecodedSheet)
{ {
Vec2 image_size; Vec2 image_size;
Vec2 frame_size; Vec2 frame_size;
u32 num_frames; u32 num_frames;
u32 num_spans; u32 num_spans;
u32 num_slice_keys; u32 num_slice_keys;
ASE_Frame *first_frame; ASE_Frame *first_frame;
ASE_Span *first_span; ASE_Span *first_span;
ASE_SliceKey *first_slice_key; ASE_SliceKey *first_slice_key;
ASE_ErrorList errors; ASE_ErrorList errors;
b32 ok; b32 ok;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -78,29 +78,29 @@ Struct(ASE_DecodedSheet)
Struct(ASE_Bitbuff) Struct(ASE_Bitbuff)
{ {
u8 *data; u8 *data;
u64 cur_bit; u64 cur_bit;
}; };
Enum(ASE_BlockType) Enum(ASE_BlockType)
{ {
ASE_BlockType_Uncompressed = 0, ASE_BlockType_Uncompressed = 0,
ASE_BlockType_CompressedFixed = 1, ASE_BlockType_CompressedFixed = 1,
ASE_BlockType_CompressedDynamic = 2, ASE_BlockType_CompressedDynamic = 2,
ASE_BlockType_Reserved = 3 ASE_BlockType_Reserved = 3
}; };
Struct(ASE_HuffEntry) Struct(ASE_HuffEntry)
{ {
u16 symbol; u16 symbol;
u16 bits_used; u16 bits_used;
}; };
Struct(ASE_HuffDict) Struct(ASE_HuffDict)
{ {
u32 max_code_bits; u32 max_code_bits;
u32 entries_count; u32 entries_count;
ASE_HuffEntry *entries; ASE_HuffEntry *entries;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -108,36 +108,36 @@ Struct(ASE_HuffDict)
Packed(Struct(ASE_Header) Packed(Struct(ASE_Header)
{ {
u32 file_size; u32 file_size;
u16 magic; u16 magic;
u16 frames; u16 frames;
u16 width; u16 width;
u16 height; u16 height;
u16 color_depth; u16 color_depth;
u32 flags; u32 flags;
u16 speed; u16 speed;
u32 _1; u32 _1;
u32 _2; u32 _2;
u8 palette_entry; u8 palette_entry;
u8 _3[3]; u8 _3[3];
u16 num_colors; u16 num_colors;
u8 pixel_width; u8 pixel_width;
u8 pixel_height; u8 pixel_height;
i16 grid_x; i16 grid_x;
i16 grid_y; i16 grid_y;
u16 grid_width; u16 grid_width;
u16 grid_height; u16 grid_height;
u8 _4[84]; u8 _4[84];
}); });
Packed(Struct(ASE_FrameHeader) Packed(Struct(ASE_FrameHeader)
{ {
u32 bytes; u32 bytes;
u16 magic; u16 magic;
u16 chunks_old; u16 chunks_old;
u16 frame_duration_ms; u16 frame_duration_ms;
u8 _[2]; u8 _[2];
u32 chunks_new; u32 chunks_new;
}); });
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -145,63 +145,63 @@ Packed(Struct(ASE_FrameHeader)
Enum(ASE_ChunkKind) Enum(ASE_ChunkKind)
{ {
ASE_ChunkKind_OldPalette1 = 0x0004, ASE_ChunkKind_OldPalette1 = 0x0004,
ASE_ChunkKind_OldPalette2 = 0x0011, ASE_ChunkKind_OldPalette2 = 0x0011,
ASE_ChunkKind_Layer = 0x2004, ASE_ChunkKind_Layer = 0x2004,
ASE_ChunkKind_Cel = 0x2005, ASE_ChunkKind_Cel = 0x2005,
ASE_ChunkKind_CelExtra = 0x2006, ASE_ChunkKind_CelExtra = 0x2006,
ASE_ChunkKind_ColorProfile = 0x2007, ASE_ChunkKind_ColorProfile = 0x2007,
ASE_ChunkKind_ExternalFiles = 0x2008, ASE_ChunkKind_ExternalFiles = 0x2008,
ASE_ChunkKind_Mask = 0x2016, ASE_ChunkKind_Mask = 0x2016,
ASE_ChunkKind_Path = 0x2017, ASE_ChunkKind_Path = 0x2017,
ASE_ChunkKind_Tags = 0x2018, ASE_ChunkKind_Tags = 0x2018,
ASE_ChunkKind_Palette = 0x2019, ASE_ChunkKind_Palette = 0x2019,
ASE_ChunkKind_Userdata = 0x2020, ASE_ChunkKind_Userdata = 0x2020,
ASE_ChunkKind_Slice = 0x2022, ASE_ChunkKind_Slice = 0x2022,
ASE_ChunkKind_Tileset = 0x2023 ASE_ChunkKind_Tileset = 0x2023
}; };
Enum(ASE_CelKind) Enum(ASE_CelKind)
{ {
ASE_CelKind_RawImage = 0, ASE_CelKind_RawImage = 0,
ASE_CelKind_Linked = 1, ASE_CelKind_Linked = 1,
ASE_CelKind_CompressedImage = 2, ASE_CelKind_CompressedImage = 2,
ASE_CelKind_CompressedTilemap = 3 ASE_CelKind_CompressedTilemap = 3
}; };
Struct(ASE_Layer) Struct(ASE_Layer)
{ {
u16 flags; u16 flags;
u16 type; u16 type;
u16 child_level; u16 child_level;
u16 blend_mode; u16 blend_mode;
u8 opacity; u8 opacity;
String name; String name;
u32 tileset_index; u32 tileset_index;
u32 index; u32 index;
ASE_Layer *next; ASE_Layer *next;
}; };
Struct(Ace_Cel) Struct(Ace_Cel)
{ {
u16 layer_index; u16 layer_index;
i16 x_pos; i16 x_pos;
i16 y_pos; i16 y_pos;
u8 opacity; u8 opacity;
ASE_CelKind type; ASE_CelKind type;
i16 z_index; i16 z_index;
/* Linked cel */ /* Linked cel */
u16 frame_pos; u16 frame_pos;
/* Compressed image */ /* Compressed image */
u32 width; u32 width;
u32 height; u32 height;
u32 *pixels; u32 *pixels;
u16 frame_index; u16 frame_index;
Ace_Cel *next; Ace_Cel *next;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////

View File

@ -2,39 +2,39 @@
//~ Compiler flag checks //~ Compiler flag checks
#ifndef IsConsoleApp #ifndef IsConsoleApp
#error Missing compile time definition for 'IsConsoleApp' #error Missing compile time definition for 'IsConsoleApp'
#endif #endif
#ifndef IsRtcEnabled #ifndef IsRtcEnabled
#error Missing compile time definition for 'IsRtcEnabled' #error Missing compile time definition for 'IsRtcEnabled'
#endif #endif
#ifndef IsAsanEnabled #ifndef IsAsanEnabled
#error Missing compile time definition for 'IsAsanEnabled' #error Missing compile time definition for 'IsAsanEnabled'
#endif #endif
#ifndef IsCrtlibEnabled #ifndef IsCrtlibEnabled
#error Missing compile time definition for 'IsCrtlibEnabled' #error Missing compile time definition for 'IsCrtlibEnabled'
#endif #endif
#ifndef IsDebinfoEnabled #ifndef IsDebinfoEnabled
#error Missing compile time definition for 'IsDebinfoEnabled' #error Missing compile time definition for 'IsDebinfoEnabled'
#endif #endif
#ifndef IsDeveloperModeEnabled #ifndef IsDeveloperModeEnabled
#error Missing compile time definition for 'IsDeveloperModeEnabled' #error Missing compile time definition for 'IsDeveloperModeEnabled'
#endif #endif
#ifndef IsUnoptimized #ifndef IsUnoptimized
#error Missing compile time definition for 'IsUnoptimized' #error Missing compile time definition for 'IsUnoptimized'
#endif #endif
#ifndef IsTestingEnabled #ifndef IsTestingEnabled
#error Missing compile time definition for 'IsTestingEnabled' #error Missing compile time definition for 'IsTestingEnabled'
#endif #endif
#ifndef IsHotSwappingEnabled #ifndef IsHotSwappingEnabled
#error Missing compile time definition for 'IsHotSwappingEnabled' #error Missing compile time definition for 'IsHotSwappingEnabled'
#endif #endif
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -42,57 +42,57 @@
//- Compiler //- Compiler
#if defined(__clang__) #if defined(__clang__)
#define IsCompilerClang 1 #define IsCompilerClang 1
#define IsCompilerMsvc 0 #define IsCompilerMsvc 0
#elif defined(_MSC_VER) #elif defined(_MSC_VER)
#define IsCompilerClang 0 #define IsCompilerClang 0
#define IsCompilerMsvc 1 #define IsCompilerMsvc 1
#else #else
#error Unknown compiler #error Unknown compiler
#endif #endif
//- Language //- Language
#if defined(__HLSL_VERSION) #if defined(__HLSL_VERSION)
#define IsLanguageC 0 #define IsLanguageC 0
#define IsLanguageG 1 #define IsLanguageG 1
#else #else
#define IsLanguageC 1 #define IsLanguageC 1
#define IsLanguageG 0 #define IsLanguageG 0
#endif #endif
//- Platform system //- Platform system
#if defined(_WIN32) #if defined(_WIN32)
#define IsPlatformWindows 1 #define IsPlatformWindows 1
#define IsPlatformMac 0 #define IsPlatformMac 0
#define IsPlatformLinux 0 #define IsPlatformLinux 0
#elif defined(__APPLE__) && defined(__MACH__) #elif defined(__APPLE__) && defined(__MACH__)
#define IsPlatformWindows 0 #define IsPlatformWindows 0
#define IsPlatformMac 1 #define IsPlatformMac 1
#define IsPlatformLinux 0 #define IsPlatformLinux 0
#elif defined(__gnu_linux__) #elif defined(__gnu_linux__)
#define IsPlatformWindows 0 #define IsPlatformWindows 0
#define IsPlatformMac 0 #define IsPlatformMac 0
#define IsPlatformLinux 1 #define IsPlatformLinux 1
#elif IsLanguageG #elif IsLanguageG
#define IsPlatformWindows 0 #define IsPlatformWindows 0
#define IsPlatformMac 0 #define IsPlatformMac 0
#define IsPlatformLinux 0 #define IsPlatformLinux 0
#else #else
#error Unknown platform #error Unknown platform
#endif #endif
//- Architecture //- Architecture
#if defined(_M_AMD64) || defined(__amd64__) #if defined(_M_AMD64) || defined(__amd64__)
#define IsArchX64 1 #define IsArchX64 1
#define IsArchArm64 0 #define IsArchArm64 0
#elif defined(_M_ARM64) || defined(__aarch64__) #elif defined(_M_ARM64) || defined(__aarch64__)
#define IsArchX64 0 #define IsArchX64 0
#define IsArchArm64 1 #define IsArchArm64 1
#elif IsLanguageG #elif IsLanguageG
#define IsArchX64 0 #define IsArchX64 0
#define IsArchArm64 0 #define IsArchArm64 0
#else #else
#error Unknown architecture #error Unknown architecture
#endif #endif
//- Cache line size //- Cache line size
@ -102,21 +102,21 @@
//- Windows NTDDI version //- Windows NTDDI version
/* TODO: Remove this */ /* TODO: Remove this */
#if 0 #if 0
#if IsCompilerMsvc #if IsCompilerMsvc
#define NTDDI_WIN11_DT 0x0C0A0000 #define NTDDI_WIN11_DT 0x0C0A0000
#define NTDDI_VERSION 0x0A000000 #define NTDDI_VERSION 0x0A000000
#if IsRtcEnabled #if IsRtcEnabled
#define _ALLOW_RTCc_IN_STL 1 #define _ALLOW_RTCc_IN_STL 1
#endif #endif
#endif #endif
#endif #endif
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ C headers //~ C headers
#if IsLanguageC #if IsLanguageC
#include <stdint.h> #include <stdint.h>
#include <stdarg.h> #include <stdarg.h>
#endif #endif
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -129,27 +129,27 @@
//- Debug assert //- Debug assert
#if IsRtcEnabled #if IsRtcEnabled
#if IsCompilerMsvc #if IsCompilerMsvc
#define Assert(cond) ((cond) ? 1 : (IsRunningInDebugger() ? (*(volatile i32 *)0 = 0) : Panic(Lit(__FILE__ ":" Stringize(__LINE__) ":0: assertion failed: "#cond"")))) #define Assert(cond) ((cond) ? 1 : (IsRunningInDebugger() ? (*(volatile i32 *)0 = 0) : Panic(Lit(__FILE__ ":" Stringize(__LINE__) ":0: assertion failed: "#cond""))))
#define DEBUGBREAK __debugbreak() #define DEBUGBREAK __debugbreak()
#else #else
#define Assert(cond) ((cond) ? 1 : (__builtin_trap(), 0)) #define Assert(cond) ((cond) ? 1 : (__builtin_trap(), 0))
#define DEBUGBREAK __builtin_debugtrap() #define DEBUGBREAK __builtin_debugtrap()
#endif #endif
#define DEBUGBREAKABLE { volatile i32 __DEBUGBREAKABLE_VAR = 0; __DEBUGBREAKABLE_VAR; } (void)0 #define DEBUGBREAKABLE { volatile i32 __DEBUGBREAKABLE_VAR = 0; __DEBUGBREAKABLE_VAR; } (void)0
#else #else
#define Assert(cond) (void)(0) #define Assert(cond) (void)(0)
#endif #endif
//- Address sanitization //- Address sanitization
#if IsAsanEnabled #if IsAsanEnabled
void __asan_poison_memory_region(void const volatile *, size_t); void __asan_poison_memory_region(void const volatile *, size_t);
void __asan_unpoison_memory_region(void const volatile *add, size_t); void __asan_unpoison_memory_region(void const volatile *add, size_t);
#define AsanPoison(addr, size) __asan_poison_memory_region((addr), (size)) #define AsanPoison(addr, size) __asan_poison_memory_region((addr), (size))
#define AsanUnpoison(addr, size) __asan_unpoison_memory_region((addr), (size)) #define AsanUnpoison(addr, size) __asan_unpoison_memory_region((addr), (size))
#else #else
#define AsanPoison(addr, size) #define AsanPoison(addr, size)
#define AsanUnpoison(addr, size) #define AsanUnpoison(addr, size)
#endif #endif
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -157,24 +157,24 @@
//- Zero initialization //- Zero initialization
#if IsLanguageC #if IsLanguageC
#define Zi { 0 } #define Zi { 0 }
#else #else
#define Zi { } #define Zi { }
#endif #endif
//- Inline //- Inline
#define Inline static inline #define Inline static inline
#if IsCompilerMsvc #if IsCompilerMsvc
#define ForceInline Inline __forceinline #define ForceInline Inline __forceinline
#else #else
#define ForceInline Inline __attribute((always_inline)) #define ForceInline Inline __attribute((always_inline))
#endif #endif
#if IsCompilerMsvc #if IsCompilerMsvc
#define ForceNoInline __declspec(noinline) #define ForceNoInline __declspec(noinline)
#else #else
#define ForceNoInline __attribute__((noinline)) #define ForceNoInline __attribute__((noinline))
#endif #endif
//- Static //- Static
@ -183,35 +183,35 @@
//- Read-only //- Read-only
#if IsPlatformWindows #if IsPlatformWindows
#if IsCompilerMsvc #if IsCompilerMsvc
#pragma section(".rdata$", read) #pragma section(".rdata$", read)
#define Readonly __declspec(allocate(".rdata$")) #define Readonly __declspec(allocate(".rdata$"))
#else #else
#define Readonly __declspec(allocate(".rdata$")) #define Readonly __declspec(allocate(".rdata$"))
#endif #endif
#elif IsPlatformMac #elif IsPlatformMac
#define Readonly __attribute((section("__TEXT,__const"))) #define Readonly __attribute((section("__TEXT,__const")))
#else #else
#define Readonly __attribute((section(".rodata"))) #define Readonly __attribute((section(".rodata")))
#endif #endif
//- Thread-local //- Thread-local
#if IsCompilerMsvc #if IsCompilerMsvc
#define ThreadLocal __declspec(thread) #define ThreadLocal __declspec(thread)
#endif #endif
//- Compiler memory barriers //- Compiler memory barriers
#if IsCompilerMsvc #if IsCompilerMsvc
#define CompilerBarrier() _ReadWriteBarrier() #define CompilerBarrier() _ReadWriteBarrier()
#elif IsArchX64 #elif IsArchX64
#define CompilerBarrier() __asm__ volatile("" ::: "memory") #define CompilerBarrier() __asm__ volatile("" ::: "memory")
#endif #endif
//- Fallthrough //- Fallthrough
#if IsCompilerClang #if IsCompilerClang
#define FALLTHROUGH __attribute((fallthrough)) #define FALLTHROUGH __attribute((fallthrough))
#else #else
#define FALLTHROUGH #define FALLTHROUGH
#endif #endif
//- Preprocessor concatenation //- Preprocessor concatenation
@ -253,23 +253,23 @@
#define SllQueuePushNZ(nil,f,l,n,next) \ #define SllQueuePushNZ(nil,f,l,n,next) \
( \ ( \
CheckNil(nil,f) ? \ CheckNil(nil,f) ? \
((f)=(l)=(n),SetNil(nil,(n)->next)) : \ ((f)=(l)=(n),SetNil(nil,(n)->next)) : \
((l)->next=(n),(l)=(n),SetNil(nil,(n)->next)) \ ((l)->next=(n),(l)=(n),SetNil(nil,(n)->next)) \
) )
#define SllQueuePushFrontNZ(nil,f,l,n,next) \ #define SllQueuePushFrontNZ(nil,f,l,n,next) \
( \ ( \
CheckNil(nil,f) ? \ CheckNil(nil,f) ? \
((f)=(l)=(n),SetNil(nil,(n)->next)) : \ ((f)=(l)=(n),SetNil(nil,(n)->next)) : \
((n)->next=(f),(f)=(n)) \ ((n)->next=(f),(f)=(n)) \
) )
#define SllQueuePopNZ(nil,f,l,next) \ #define SllQueuePopNZ(nil,f,l,next) \
( \ ( \
(f)==(l) ? \ (f)==(l) ? \
(SetNil(nil,f),SetNil(nil,l)) : \ (SetNil(nil,f),SetNil(nil,l)) : \
((f)=(f)->next) \ ((f)=(f)->next) \
) )
#define SllQueuePushN(f,l,n,next) SllQueuePushNZ(0,f,l,n,next) #define SllQueuePushN(f,l,n,next) SllQueuePushNZ(0,f,l,n,next)
@ -283,28 +283,28 @@
#define DllStackPushNPZ(nil,f,n,next,prev) \ #define DllStackPushNPZ(nil,f,n,next,prev) \
( \ ( \
SetNil(nil,(n)->prev), \ SetNil(nil,(n)->prev), \
((n)->next = (f)), \ ((n)->next = (f)), \
CheckNil(nil,f) ? (0) : ((f)->prev = (n)), \ CheckNil(nil,f) ? (0) : ((f)->prev = (n)), \
((f) = (n)) \ ((f) = (n)) \
) )
#define DllStackInsertNPZ(nil,f,p,n,next,prev) \ #define DllStackInsertNPZ(nil,f,p,n,next,prev) \
( \ ( \
(CheckNil(nil,f) || CheckNil(nil,p)) ? (DllStackPushNPZ(nil,(f),(n),next,prev)) : \ (CheckNil(nil,f) || CheckNil(nil,p)) ? (DllStackPushNPZ(nil,(f),(n),next,prev)) : \
( \ ( \
((n)->prev = (p)), \ ((n)->prev = (p)), \
((n)->next = (p)->next), \ ((n)->next = (p)->next), \
((p)->next = (n)), \ ((p)->next = (n)), \
CheckNil(nil,(p)->next) ? (0) : ((p)->next->prev = (n)) \ CheckNil(nil,(p)->next) ? (0) : ((p)->next->prev = (n)) \
) \ ) \
) )
#define DllStackRemoveNPZ(nil,f,n,next,prev) \ #define DllStackRemoveNPZ(nil,f,n,next,prev) \
( \ ( \
((n) == (f) ? ((f) = (n)->next) : (0)), \ ((n) == (f) ? ((f) = (n)->next) : (0)), \
(CheckNil(nil,(n)->next) ? (0) : ((n)->next->prev = (n)->prev)), \ (CheckNil(nil,(n)->next) ? (0) : ((n)->next->prev = (n)->prev)), \
(CheckNil(nil,(n)->prev) ? (0) : ((n)->prev->next = (n)->next)) \ (CheckNil(nil,(n)->prev) ? (0) : ((n)->prev->next = (n)->next)) \
) )
#define DllStackPushNP(f,n,next,prev) DllStackPushNPZ(0,f,n,next,prev) #define DllStackPushNP(f,n,next,prev) DllStackPushNPZ(0,f,n,next,prev)
@ -318,29 +318,29 @@
#define DllQueueInsertNPZ(nil,f,l,p,n,next,prev) \ #define DllQueueInsertNPZ(nil,f,l,p,n,next,prev) \
( \ ( \
CheckNil(nil,f) ? \ CheckNil(nil,f) ? \
((f) = (l) = (n), SetNil(nil,(n)->next), SetNil(nil,(n)->prev)) : \ ((f) = (l) = (n), SetNil(nil,(n)->next), SetNil(nil,(n)->prev)) : \
CheckNil(nil,p) ? \ CheckNil(nil,p) ? \
((n)->next = (f), (f)->prev = (n), (f) = (n), SetNil(nil,(n)->prev)) : \ ((n)->next = (f), (f)->prev = (n), (f) = (n), SetNil(nil,(n)->prev)) : \
((p)==(l)) ? \ ((p)==(l)) ? \
((l)->next = (n), (n)->prev = (l), (l) = (n), SetNil(nil, (n)->next)) : \ ((l)->next = (n), (n)->prev = (l), (l) = (n), SetNil(nil, (n)->next)) : \
(((!CheckNil(nil,p) && CheckNil(nil,(p)->next)) ? (0) : \ (((!CheckNil(nil,p) && CheckNil(nil,(p)->next)) ? (0) : \
( \ ( \
(p)->next->prev = (n))), \ (p)->next->prev = (n))), \
((n)->next = (p)->next), \ ((n)->next = (p)->next), \
((p)->next = (n)), \ ((p)->next = (n)), \
((n)->prev = (p)) \ ((n)->prev = (p)) \
) \ ) \
) )
#define DllQueueRemoveNPZ(nil,f,l,n,next,prev) \ #define DllQueueRemoveNPZ(nil,f,l,n,next,prev) \
( \ ( \
((n) == (f) ? (f) = (n)->next : (0)), \ ((n) == (f) ? (f) = (n)->next : (0)), \
((n) == (l) ? (l) = (l)->prev : (0)), \ ((n) == (l) ? (l) = (l)->prev : (0)), \
(CheckNil(nil,(n)->prev) ? (0) : \ (CheckNil(nil,(n)->prev) ? (0) : \
((n)->prev->next = (n)->next)), \ ((n)->prev->next = (n)->next)), \
(CheckNil(nil,(n)->next) ? (0) : \ (CheckNil(nil,(n)->next) ? (0) : \
((n)->next->prev = (n)->prev)) \ ((n)->next->prev = (n)->prev)) \
) )
#define DllQueuePushNPZ(nil,f,l,n,next,prev) DllQueueInsertNPZ(nil,f,l,l,n,next,prev) #define DllQueuePushNPZ(nil,f,l,n,next,prev) DllQueueInsertNPZ(nil,f,l,l,n,next,prev)
@ -384,20 +384,20 @@
//~ Intrinsic headers //~ Intrinsic headers
#if IsLanguageC #if IsLanguageC
/* Intrinsic header info: /* Intrinsic header info:
* mmintrin.h MMX * mmintrin.h MMX
* xmmintrin.h SSE * xmmintrin.h SSE
* emmintrin.h SSE2 * emmintrin.h SSE2
* pmmintrin.h SSE3 * pmmintrin.h SSE3
* tmmintrin.h SSSE3 * tmmintrin.h SSSE3
* smmintrin.h SSE4.1 * smmintrin.h SSE4.1
* nmmintrin.h SSE4.2 * nmmintrin.h SSE4.2
* ammintrin.h SSE4A * ammintrin.h SSE4A
* wmmintrin.h AES * wmmintrin.h AES
* immintrin.h AVX, AVX2, FMA * immintrin.h AVX, AVX2, FMA
*/ */
#include <intrin.h> #include <intrin.h>
#include <nmmintrin.h> /* SSE4.2 */ #include <nmmintrin.h> /* SSE4.2 */
#endif #endif
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -410,14 +410,14 @@
//- Enum //- Enum
#if IsLanguageC #if IsLanguageC
#define Enum(name) typedef enum name name; enum name #define Enum(name) typedef enum name name; enum name
#else #else
#define Enum(name) enum name #define Enum(name) enum name
#endif #endif
//- alignof //- alignof
#if IsLanguageC && (IsCompilerMsvc || __STDC_VERSION__ < 202311L) #if IsLanguageC && (IsCompilerMsvc || __STDC_VERSION__ < 202311L)
#define alignof(type) __alignof(type) #define alignof(type) __alignof(type)
#endif #endif
//- field sizeof //- field sizeof
@ -425,7 +425,7 @@
//- countof //- countof
#if IsLanguageC #if IsLanguageC
#define countof(a) (sizeof(a) / sizeof((a)[0])) #define countof(a) (sizeof(a) / sizeof((a)[0]))
#endif #endif
//- IsFixedArray //- IsFixedArray
@ -434,11 +434,11 @@
//- offsetof //- offsetof
#if !IsCompilerMsvc #if !IsCompilerMsvc
#ifdef _CRT_USE_BUILTIN_OFFSETOF #ifdef _CRT_USE_BUILTIN_OFFSETOF
#define offsetof(type, field) __builtin_offsetof(type, field) #define offsetof(type, field) __builtin_offsetof(type, field)
#else #else
#define offsetof(type, field) ((u64)&(((type *)0)->field)) #define offsetof(type, field) ((u64)&(((type *)0)->field))
#endif #endif
#endif #endif
//- struct region //- struct region
@ -449,44 +449,44 @@
//- Packed //- Packed
#if IsCompilerMsvc #if IsCompilerMsvc
#define Packed(s) __pragma(pack(push, 1)) s __pragma(pack(pop)) #define Packed(s) __pragma(pack(push, 1)) s __pragma(pack(pop))
#elif IsCompilerClang #elif IsCompilerClang
#define Packed(s) s __attribute((__packed__)) #define Packed(s) s __attribute((__packed__))
#elif IsLanguageG #elif IsLanguageG
#define Packed(s) s #define Packed(s) s
#endif #endif
//- alignas //- alignas
#if (IsCompilerMsvc && IsLanguageC) || (IsLanguageC && __STDC_VERSION__ < 202311L) #if (IsCompilerMsvc && IsLanguageC) || (IsLanguageC && __STDC_VERSION__ < 202311L)
#if IsCompilerMsvc #if IsCompilerMsvc
#define alignas(n) __declspec(align(n)) #define alignas(n) __declspec(align(n))
#else #else
#define alignas(n) __attribute__((aligned(n))) #define alignas(n) __attribute__((aligned(n)))
#endif #endif
#endif #endif
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Scalar types //~ Scalar types
#if IsLanguageC #if IsLanguageC
typedef int8_t i8; typedef int8_t i8;
typedef int16_t i16; typedef int16_t i16;
typedef int32_t i32; typedef int32_t i32;
typedef int64_t i64; typedef int64_t i64;
typedef uint8_t u8; typedef uint8_t u8;
typedef uint16_t u16; typedef uint16_t u16;
typedef uint32_t u32; typedef uint32_t u32;
typedef uint64_t u64; typedef uint64_t u64;
typedef float f32; typedef float f32;
typedef double f64; typedef double f64;
typedef i8 b8; typedef i8 b8;
typedef u32 b32; typedef u32 b32;
Struct(U128) { u64 hi; u64 lo; }; Struct(U128) { u64 hi; u64 lo; };
#elif IsLanguageG #elif IsLanguageG
typedef int i32; typedef int i32;
typedef uint u32; typedef uint u32;
typedef float f32; typedef float f32;
typedef uint b32; typedef uint b32;
#endif #endif
//- Min / max constants //- Min / max constants
@ -507,274 +507,274 @@
//- Float infinity / nan constants //- Float infinity / nan constants
#if IsLanguageC #if IsLanguageC
Global const u32 _f32_infinity_u32 = 0x7f800000; Global const u32 _f32_infinity_u32 = 0x7f800000;
Global const f32 *_f32_infinity = (f32 *)&_f32_infinity_u32; Global const f32 *_f32_infinity = (f32 *)&_f32_infinity_u32;
#define F32Infinity (*_f32_infinity) #define F32Infinity (*_f32_infinity)
Global const u64 _f64_infinity_u64 = 0x7ff0000000000000ULL; Global const u64 _f64_infinity_u64 = 0x7ff0000000000000ULL;
Global const f64 *_f64_infinity = (f64 *)&_f64_infinity_u64; Global const f64 *_f64_infinity = (f64 *)&_f64_infinity_u64;
#define F64Infinity (*_f64_infinity) #define F64Infinity (*_f64_infinity)
Global const u32 _f32_nan_u32 = 0x7f800001; Global const u32 _f32_nan_u32 = 0x7f800001;
Global const f32 *_f32_nan = (f32 *)&_f32_nan_u32; Global const f32 *_f32_nan = (f32 *)&_f32_nan_u32;
#define F32Nan (*_f32_nan) #define F32Nan (*_f32_nan)
Global const u64 _f64_nan_u64 = 0x7ff8000000000001; Global const u64 _f64_nan_u64 = 0x7ff8000000000001;
Global const f64 *_f64_nan = (f64 *)&_f64_nan_u64; Global const f64 *_f64_nan = (f64 *)&_f64_nan_u64;
#define F64Nan (*_f64_nan) #define F64Nan (*_f64_nan)
#define IsF32Nan(x) (x != x) #define IsF32Nan(x) (x != x)
#define IsF64Nan(x) (x != x) #define IsF64Nan(x) (x != x)
#endif #endif
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Atomics //~ Atomics
#if IsLanguageC #if IsLanguageC
//- Atomic types //- Atomic types
Struct(Atomic8) { volatile i8 _v; }; Struct(Atomic8) { volatile i8 _v; };
Struct(Atomic16) { volatile i16 _v; }; Struct(Atomic16) { volatile i16 _v; };
Struct(Atomic32) { volatile i32 _v; }; Struct(Atomic32) { volatile i32 _v; };
Struct(Atomic64) { volatile i64 _v; }; Struct(Atomic64) { volatile i64 _v; };
//- Cache-line isolated aligned atomic types //- Cache-line isolated aligned atomic types
AlignedStruct(Atomic8Padded, CachelineSize) { Atomic8 v; }; AlignedStruct(Atomic8Padded, CachelineSize) { Atomic8 v; };
AlignedStruct(Atomic16Padded, CachelineSize) { Atomic16 v; }; AlignedStruct(Atomic16Padded, CachelineSize) { Atomic16 v; };
AlignedStruct(Atomic32Padded, CachelineSize) { Atomic32 v; }; AlignedStruct(Atomic32Padded, CachelineSize) { Atomic32 v; };
AlignedStruct(Atomic64Padded, CachelineSize) { Atomic64 v; }; AlignedStruct(Atomic64Padded, CachelineSize) { Atomic64 v; };
StaticAssert(alignof(Atomic8Padded) == CachelineSize && sizeof(Atomic8Padded) % CachelineSize == 0); StaticAssert(alignof(Atomic8Padded) == CachelineSize && sizeof(Atomic8Padded) % CachelineSize == 0);
StaticAssert(alignof(Atomic16Padded) == CachelineSize && sizeof(Atomic16Padded) % CachelineSize == 0); StaticAssert(alignof(Atomic16Padded) == CachelineSize && sizeof(Atomic16Padded) % CachelineSize == 0);
StaticAssert(alignof(Atomic32Padded) == CachelineSize && sizeof(Atomic32Padded) % CachelineSize == 0); StaticAssert(alignof(Atomic32Padded) == CachelineSize && sizeof(Atomic32Padded) % CachelineSize == 0);
StaticAssert(alignof(Atomic64Padded) == CachelineSize && sizeof(Atomic64Padded) % CachelineSize == 0); StaticAssert(alignof(Atomic64Padded) == CachelineSize && sizeof(Atomic64Padded) % CachelineSize == 0);
#if IsPlatformWindows && IsArchX64 #if IsPlatformWindows && IsArchX64
//- 8 bit atomic ops //- 8 bit atomic ops
ForceInline i8 Atomic8Fetch (Atomic8 *x) { CompilerBarrier(); i8 result = x->_v; CompilerBarrier(); return result; } ForceInline i8 Atomic8Fetch (Atomic8 *x) { CompilerBarrier(); i8 result = x->_v; CompilerBarrier(); return result; }
ForceInline void Atomic8Set (Atomic8 *x, i8 e) { CompilerBarrier(); x->_v = e; CompilerBarrier(); } ForceInline void Atomic8Set (Atomic8 *x, i8 e) { CompilerBarrier(); x->_v = e; CompilerBarrier(); }
ForceInline i8 Atomic8FetchSet (Atomic8 *x, i8 e) { return (i8)_InterlockedExchange8((volatile char *)&x->_v, e); } ForceInline i8 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 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 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); } ForceInline i8 Atomic8FetchAdd (Atomic8 *x, i8 a) { return (i8)_InterlockedExchangeAdd8((volatile char *)&x->_v, a); }
//- 16 bit atomic ops //- 16 bit atomic ops
ForceInline i16 Atomic16Fetch (Atomic16 *x) { CompilerBarrier(); i16 result = x->_v; CompilerBarrier(); return result; } ForceInline i16 Atomic16Fetch (Atomic16 *x) { CompilerBarrier(); i16 result = x->_v; CompilerBarrier(); return result; }
ForceInline void Atomic16Set (Atomic16 *x, i16 e) { CompilerBarrier(); x->_v = e; CompilerBarrier(); } ForceInline void Atomic16Set (Atomic16 *x, i16 e) { CompilerBarrier(); x->_v = e; CompilerBarrier(); }
ForceInline i16 Atomic16FetchSet (Atomic16 *x, i16 e) { return (i16)_InterlockedExchange16(&x->_v, e); } ForceInline i16 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 Atomic16FetchTestSet (Atomic16 *x, i16 c, i16 e) { return (i16)_InterlockedCompareExchange16(&x->_v, e, c); }
ForceInline i16 Atomic16FetchXor (Atomic16 *x, i16 c) { return (i16)_InterlockedXor16(&x->_v, c); } ForceInline i16 Atomic16FetchXor (Atomic16 *x, i16 c) { return (i16)_InterlockedXor16(&x->_v, c); }
ForceInline i16 Atomic16FetchAdd (Atomic16 *x, i16 a) { return (i16)_InterlockedExchangeAdd16(&x->_v, a); } ForceInline i16 Atomic16FetchAdd (Atomic16 *x, i16 a) { return (i16)_InterlockedExchangeAdd16(&x->_v, a); }
//- 32 bit atomic ops //- 32 bit atomic ops
ForceInline i32 Atomic32Fetch (Atomic32 *x) { CompilerBarrier(); i32 result = x->_v; CompilerBarrier(); return result; } ForceInline i32 Atomic32Fetch (Atomic32 *x) { CompilerBarrier(); i32 result = x->_v; CompilerBarrier(); return result; }
ForceInline void Atomic32Set (Atomic32 *x, i32 e) { CompilerBarrier(); x->_v = e; CompilerBarrier(); } ForceInline void Atomic32Set (Atomic32 *x, i32 e) { CompilerBarrier(); x->_v = e; CompilerBarrier(); }
ForceInline i32 Atomic32FetchSet (Atomic32 *x, i32 e) { return (i32)_InterlockedExchange((volatile long *)&x->_v, e); } ForceInline i32 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 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 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); } ForceInline i32 Atomic32FetchAdd (Atomic32 *x, i32 a) { return (i32)_InterlockedExchangeAdd((volatile long *)&x->_v, a); }
//- 64 bit atomic ops //- 64 bit atomic ops
ForceInline i64 Atomic64Fetch (Atomic64 *x) { CompilerBarrier(); i64 result = x->_v; CompilerBarrier(); return result; } ForceInline i64 Atomic64Fetch (Atomic64 *x) { CompilerBarrier(); i64 result = x->_v; CompilerBarrier(); return result; }
ForceInline void Atomic64Set (Atomic64 *x, i64 e) { CompilerBarrier(); x->_v = e; CompilerBarrier(); } ForceInline void Atomic64Set (Atomic64 *x, i64 e) { CompilerBarrier(); x->_v = e; CompilerBarrier(); }
ForceInline i64 Atomic64FetchSet (Atomic64 *x, i64 e) { return (i64)_InterlockedExchange64(&x->_v, e); } ForceInline i64 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 Atomic64FetchTestSet (Atomic64 *x, i64 c, i64 e) { return (i64)_InterlockedCompareExchange64(&x->_v, e, c); }
ForceInline i64 Atomic64FetchXor (Atomic64 *x, i64 c) { return (i64)_InterlockedXor64(&x->_v, c); } ForceInline i64 Atomic64FetchXor (Atomic64 *x, i64 c) { return (i64)_InterlockedXor64(&x->_v, c); }
ForceInline i64 Atomic64FetchAdd (Atomic64 *x, i64 a) { return (i64)_InterlockedExchangeAdd64(&x->_v, a); } ForceInline i64 Atomic64FetchAdd (Atomic64 *x, i64 a) { return (i64)_InterlockedExchangeAdd64(&x->_v, a); }
#else #else
#error Atomics not implemented #error Atomics not implemented
#endif #endif
#endif #endif
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Ticket mutex //~ Ticket mutex
#if IsLanguageC #if IsLanguageC
Struct(TicketMutex) Struct(TicketMutex)
{ {
Atomic64Padded ticket; Atomic64Padded ticket;
Atomic64Padded serving; Atomic64Padded serving;
}; };
ForceInline void LockTicketMutex(TicketMutex *tm) ForceInline void LockTicketMutex(TicketMutex *tm)
{
i64 ticket = Atomic64FetchAdd(&tm->ticket.v, 1);
while (Atomic64Fetch(&tm->serving.v) != ticket)
{ {
i64 ticket = Atomic64FetchAdd(&tm->ticket.v, 1); _mm_pause();
while (Atomic64Fetch(&tm->serving.v) != ticket)
{
_mm_pause();
}
} }
}
ForceInline void UnlockTicketMutex(TicketMutex *tm) ForceInline void UnlockTicketMutex(TicketMutex *tm)
{ {
/* TODO: Atomic set w/ known ticket + 1 */ /* TODO: Atomic set w/ known ticket + 1 */
Atomic64FetchAdd(&tm->serving.v, 1); Atomic64FetchAdd(&tm->serving.v, 1);
} }
#endif #endif
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ String types //~ String types
#if IsLanguageC #if IsLanguageC
#define STRING(size, data) ((String) { (size), (data) }) #define STRING(size, data) ((String) { (size), (data) })
#define Zstr ((String) { 0, 0}) #define Zstr ((String) { 0, 0})
#define Lit(cstr_lit) (String) { (sizeof((cstr_lit)) - 1), (u8 *)(cstr_lit) } #define Lit(cstr_lit) (String) { (sizeof((cstr_lit)) - 1), (u8 *)(cstr_lit) }
#define CompLit(cstr_lit) { .len = (sizeof((cstr_lit)) - 1), .text = (u8 *)(cstr_lit) } #define CompLit(cstr_lit) { .len = (sizeof((cstr_lit)) - 1), .text = (u8 *)(cstr_lit) }
#define StringFromPointers(p0, p1) ((String) { (u8 *)(p1) - (u8 *)(p0), (u8 *)p0 }) #define StringFromPointers(p0, p1) ((String) { (u8 *)(p1) - (u8 *)(p0), (u8 *)p0 })
#define StringFromStruct(ptr) ((String) { sizeof(*(ptr)), (u8 *)(ptr) }) #define StringFromStruct(ptr) ((String) { sizeof(*(ptr)), (u8 *)(ptr) })
#define StringFromArena(arena) (STRING((arena)->pos, ArenaFirst(arena, u8))) #define StringFromArena(arena) (STRING((arena)->pos, ArenaFirst(arena, u8)))
#define StringFromFixedArray(a) \ #define StringFromFixedArray(a) \
( \ ( \
Assert(IsFixedArray(a)), \ Assert(IsFixedArray(a)), \
((String) { .len = sizeof(a), .text = (u8 *)(a) }) \ ((String) { .len = sizeof(a), .text = (u8 *)(a) }) \
) )
Struct(String) Struct(String)
{ {
u64 len; u64 len;
u8 *text; u8 *text;
}; };
Struct(String16) Struct(String16)
{ {
u64 len; u64 len;
u16 *text; u16 *text;
}; };
Struct(String32) Struct(String32)
{ {
u64 len; u64 len;
u32 *text; u32 *text;
}; };
Struct(StringArray) Struct(StringArray)
{ {
u64 count; u64 count;
String *strings; String *strings;
}; };
Struct(StringListNode) Struct(StringListNode)
{ {
String s; String s;
StringListNode *next; StringListNode *next;
StringListNode *prev; StringListNode *prev;
}; };
Struct(StringList) Struct(StringList)
{ {
StringListNode *first; StringListNode *first;
StringListNode *last; StringListNode *last;
u64 count; u64 count;
}; };
#endif #endif
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Arena types //~ Arena types
#if IsLanguageC #if IsLanguageC
Struct(Arena) Struct(Arena)
{ {
u64 pos; u64 pos;
u64 committed; u64 committed;
u64 reserved; u64 reserved;
}; };
Struct(TempArena) Struct(TempArena)
{ {
Arena *arena; Arena *arena;
u64 start_pos; u64 start_pos;
}; };
#endif #endif
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Resource types //~ Resource types
#if IsLanguageC #if IsLanguageC
#define ResourceEmbeddedMagic 0xfc060937194f4406 #define ResourceEmbeddedMagic 0xfc060937194f4406
Struct(ResourceStore) Struct(ResourceStore)
{ {
u64 v; u64 v;
}; };
Struct(ResourceKey) Struct(ResourceKey)
{ {
u64 v; u64 v;
}; };
#endif #endif
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Cpu topology types //~ Cpu topology types
#if IsLanguageC #if IsLanguageC
Struct(CpuTopologyInfo) Struct(CpuTopologyInfo)
{ {
i32 num_logical_cores; /* Includes P cores, Non-P cores, SMT siblings */ i32 num_logical_cores; /* Includes P cores, Non-P cores, SMT siblings */
i32 num_physical_cores; /* Includes P Cores, Non-P Cores */ i32 num_physical_cores; /* Includes P Cores, Non-P Cores */
i32 num_physical_performance_cores; /* Includes P Cores */ i32 num_physical_performance_cores; /* Includes P Cores */
i32 num_physical_non_performance_cores; /* Includes Non-P cores */ i32 num_physical_non_performance_cores; /* Includes Non-P cores */
}; };
#endif #endif
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Shader linkage types //~ Shader linkage types
#if IsLanguageC #if IsLanguageC
Struct(VertexShader) { ResourceKey resource; }; Struct(VertexShader) { ResourceKey resource; };
Struct(PixelShader) { ResourceKey resource; }; Struct(PixelShader) { ResourceKey resource; };
Struct(ComputeShader) { ResourceKey resource; }; Struct(ComputeShader) { ResourceKey resource; };
#elif IsLanguageG #elif IsLanguageG
#define Semantic(t, n) t n : n #define Semantic(t, n) t n : n
#define ComputeShader(name, x) [numthreads(x, 1, 1)] void name(Semantic(u32, SV_DispatchThreadID)) #define ComputeShader(name, x) [numthreads(x, 1, 1)] void name(Semantic(u32, SV_DispatchThreadID))
#define ComputeShader2D(name, x, y) [numthreads(x, y, 1)] void name(Semantic(Vec2U32, SV_DispatchThreadID)) #define ComputeShader2D(name, x, y) [numthreads(x, y, 1)] void name(Semantic(Vec2U32, SV_DispatchThreadID))
#define ComputeShader3D(name, x, y, z) [numthreads(x, y, z)] void name(Semantic(Vec3U32, SV_DispatchThreadID)) #define ComputeShader3D(name, x, y, z) [numthreads(x, y, z)] void name(Semantic(Vec3U32, SV_DispatchThreadID))
#define VertexShader(name, return_type) return_type name(Semantic(u32, SV_InstanceID), Semantic(u32, SV_VertexID)) #define VertexShader(name, return_type) return_type name(Semantic(u32, SV_InstanceID), Semantic(u32, SV_VertexID))
#define PixelShader(name, return_type, ...) return_type name(__VA_ARGS__) #define PixelShader(name, return_type, ...) return_type name(__VA_ARGS__)
#endif #endif
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Exit callback types //~ Exit callback types
#if IsLanguageC #if IsLanguageC
#define ExitFuncDef(name) void name(void) #define ExitFuncDef(name) void name(void)
typedef ExitFuncDef(ExitFunc); typedef ExitFuncDef(ExitFunc);
#endif #endif
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ @hookdecl Core api //~ @hookdecl Core api
#if IsLanguageC #if IsLanguageC
StringList GetRawCommandline(void); StringList GetRawCommandline(void);
void Echo(String msg); void Echo(String msg);
b32 Panic(String msg); b32 Panic(String msg);
b32 IsRunningInDebugger(void); b32 IsRunningInDebugger(void);
i64 TimeNs(void); i64 TimeNs(void);
void TrueRand(String buffer); void TrueRand(String buffer);
CpuTopologyInfo GetCpuTopologyInfo(void); CpuTopologyInfo GetCpuTopologyInfo(void);
void SleepSeconds(f64 seconds); void SleepSeconds(f64 seconds);
#endif #endif
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ @hookdecl Swap //~ @hookdecl Swap
#if IsLanguageC #if IsLanguageC
b32 IsSwappedIn(void); b32 IsSwappedIn(void);
b32 IsSwappingOut(void); b32 IsSwappingOut(void);
String SwappedStateFromName(Arena *arena, String name); String SwappedStateFromName(Arena *arena, String name);
void WriteSwappedState(String name, String data); void WriteSwappedState(String name, String data);
#endif #endif
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ @hookdecl Exit //~ @hookdecl Exit
#if IsLanguageC #if IsLanguageC
void OnExit(ExitFunc *func); void OnExit(ExitFunc *func);
void SignalExit(i32 code); void SignalExit(i32 code);
void ExitNow(i32 code); void ExitNow(i32 code);
#endif #endif
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ @hookdecl Bootstrap layers //~ @hookdecl Bootstrap layers
#if IsLanguageC #if IsLanguageC
void BootstrapLayers(void); void BootstrapLayers(void);
#endif #endif
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////

View File

@ -3,86 +3,86 @@
Arena *AcquireArena(u64 reserve) Arena *AcquireArena(u64 reserve)
{ {
reserve += ArenaHeaderSize; reserve += ArenaHeaderSize;
/* Round up to nearest block size */ /* Round up to nearest block size */
u64 block_remainder = reserve % ArenaBlockSize; u64 block_remainder = reserve % ArenaBlockSize;
if (block_remainder > 0) if (block_remainder > 0)
{ {
reserve += ArenaBlockSize - block_remainder; reserve += ArenaBlockSize - block_remainder;
} }
u8 *base = ReserveMemory(reserve); u8 *base = ReserveMemory(reserve);
if (!base) if (!base)
{ {
Panic(Lit("Failed to reserve memory")); Panic(Lit("Failed to reserve memory"));
} }
u64 reserved = reserve; u64 reserved = reserve;
AddGstat(ArenaMemoryReserved, reserve); AddGstat(ArenaMemoryReserved, reserve);
/* Commit initial block */ /* Commit initial block */
base = CommitMemory(base, ArenaBlockSize); base = CommitMemory(base, ArenaBlockSize);
if (!base) if (!base)
{ {
Panic(Lit("Failed to commit initial memory block: System may be out of memory")); Panic(Lit("Failed to commit initial memory block: System may be out of memory"));
} }
Assert(((u64)base & 0xFFF) == 0); /* Base should be 4k aligned */ Assert(((u64)base & 0xFFF) == 0); /* Base should be 4k aligned */
StaticAssert(ArenaHeaderSize <= ArenaBlockSize); /* Header must fit in first block */ StaticAssert(ArenaHeaderSize <= ArenaBlockSize); /* Header must fit in first block */
StaticAssert(sizeof(Arena) <= ArenaHeaderSize); /* Arena struct must fit in header */ StaticAssert(sizeof(Arena) <= ArenaHeaderSize); /* Arena struct must fit in header */
AsanPoison(base + sizeof(Arena), ArenaBlockSize - sizeof(Arena)); AsanPoison(base + sizeof(Arena), ArenaBlockSize - sizeof(Arena));
AddGstat(ArenaMemoryCommitted, ArenaBlockSize); AddGstat(ArenaMemoryCommitted, ArenaBlockSize);
AddGstat(NumArenas, 1); AddGstat(NumArenas, 1);
/* Create & return arena header at beginning of block */ /* Create & return arena header at beginning of block */
Arena *arena = (Arena *)base; Arena *arena = (Arena *)base;
ZeroStruct(arena); ZeroStruct(arena);
arena->committed = ArenaBlockSize - ArenaHeaderSize; arena->committed = ArenaBlockSize - ArenaHeaderSize;
arena->reserved = reserved; arena->reserved = reserved;
return arena; return arena;
} }
void ReleaseArena(Arena *arena) void ReleaseArena(Arena *arena)
{ {
AsanUnpoison(arena, arena->committed + ArenaHeaderSize); AsanUnpoison(arena, arena->committed + ArenaHeaderSize);
AddGstat(ArenaMemoryCommitted, -(i64)(arena->committed - ArenaHeaderSize)); AddGstat(ArenaMemoryCommitted, -(i64)(arena->committed - ArenaHeaderSize));
AddGstat(ArenaMemoryReserved, -(i64)(arena->reserved)); AddGstat(ArenaMemoryReserved, -(i64)(arena->reserved));
AddGstat(NumArenas, -1); AddGstat(NumArenas, -1);
ReleaseMemory(arena); ReleaseMemory(arena);
} }
/* Copy the memory from src to dst, replacing old contents. /* Copy the memory from src to dst, replacing old contents.
* Dst will expand if necessary. */ * Dst will expand if necessary. */
void CopyArena(Arena *dst, Arena *src) void CopyArena(Arena *dst, Arena *src)
{ {
ResetArena(dst); ResetArena(dst);
u64 data_size = src->pos; u64 data_size = src->pos;
u8 *data_src = ArenaFirst(src, u8); u8 *data_src = ArenaFirst(src, u8);
u8 *data_dst = PushBytesNoZero(dst, data_size, 1); u8 *data_dst = PushBytesNoZero(dst, data_size, 1);
CopyBytes(data_dst, data_src, data_size); CopyBytes(data_dst, data_src, data_size);
} }
void ShrinkArena(Arena *arena) void ShrinkArena(Arena *arena)
{ {
/* Not implemented */ /* Not implemented */
Assert(0); Assert(0);
} }
void SetArenaReadonly(Arena *arena) void SetArenaReadonly(Arena *arena)
{ {
SetMemoryReadonly(arena, arena->committed + ArenaHeaderSize); SetMemoryReadonly(arena, arena->committed + ArenaHeaderSize);
} }
void SetArenaReadWrite(Arena *arena) void SetArenaReadWrite(Arena *arena)
{ {
SetMemoryReadWrite(arena, arena->committed + ArenaHeaderSize); SetMemoryReadWrite(arena, arena->committed + ArenaHeaderSize);
} }
void *ResetArena(Arena *arena) void *ResetArena(Arena *arena)
{ {
PopTo(arena, 0); PopTo(arena, 0);
return ArenaFirst(arena, u8); return ArenaFirst(arena, u8);
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -90,89 +90,89 @@ void *ResetArena(Arena *arena)
void *PushBytesNoZero(Arena *arena, u64 size, u64 align) void *PushBytesNoZero(Arena *arena, u64 size, u64 align)
{ {
Assert(align > 0); Assert(align > 0);
u8 *base = ArenaFirst(arena, u8); u8 *base = ArenaFirst(arena, u8);
u64 start_pos = AlignU64(arena->pos, align); u64 start_pos = AlignU64(arena->pos, align);
u64 end_pos = start_pos + size; u64 end_pos = start_pos + size;
void *result = base + start_pos; void *result = base + start_pos;
/* Commit new block(s) */ /* Commit new block(s) */
if (size > 0 && end_pos > arena->committed) if (size > 0 && end_pos > arena->committed)
{
u64 blocks_needed = (end_pos - arena->committed + ArenaBlockSize - 1) / ArenaBlockSize;
u64 commit_bytes = blocks_needed * ArenaBlockSize;
u64 new_capacity = arena->committed + commit_bytes;
if (new_capacity > arena->reserved)
{ {
u64 blocks_needed = (end_pos - arena->committed + ArenaBlockSize - 1) / ArenaBlockSize; /* Hard fail if we overflow reserved memory for now */
u64 commit_bytes = blocks_needed * ArenaBlockSize; Panic(Lit("Failed to commit new memory block: Overflow of reserved memory"));
u64 new_capacity = arena->committed + commit_bytes;
if (new_capacity > arena->reserved)
{
/* Hard fail if we overflow reserved memory for now */
Panic(Lit("Failed to commit new memory block: Overflow of reserved memory"));
}
void *commit_address = base + arena->committed;
if (!CommitMemory(commit_address, commit_bytes))
{
/* Hard fail on memory allocation failure for now */
Panic(Lit("Failed to commit new memory block: System may be out of memory"));
}
arena->committed += commit_bytes;
AddGstat(ArenaMemoryCommitted, commit_bytes);
AsanPoison(commit_address, commit_bytes);
} }
void *commit_address = base + arena->committed;
if (!CommitMemory(commit_address, commit_bytes))
{
/* Hard fail on memory allocation failure for now */
Panic(Lit("Failed to commit new memory block: System may be out of memory"));
}
arena->committed += commit_bytes;
AddGstat(ArenaMemoryCommitted, commit_bytes);
AsanPoison(commit_address, commit_bytes);
}
AsanUnpoison(result, size); AsanUnpoison(result, size);
arena->pos = end_pos; arena->pos = end_pos;
return result; return result;
} }
void *PushBytes(Arena *arena, u64 size, u64 align) void *PushBytes(Arena *arena, u64 size, u64 align)
{ {
void *p = PushBytesNoZero(arena, size, align); void *p = PushBytesNoZero(arena, size, align);
ZeroBytes(p, size); ZeroBytes(p, size);
return p; return p;
} }
void *PushAlign(Arena *arena, u64 align) void *PushAlign(Arena *arena, u64 align)
{ {
u64 push_count = AlignU64(arena->pos, align) - arena->pos; u64 push_count = AlignU64(arena->pos, align) - arena->pos;
return PushStructsNoZero(arena, u8, push_count); return PushStructsNoZero(arena, u8, push_count);
} }
void PopTo(Arena *arena, u64 pos) void PopTo(Arena *arena, u64 pos)
{ {
Assert(arena->pos >= pos); Assert(arena->pos >= pos);
AsanPoison(ArenaFirst(arena, u8) + pos, arena->pos - pos); AsanPoison(ArenaFirst(arena, u8) + pos, arena->pos - pos);
arena->pos = pos; arena->pos = pos;
} }
void PopBytesNoCopy(Arena *arena, u64 size) void PopBytesNoCopy(Arena *arena, u64 size)
{ {
Assert(arena->pos >= size); Assert(arena->pos >= size);
u64 new_pos = arena->pos - size; u64 new_pos = arena->pos - size;
AsanPoison(ArenaFirst(arena, u8) + new_pos, arena->pos - new_pos); AsanPoison(ArenaFirst(arena, u8) + new_pos, arena->pos - new_pos);
arena->pos = new_pos; arena->pos = new_pos;
} }
void PopBytes(Arena *arena, u64 size, void *copy_dst) void PopBytes(Arena *arena, u64 size, void *copy_dst)
{ {
Assert(arena->pos >= size); Assert(arena->pos >= size);
u64 new_pos = arena->pos - size; u64 new_pos = arena->pos - size;
void *src = (void *)(ArenaFirst(arena, u8) + new_pos); void *src = (void *)(ArenaFirst(arena, u8) + new_pos);
CopyBytes(copy_dst, src, size); CopyBytes(copy_dst, src, size);
AsanPoison(ArenaFirst(arena, u8) + new_pos, arena->pos - new_pos); AsanPoison(ArenaFirst(arena, u8) + new_pos, arena->pos - new_pos);
arena->pos = new_pos; arena->pos = new_pos;
} }
void *ArenaFirst_(Arena *arena, u64 align) void *ArenaFirst_(Arena *arena, u64 align)
{ {
void *result = (void *)AlignU64((u64)arena + ArenaHeaderSize, align); void *result = (void *)AlignU64((u64)arena + ArenaHeaderSize, align);
return result; return result;
} }
void *ArenaNext_(Arena *arena, u64 align) void *ArenaNext_(Arena *arena, u64 align)
{ {
void *result = (void *)AlignU64((u64)arena + ArenaHeaderSize + arena->pos, align); void *result = (void *)AlignU64((u64)arena + ArenaHeaderSize + arena->pos, align);
return result; return result;
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -180,15 +180,15 @@ void *ArenaNext_(Arena *arena, u64 align)
TempArena BeginTempArena(Arena *arena) TempArena BeginTempArena(Arena *arena)
{ {
TempArena t = Zi; TempArena t = Zi;
t.arena = arena; t.arena = arena;
t.start_pos = arena->pos; t.start_pos = arena->pos;
return t; return t;
} }
void EndTempArena(TempArena temp) void EndTempArena(TempArena temp)
{ {
PopTo(temp.arena, temp.start_pos); PopTo(temp.arena, temp.start_pos);
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -196,29 +196,29 @@ void EndTempArena(TempArena temp)
TempArena BeginScratch(Arena *potential_conflict) TempArena BeginScratch(Arena *potential_conflict)
{ {
/* This function is currently hard-coded for 2 thread-local scratch arenas */ /* This function is currently hard-coded for 2 thread-local scratch arenas */
StaticAssert(countof(Base_tl.arenas.scratch) == 2); StaticAssert(countof(Base_tl.arenas.scratch) == 2);
/* Use `BeginScratchNoConflict` if no conflicts are present */ /* Use `BeginScratchNoConflict` if no conflicts are present */
Assert(potential_conflict != 0); Assert(potential_conflict != 0);
Arena *scratch_arena = Base_tl.arenas.scratch[0]; Arena *scratch_arena = Base_tl.arenas.scratch[0];
if (scratch_arena == potential_conflict) if (scratch_arena == potential_conflict)
{ {
scratch_arena = Base_tl.arenas.scratch[1]; scratch_arena = Base_tl.arenas.scratch[1];
} }
TempArena temp = BeginTempArena(scratch_arena); TempArena temp = BeginTempArena(scratch_arena);
return temp; return temp;
} }
TempArena BeginScratchNoConflict_(void) TempArena BeginScratchNoConflict_(void)
{ {
Arena *scratch_arena = Base_tl.arenas.scratch[0]; Arena *scratch_arena = Base_tl.arenas.scratch[0];
TempArena temp = BeginTempArena(scratch_arena); TempArena temp = BeginTempArena(scratch_arena);
return temp; return temp;
} }
void EndScratch(TempArena scratch_temp) void EndScratch(TempArena scratch_temp)
{ {
EndTempArena(scratch_temp); EndTempArena(scratch_temp);
} }

View File

@ -6,8 +6,8 @@
Struct(ThreadLocalArenaCtx) Struct(ThreadLocalArenaCtx)
{ {
Arena *perm; Arena *perm;
Arena *scratch[2]; Arena *scratch[2];
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -68,11 +68,11 @@ TempArena BeginScratchNoConflict_(void);
void EndScratch(TempArena scratch_temp); void EndScratch(TempArena scratch_temp);
/* This macro declares an unused "arena" variable that will produce a shadowing /* This macro declares an unused "arena" variable that will produce a shadowing
* warning variable is present (due to shadowing). This is for catching obvious * warning variable is present (due to shadowing). This is for catching obvious
* cases of `BeginScratchNoConflict` getting called when an `arena` variable * cases of `BeginScratchNoConflict` getting called when an `arena` variable
* already exists in the caller's scope. */ * already exists in the caller's scope. */
#define BeginScratchNoConflict() \ #define BeginScratchNoConflict() \
BeginScratchNoConflict_(); \ BeginScratchNoConflict_(); \
do { \ do { \
u8 arena = 0; \ u8 arena = 0; \
} while (0) } while (0)

View File

@ -3,8 +3,8 @@
void BootstrapAsync(void) void BootstrapAsync(void)
{ {
/* TODO: Dynamic lane counts */ /* TODO: Dynamic lane counts */
DispatchWave(Lit("Async"), 4, AsyncWorkerEntryPoint, 0); DispatchWave(Lit("Async"), 4, AsyncWorkerEntryPoint, 0);
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -12,23 +12,23 @@ void BootstrapAsync(void)
void OnAsyncTick(AsyncTickCallbackFunc *func) void OnAsyncTick(AsyncTickCallbackFunc *func)
{ {
Arena *perm = PermArena(); Arena *perm = PermArena();
AsyncTickCallbackNode *n = PushStruct(perm, AsyncTickCallbackNode); AsyncTickCallbackNode *n = PushStruct(perm, AsyncTickCallbackNode);
n->callback.func = func; n->callback.func = func;
Lock lock = LockE(&Base.async.mutex); Lock lock = LockE(&Base.async.mutex);
{ {
SllQueuePush(Base.async.first_callback_node, Base.async.last_callback_node, n); SllQueuePush(Base.async.first_callback_node, Base.async.last_callback_node, n);
Base.async.callback_nodes_count += 1; Base.async.callback_nodes_count += 1;
} }
Unlock(&lock); Unlock(&lock);
} }
void SignalAsyncTick(void) void SignalAsyncTick(void)
{ {
Atomic64FetchAdd(&Base.async.signal.v, 1); Atomic64FetchAdd(&Base.async.signal.v, 1);
FutexWakeNeq(&Base.async.signal.v); FutexWakeNeq(&Base.async.signal.v);
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -36,67 +36,67 @@ void SignalAsyncTick(void)
void AsyncWorkerEntryPoint(WaveLaneCtx *lane) void AsyncWorkerEntryPoint(WaveLaneCtx *lane)
{ {
AsyncTickCtx tick = Zi; AsyncTickCtx tick = Zi;
tick.arena = AcquireArena(Gibi(64)); tick.arena = AcquireArena(Gibi(64));
/* Tick forever */ /* Tick forever */
for (;;) for (;;)
{
AsyncWorkerCtx *w = &Base.async.worker;
//////////////////////////////
//- Begin tick
if (lane->idx == 0)
{ {
AsyncWorkerCtx *w = &Base.async.worker; /* Wait for signal */
{
////////////////////////////// i64 cur_signal = Atomic64Fetch(&Base.async.signal.v);
//- Begin tick while (cur_signal <= w->last_seen_signal)
if (lane->idx == 0)
{ {
/* Wait for signal */ FutexYieldNeq(&Base.async.signal.v, &cur_signal, sizeof(cur_signal));
{ cur_signal = Atomic64Fetch(&Base.async.signal.v);
i64 cur_signal = Atomic64Fetch(&Base.async.signal.v);
while (cur_signal <= w->last_seen_signal)
{
FutexYieldNeq(&Base.async.signal.v, &cur_signal, sizeof(cur_signal));
cur_signal = Atomic64Fetch(&Base.async.signal.v);
}
w->last_seen_signal = cur_signal;
}
/* Collect callbacks */
{
Lock lock = LockE(&Base.async.mutex);
{
w->callbacks_count = Base.async.callback_nodes_count;
w->callbacks = PushStructsNoZero(tick.arena, AsyncTickCallback, w->callbacks_count);
u64 callback_idx = 0;
for (AsyncTickCallbackNode *n = Base.async.first_callback_node; n; n = n->next)
{
w->callbacks[callback_idx] = n->callback;
++callback_idx;
}
}
Unlock(&lock);
}
} }
w->last_seen_signal = cur_signal;
WaveSync(lane); }
/* Collect callbacks */
////////////////////////////// {
//- Run async callbacks Lock lock = LockE(&Base.async.mutex);
for (u64 callback_idx = 0; callback_idx < w->callbacks_count; ++callback_idx)
{ {
AsyncTickCallback *callback = &w->callbacks[callback_idx]; w->callbacks_count = Base.async.callback_nodes_count;
callback->func(lane, &tick); w->callbacks = PushStructsNoZero(tick.arena, AsyncTickCallback, w->callbacks_count);
} u64 callback_idx = 0;
for (AsyncTickCallbackNode *n = Base.async.first_callback_node; n; n = n->next)
////////////////////////////// {
//- End tick w->callbacks[callback_idx] = n->callback;
++callback_idx;
WaveSync(lane); }
ResetArena(tick.arena);
{
Arena *tick_arena = tick.arena;
ZeroStruct(&tick);
tick.arena = tick_arena;
} }
Unlock(&lock);
}
} }
WaveSync(lane);
//////////////////////////////
//- Run async callbacks
for (u64 callback_idx = 0; callback_idx < w->callbacks_count; ++callback_idx)
{
AsyncTickCallback *callback = &w->callbacks[callback_idx];
callback->func(lane, &tick);
}
//////////////////////////////
//- End tick
WaveSync(lane);
ResetArena(tick.arena);
{
Arena *tick_arena = tick.arena;
ZeroStruct(&tick);
tick.arena = tick_arena;
}
}
} }

View File

@ -6,37 +6,37 @@ typedef void AsyncTickCallbackFunc(WaveLaneCtx *lane, AsyncTickCtx *tick);
Struct(AsyncTickCallback) Struct(AsyncTickCallback)
{ {
AsyncTickCallbackFunc *func; AsyncTickCallbackFunc *func;
}; };
Struct(AsyncTickCallbackNode) Struct(AsyncTickCallbackNode)
{ {
AsyncTickCallbackNode *next; AsyncTickCallbackNode *next;
AsyncTickCallback callback; AsyncTickCallback callback;
}; };
Struct(AsyncTickCtx) Struct(AsyncTickCtx)
{ {
Arena *arena; Arena *arena;
}; };
Struct(AsyncWorkerCtx) Struct(AsyncWorkerCtx)
{ {
i64 last_seen_signal; i64 last_seen_signal;
u64 callbacks_count; u64 callbacks_count;
AsyncTickCallback *callbacks; AsyncTickCallback *callbacks;
}; };
Struct(AsyncCtx) Struct(AsyncCtx)
{ {
Mutex mutex; Mutex mutex;
u64 callback_nodes_count; u64 callback_nodes_count;
AsyncTickCallbackNode *first_callback_node; AsyncTickCallbackNode *first_callback_node;
AsyncTickCallbackNode *last_callback_node; AsyncTickCallbackNode *last_callback_node;
AsyncWorkerCtx worker; AsyncWorkerCtx worker;
Atomic64Padded signal; Atomic64Padded signal;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////

File diff suppressed because it is too large Load Diff

View File

@ -4,13 +4,13 @@
//- Buff //- Buff
Struct(BB_Buff) Struct(BB_Buff)
{ {
b32 is_backed_by_arena; b32 is_backed_by_arena;
/* If `is_arena_bitbuff` is 1, this dynamically-sized arena will be used for reading & writing (meaning writing cannot overflow) */ /* If `is_arena_bitbuff` is 1, this dynamically-sized arena will be used for reading & writing (meaning writing cannot overflow) */
Arena *arena; Arena *arena;
/* If `is_arena_bitbuff` is 0, this fixed-sized buffer willl be used for reading & writing */ /* If `is_arena_bitbuff` is 0, this fixed-sized buffer willl be used for reading & writing */
String fixed_buffer; String fixed_buffer;
}; };
//- Writer //- Writer
@ -18,24 +18,24 @@ Struct(BB_Buff)
#define BB_WriterOverflowArenaPushSize 4096 #define BB_WriterOverflowArenaPushSize 4096
Struct(BB_Writer) Struct(BB_Writer)
{ {
b32 overflowed; b32 overflowed;
BB_Buff *bb; BB_Buff *bb;
u8 *base; u8 *base;
u64 cur_bit; u64 cur_bit;
#if BITBUFF_DEBUG #if BITBUFF_DEBUG
b32 debug_enabled; b32 debug_enabled;
#endif #endif
}; };
//- Reader //- Reader
Struct(BB_Reader) Struct(BB_Reader)
{ {
b32 overflowed; b32 overflowed;
u64 base_len; u64 base_len;
u8 *base; u8 *base;
u64 cur_bit; u64 cur_bit;
#if BITBUFF_DEBUG #if BITBUFF_DEBUG
b32 debug_enabled; b32 debug_enabled;
#endif #endif
}; };
@ -47,16 +47,16 @@ Struct(BB_Reader)
/* Magic numbers inserted to verify read/write type & length */ /* Magic numbers inserted to verify read/write type & length */
Enum(BB_DebugMagicKind) Enum(BB_DebugMagicKind)
{ {
BB_DebugMagicKind_AlignBytes = 0x20A4, BB_DebugMagicKind_AlignBytes = 0x20A4,
BB_DebugMagicKind_AlignToNextByte = 0x379A, BB_DebugMagicKind_AlignToNextByte = 0x379A,
BB_DebugMagicKind_UBits = 0xCB4A, BB_DebugMagicKind_UBits = 0xCB4A,
BB_DebugMagicKind_IBits = 0xB30D, BB_DebugMagicKind_IBits = 0xB30D,
BB_DebugMagicKind_UV = 0xE179, BB_DebugMagicKind_UV = 0xE179,
BB_DebugMagicKind_IV = 0x981f, BB_DebugMagicKind_IV = 0x981f,
BB_DebugMagicKind_F32 = 0x56F9, BB_DebugMagicKind_F32 = 0x56F9,
BB_DebugMagicKind_F64 = 0x7053, BB_DebugMagicKind_F64 = 0x7053,
BB_DebugMagicKind_Uid = 0xA24E, BB_DebugMagicKind_Uid = 0xA24E,
BB_DebugMagicKind_String = 0x7866 BB_DebugMagicKind_String = 0x7866
}; };
#endif #endif
@ -118,11 +118,11 @@ void BB_WriteSeekBytes(BB_Writer *bw, u64 num_bytes);
//~ Writer debug //~ Writer debug
#if BITBUFF_DEBUG #if BITBUFF_DEBUG
void BB_WriteDebugMagic(BB_Writer *bw, BB_DebugMagicKind magic, u8 num_bits); void BB_WriteDebugMagic(BB_Writer *bw, BB_DebugMagicKind magic, u8 num_bits);
void BB_WriteDebugMarker(BB_Writer *bw, String name); void BB_WriteDebugMarker(BB_Writer *bw, String name);
#else #else
#define BB_WriteDebugMagic(bw, magic, num_bits) #define BB_WriteDebugMagic(bw, magic, num_bits)
#define BB_WriteDebugMarker(bw, name) #define BB_WriteDebugMarker(bw, name)
#endif #endif
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////

View File

@ -5,29 +5,29 @@
BuddyCtx *AcquireBuddyCtx(u64 reserve) BuddyCtx *AcquireBuddyCtx(u64 reserve)
{ {
/* TODO: Determine meta reserve dynamically */ /* TODO: Determine meta reserve dynamically */
Arena *meta_arena = AcquireArena(Gibi(64)); Arena *meta_arena = AcquireArena(Gibi(64));
BuddyCtx *ctx = PushStruct(meta_arena, BuddyCtx); BuddyCtx *ctx = PushStruct(meta_arena, BuddyCtx);
ctx->meta_arena = meta_arena; ctx->meta_arena = meta_arena;
ctx->data_arena = AcquireArena(reserve); ctx->data_arena = AcquireArena(reserve);
/* TODO: Minimum block size */ /* TODO: Minimum block size */
ctx->levels = PushStructs(ctx->meta_arena, BuddyLevel, 64); ctx->levels = PushStructs(ctx->meta_arena, BuddyLevel, 64);
for (u64 i = 0; i < 64; ++i) for (u64 i = 0; i < 64; ++i)
{ {
BuddyLevel *level = &ctx->levels[i]; BuddyLevel *level = &ctx->levels[i];
level->ctx = ctx; level->ctx = ctx;
level->tier = i; level->tier = i;
level->size = (u64)1 << i; level->size = (u64)1 << i;
} }
return ctx; return ctx;
} }
void ReleaseBuddyCtx(BuddyCtx *ctx) void ReleaseBuddyCtx(BuddyCtx *ctx)
{ {
ReleaseArena(ctx->data_arena); ReleaseArena(ctx->data_arena);
ReleaseArena(ctx->meta_arena); ReleaseArena(ctx->meta_arena);
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -35,172 +35,172 @@ void ReleaseBuddyCtx(BuddyCtx *ctx)
BuddyBlock *GetUnusedBuddyBlock(BuddyCtx *ctx, BuddyLevel *level) BuddyBlock *GetUnusedBuddyBlock(BuddyCtx *ctx, BuddyLevel *level)
{ {
BuddyBlock *block = 0; BuddyBlock *block = 0;
/* TODO: Tier oob check */ /* TODO: Tier oob check */
if (level->first_unused_block)
{
block = level->first_unused_block;
level->first_unused_block = block->next;
if (level->first_unused_block) if (level->first_unused_block)
{ {
block = level->first_unused_block; level->first_unused_block->prev = 0;
level->first_unused_block = block->next; }
if (level->first_unused_block) block->is_used = 1;
{ block->next = 0;
level->first_unused_block->prev = 0; }
} else
block->is_used = 1; {
block->next = 0; if (level->backed)
{
BuddyLevel *parent_level = &ctx->levels[level->tier + 1];
BuddyBlock *parent_block = GetUnusedBuddyBlock(ctx, parent_level);
/* Create left (used) block from parent block */
BuddyBlock *left = PushBuddyBlock(ctx);
left->is_used = 1;
left->level = level;
left->parent = parent_block;
left->memory = parent_block->memory;
/* Create right LAX block from parent block */
BuddyBlock *right = PushBuddyBlock(ctx);
right->is_used = 0;
right->level = level;
right->parent = parent_block;
right->memory = left->memory + level->size;
if (level->first_unused_block)
{
right->next = level->first_unused_block;
level->first_unused_block->prev = right;
}
level->first_unused_block = right;
left->sibling = right;
right->sibling = left;
block = left;
} }
else else
{ {
if (level->backed) Arena *arena = ctx->data_arena;
{
BuddyLevel *parent_level = &ctx->levels[level->tier + 1];
BuddyBlock *parent_block = GetUnusedBuddyBlock(ctx, parent_level);
/* Create left (used) block from parent block */ /* Grow arena */
BuddyBlock *left = PushBuddyBlock(ctx); i64 level_commit_diff = (level->size * 2) - arena->pos;
left->is_used = 1; if (level_commit_diff > 0)
left->level = level; {
left->parent = parent_block; PushStructsNoZero(arena, u8, level_commit_diff);
left->memory = parent_block->memory; Assert(arena->pos == (level->size * 2));
}
/* Create right LAX block from parent block */ /* Create left (used) block from existing child block memory */
BuddyBlock *right = PushBuddyBlock(ctx); BuddyBlock *left = PushBuddyBlock(ctx);
right->is_used = 0; left->is_used = 1;
right->level = level; left->level = level;
right->parent = parent_block; left->memory = ArenaFirst(arena, u8);
right->memory = left->memory + level->size;
if (level->first_unused_block)
{
right->next = level->first_unused_block;
level->first_unused_block->prev = right;
}
level->first_unused_block = right;
left->sibling = right; /* Create right LAX block from new arena memory */
right->sibling = left; BuddyBlock *right = PushBuddyBlock(ctx);
block = left; right->is_used = 0;
} right->level = level;
else right->memory = left->memory + level->size;
{
Arena *arena = ctx->data_arena;
/* Grow arena */ left->sibling = right;
i64 level_commit_diff = (level->size * 2) - arena->pos; right->sibling = left;
if (level_commit_diff > 0) block = left;
{
PushStructsNoZero(arena, u8, level_commit_diff);
Assert(arena->pos == (level->size * 2));
}
/* Create left (used) block from existing child block memory */ level->backed = 1;
BuddyBlock *left = PushBuddyBlock(ctx);
left->is_used = 1;
left->level = level;
left->memory = ArenaFirst(arena, u8);
/* Create right LAX block from new arena memory */
BuddyBlock *right = PushBuddyBlock(ctx);
right->is_used = 0;
right->level = level;
right->memory = left->memory + level->size;
left->sibling = right;
right->sibling = left;
block = left;
level->backed = 1;
}
} }
}
return block; return block;
} }
BuddyBlock *PushBuddyBlock(BuddyCtx *ctx) BuddyBlock *PushBuddyBlock(BuddyCtx *ctx)
{ {
BuddyBlock *block; BuddyBlock *block;
if (ctx->first_free_block) if (ctx->first_free_block)
{ {
block = ctx->first_free_block; block = ctx->first_free_block;
ctx->first_free_block = block->next; ctx->first_free_block = block->next;
} }
else else
{ {
block = PushStructNoZero(ctx->meta_arena, BuddyBlock); block = PushStructNoZero(ctx->meta_arena, BuddyBlock);
} }
ZeroStruct(block); ZeroStruct(block);
return block; return block;
} }
void PopBuddyBlock(BuddyCtx *ctx, BuddyLevel *level, BuddyBlock *block) void PopBuddyBlock(BuddyCtx *ctx, BuddyLevel *level, BuddyBlock *block)
{ {
/* Remove from unused list */ /* Remove from unused list */
{
BuddyBlock *prev = block->prev;
BuddyBlock *next = block->next;
if (prev)
{ {
BuddyBlock *prev = block->prev; prev->next = next;
BuddyBlock *next = block->next;
if (prev)
{
prev->next = next;
}
else
{
level->first_unused_block = next;
}
if (next)
{
next->prev = prev;
}
} }
block->next = ctx->first_free_block; else
ctx->first_free_block = block; {
level->first_unused_block = next;
}
if (next)
{
next->prev = prev;
}
}
block->next = ctx->first_free_block;
ctx->first_free_block = block;
} }
BuddyBlock *AcquireBuddyBlock(BuddyCtx *ctx, u64 size) BuddyBlock *AcquireBuddyBlock(BuddyCtx *ctx, u64 size)
{ {
if (size > 0x00FFFFFFFFFFFFFFULL) if (size > 0x00FFFFFFFFFFFFFFULL)
{ {
/* TODO: Error */ /* TODO: Error */
Assert(0); Assert(0);
} }
/* TODO: Minimum block size */ /* TODO: Minimum block size */
/* TODO: Faster MSB calculation */ /* TODO: Faster MSB calculation */
u64 desired_block_size = 1; u64 desired_block_size = 1;
u64 desired_level_tier = 0; u64 desired_level_tier = 0;
while (desired_block_size < size && desired_level_tier < 64) while (desired_block_size < size && desired_level_tier < 64)
{ {
desired_block_size <<= 1; desired_block_size <<= 1;
++desired_level_tier; ++desired_level_tier;
} }
BuddyBlock *block = GetUnusedBuddyBlock(ctx, &ctx->levels[desired_level_tier]); BuddyBlock *block = GetUnusedBuddyBlock(ctx, &ctx->levels[desired_level_tier]);
return block; return block;
} }
void ReleaseBuddyBlock(BuddyBlock *block) void ReleaseBuddyBlock(BuddyBlock *block)
{ {
block->is_used = 0; block->is_used = 0;
BuddyLevel *level = block->level; BuddyLevel *level = block->level;
BuddyBlock *parent = block->parent; BuddyBlock *parent = block->parent;
BuddyBlock *sibling = block->sibling; BuddyBlock *sibling = block->sibling;
if (!sibling->is_used && parent != 0) if (!sibling->is_used && parent != 0)
{
/* Merge siblings */
BuddyCtx *ctx = level->ctx;
PopBuddyBlock(ctx, level, block);
PopBuddyBlock(ctx, level, sibling);
/* Release parent */
ReleaseBuddyBlock(parent);
}
else
{
if (level->first_unused_block)
{ {
/* Merge siblings */ block->next = level->first_unused_block;
BuddyCtx *ctx = level->ctx; level->first_unused_block->prev = block;
PopBuddyBlock(ctx, level, block);
PopBuddyBlock(ctx, level, sibling);
/* Release parent */
ReleaseBuddyBlock(parent);
}
else
{
if (level->first_unused_block)
{
block->next = level->first_unused_block;
level->first_unused_block->prev = block;
}
level->first_unused_block = block;
} }
level->first_unused_block = block;
}
} }

View File

@ -4,35 +4,35 @@
//- Block //- Block
Struct(BuddyBlock) Struct(BuddyBlock)
{ {
b32 is_used; b32 is_used;
struct BuddyLevel *level; struct BuddyLevel *level;
BuddyBlock *parent; BuddyBlock *parent;
BuddyBlock *sibling; BuddyBlock *sibling;
/* Links to block in level's unused list or in ctx's free list */ /* Links to block in level's unused list or in ctx's free list */
BuddyBlock *prev; BuddyBlock *prev;
BuddyBlock *next; BuddyBlock *next;
u8 *memory; u8 *memory;
}; };
//- Level //- Level
Struct(BuddyLevel) Struct(BuddyLevel)
{ {
struct BuddyCtx *ctx; struct BuddyCtx *ctx;
b32 backed; /* Signals whether this level is backed by memory in the ctx arena */ b32 backed; /* Signals whether this level is backed by memory in the ctx arena */
u32 tier; u32 tier;
u64 size; u64 size;
BuddyBlock *first_unused_block; BuddyBlock *first_unused_block;
}; };
//- Ctx //- Ctx
Struct(BuddyCtx) Struct(BuddyCtx)
{ {
Arena *meta_arena; Arena *meta_arena;
Arena *data_arena; Arena *data_arena;
BuddyLevel *levels; BuddyLevel *levels;
BuddyBlock *first_free_block; BuddyBlock *first_free_block;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////

View File

@ -3,70 +3,70 @@
void BootstrapCmdline(void) void BootstrapCmdline(void)
{ {
TempArena scratch = BeginScratchNoConflict(); TempArena scratch = BeginScratchNoConflict();
{
StringList raw = GetRawCommandline();
u64 tmp_args_count = 0;
u64 tmp_positionals_count = 0;
CommandlineArg *tmp_args = PushStructs(scratch.arena, CommandlineArg, raw.count);
String *tmp_positionals = PushStructs(scratch.arena, String, raw.count);
{ {
StringList raw = GetRawCommandline(); String name = Zi;
for (StringListNode *n = raw.first; n; n = n->next)
u64 tmp_args_count = 0; {
u64 tmp_positionals_count = 0; String s = n->s;
CommandlineArg *tmp_args = PushStructs(scratch.arena, CommandlineArg, raw.count); if (StringBeginsWith(s, Lit("--")))
String *tmp_positionals = PushStructs(scratch.arena, String, raw.count);
{ {
String name = Zi; if (name.len > 0)
for (StringListNode *n = raw.first; n; n = n->next) {
{ CommandlineArg *arg = &tmp_args[tmp_args_count++];
String s = n->s; arg->name = name;
if (StringBeginsWith(s, Lit("--"))) arg->exists = 1;
{ }
if (name.len > 0) name = TrimLeft(s, Lit("--"));
{
CommandlineArg *arg = &tmp_args[tmp_args_count++];
arg->name = name;
arg->exists = 1;
}
name = TrimLeft(s, Lit("--"));
}
else
{
if (name.len > 0)
{
CommandlineArg *arg = &tmp_args[tmp_args_count++];
arg->name = name;
arg->value = s;
arg->exists = 1;
name = Zstr;
}
else
{
tmp_positionals[tmp_positionals_count++] = s;
}
}
}
if (name.len > 0)
{
CommandlineArg *arg = &tmp_args[tmp_args_count++];
arg->name = name;
arg->exists = 1;
}
} }
else
Arena *perm = PermArena();
Base.cmdline.positional_args_count = tmp_positionals_count;
Base.cmdline.positional_args = PushStructsNoZero(perm, String, tmp_positionals_count);
CopyStructs(Base.cmdline.positional_args, tmp_positionals, tmp_positionals_count);
for (u64 i = 0; i < tmp_args_count; ++i)
{ {
CommandlineArg arg = tmp_args[i]; if (name.len > 0)
CommandlineArgNode *n = PushStruct(perm, CommandlineArgNode); {
u64 hash = HashFnv64(Fnv64Basis, arg.name); CommandlineArg *arg = &tmp_args[tmp_args_count++];
u64 bin_idx = hash % countof(Base.cmdline.arg_bins); arg->name = name;
n->arg = arg; arg->value = s;
n->hash = hash; arg->exists = 1;
n->next = Base.cmdline.arg_bins[bin_idx]; name = Zstr;
Base.cmdline.arg_bins[bin_idx] = n; }
else
{
tmp_positionals[tmp_positionals_count++] = s;
}
} }
}
if (name.len > 0)
{
CommandlineArg *arg = &tmp_args[tmp_args_count++];
arg->name = name;
arg->exists = 1;
}
} }
EndScratch(scratch);
Arena *perm = PermArena();
Base.cmdline.positional_args_count = tmp_positionals_count;
Base.cmdline.positional_args = PushStructsNoZero(perm, String, tmp_positionals_count);
CopyStructs(Base.cmdline.positional_args, tmp_positionals, tmp_positionals_count);
for (u64 i = 0; i < tmp_args_count; ++i)
{
CommandlineArg arg = tmp_args[i];
CommandlineArgNode *n = PushStruct(perm, CommandlineArgNode);
u64 hash = HashFnv64(Fnv64Basis, arg.name);
u64 bin_idx = hash % countof(Base.cmdline.arg_bins);
n->arg = arg;
n->hash = hash;
n->next = Base.cmdline.arg_bins[bin_idx];
Base.cmdline.arg_bins[bin_idx] = n;
}
}
EndScratch(scratch);
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -74,25 +74,25 @@ void BootstrapCmdline(void)
String StringFromCommandlineIdx(i32 idx) String StringFromCommandlineIdx(i32 idx)
{ {
String result = Zi; String result = Zi;
if (idx < Base.cmdline.positional_args_count) if (idx < Base.cmdline.positional_args_count)
{ {
result = Base.cmdline.positional_args[idx]; result = Base.cmdline.positional_args[idx];
} }
return result; return result;
} }
CommandlineArg CommandlineArgFromName(String name) CommandlineArg CommandlineArgFromName(String name)
{ {
CommandlineArg result = Zi; CommandlineArg result = Zi;
u64 hash = HashFnv64(Fnv64Basis, name); u64 hash = HashFnv64(Fnv64Basis, name);
for (CommandlineArgNode *n = Base.cmdline.arg_bins[hash % countof(Base.cmdline.arg_bins)]; n; n = n->next) for (CommandlineArgNode *n = Base.cmdline.arg_bins[hash % countof(Base.cmdline.arg_bins)]; n; n = n->next)
{
if (n->hash == hash && MatchString(n->arg.name, name))
{ {
if (n->hash == hash && MatchString(n->arg.name, name)) result = n->arg;
{ break;
result = n->arg;
break;
}
} }
return result; }
return result;
} }

View File

@ -3,23 +3,23 @@
Struct(CommandlineArg) Struct(CommandlineArg)
{ {
b32 exists; b32 exists;
String name; String name;
String value; String value;
}; };
Struct(CommandlineArgNode) Struct(CommandlineArgNode)
{ {
CommandlineArgNode *next; CommandlineArgNode *next;
u64 hash; u64 hash;
CommandlineArg arg; CommandlineArg arg;
}; };
Struct(CmdLineCtx) Struct(CmdLineCtx)
{ {
String *positional_args; String *positional_args;
u64 positional_args_count; u64 positional_args_count;
CommandlineArgNode *arg_bins[1024]; CommandlineArgNode *arg_bins[1024];
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////

View File

@ -3,107 +3,107 @@
String StringFromButton(Button button) String StringFromButton(Button button)
{ {
PERSIST Readonly String names[Button_Count] = { PERSIST Readonly String names[Button_Count] = {
[Button_M1] = CompLit("Mouse 1"), [Button_M1] = CompLit("Mouse 1"),
[Button_M2] = CompLit("Mouse 2"), [Button_M2] = CompLit("Mouse 2"),
[Button_M3] = CompLit("Mouse 3"), [Button_M3] = CompLit("Mouse 3"),
[Button_M4] = CompLit("Mouse 4"), [Button_M4] = CompLit("Mouse 4"),
[Button_M5] = CompLit("Mouse 5"), [Button_M5] = CompLit("Mouse 5"),
[Button_MWheelUp] = CompLit("Wheel Up"), [Button_MWheelUp] = CompLit("Wheel Up"),
[Button_MWheelDown] = CompLit("Wheel Down"), [Button_MWheelDown] = CompLit("Wheel Down"),
[Button_Escape] = CompLit("Escape"), [Button_Escape] = CompLit("Escape"),
[Button_F1] = CompLit("F1"), [Button_F1] = CompLit("F1"),
[Button_F2] = CompLit("F2"), [Button_F2] = CompLit("F2"),
[Button_F3] = CompLit("F3"), [Button_F3] = CompLit("F3"),
[Button_F4] = CompLit("F4"), [Button_F4] = CompLit("F4"),
[Button_F5] = CompLit("F5"), [Button_F5] = CompLit("F5"),
[Button_F6] = CompLit("F6"), [Button_F6] = CompLit("F6"),
[Button_F7] = CompLit("F7"), [Button_F7] = CompLit("F7"),
[Button_F8] = CompLit("F8"), [Button_F8] = CompLit("F8"),
[Button_F9] = CompLit("F9"), [Button_F9] = CompLit("F9"),
[Button_F10] = CompLit("F10"), [Button_F10] = CompLit("F10"),
[Button_F11] = CompLit("F11"), [Button_F11] = CompLit("F11"),
[Button_F12] = CompLit("F12"), [Button_F12] = CompLit("F12"),
[Button_F13] = CompLit("F13"), [Button_F13] = CompLit("F13"),
[Button_F14] = CompLit("F14"), [Button_F14] = CompLit("F14"),
[Button_F15] = CompLit("F15"), [Button_F15] = CompLit("F15"),
[Button_F16] = CompLit("F16"), [Button_F16] = CompLit("F16"),
[Button_F17] = CompLit("F17"), [Button_F17] = CompLit("F17"),
[Button_F18] = CompLit("F18"), [Button_F18] = CompLit("F18"),
[Button_F19] = CompLit("F19"), [Button_F19] = CompLit("F19"),
[Button_F20] = CompLit("F20"), [Button_F20] = CompLit("F20"),
[Button_F21] = CompLit("F21"), [Button_F21] = CompLit("F21"),
[Button_F22] = CompLit("F22"), [Button_F22] = CompLit("F22"),
[Button_F23] = CompLit("F23"), [Button_F23] = CompLit("F23"),
[Button_F24] = CompLit("F24"), [Button_F24] = CompLit("F24"),
[Button_GraveAccent] = CompLit("~"), [Button_GraveAccent] = CompLit("~"),
[Button_0] = CompLit("0"), [Button_0] = CompLit("0"),
[Button_1] = CompLit("1"), [Button_1] = CompLit("1"),
[Button_2] = CompLit("2"), [Button_2] = CompLit("2"),
[Button_3] = CompLit("3"), [Button_3] = CompLit("3"),
[Button_4] = CompLit("4"), [Button_4] = CompLit("4"),
[Button_5] = CompLit("5"), [Button_5] = CompLit("5"),
[Button_6] = CompLit("6"), [Button_6] = CompLit("6"),
[Button_7] = CompLit("7"), [Button_7] = CompLit("7"),
[Button_8] = CompLit("8"), [Button_8] = CompLit("8"),
[Button_9] = CompLit("9"), [Button_9] = CompLit("9"),
[Button_Minus] = CompLit("Minus"), [Button_Minus] = CompLit("Minus"),
[Button_Equal] = CompLit("Equal"), [Button_Equal] = CompLit("Equal"),
[Button_Backspace] = CompLit("Backspace"), [Button_Backspace] = CompLit("Backspace"),
[Button_Delete] = CompLit("Delete"), [Button_Delete] = CompLit("Delete"),
[Button_Tab] = CompLit("Tab"), [Button_Tab] = CompLit("Tab"),
[Button_A] = CompLit("A"), [Button_A] = CompLit("A"),
[Button_B] = CompLit("B"), [Button_B] = CompLit("B"),
[Button_C] = CompLit("C"), [Button_C] = CompLit("C"),
[Button_D] = CompLit("D"), [Button_D] = CompLit("D"),
[Button_E] = CompLit("E"), [Button_E] = CompLit("E"),
[Button_F] = CompLit("F"), [Button_F] = CompLit("F"),
[Button_G] = CompLit("G"), [Button_G] = CompLit("G"),
[Button_H] = CompLit("H"), [Button_H] = CompLit("H"),
[Button_I] = CompLit("I"), [Button_I] = CompLit("I"),
[Button_J] = CompLit("J"), [Button_J] = CompLit("J"),
[Button_K] = CompLit("K"), [Button_K] = CompLit("K"),
[Button_L] = CompLit("L"), [Button_L] = CompLit("L"),
[Button_M] = CompLit("M"), [Button_M] = CompLit("M"),
[Button_N] = CompLit("N"), [Button_N] = CompLit("N"),
[Button_O] = CompLit("O"), [Button_O] = CompLit("O"),
[Button_P] = CompLit("P"), [Button_P] = CompLit("P"),
[Button_Q] = CompLit("Q"), [Button_Q] = CompLit("Q"),
[Button_R] = CompLit("R"), [Button_R] = CompLit("R"),
[Button_S] = CompLit("S"), [Button_S] = CompLit("S"),
[Button_T] = CompLit("T"), [Button_T] = CompLit("T"),
[Button_U] = CompLit("U"), [Button_U] = CompLit("U"),
[Button_V] = CompLit("V"), [Button_V] = CompLit("V"),
[Button_W] = CompLit("W"), [Button_W] = CompLit("W"),
[Button_X] = CompLit("X"), [Button_X] = CompLit("X"),
[Button_Y] = CompLit("Y"), [Button_Y] = CompLit("Y"),
[Button_Z] = CompLit("Z"), [Button_Z] = CompLit("Z"),
[Button_Space] = CompLit("Space"), [Button_Space] = CompLit("Space"),
[Button_Enter] = CompLit("Enter"), [Button_Enter] = CompLit("Enter"),
[Button_Ctrl] = CompLit("Ctrl"), [Button_Ctrl] = CompLit("Ctrl"),
[Button_Shift] = CompLit("Shift"), [Button_Shift] = CompLit("Shift"),
[Button_Alt] = CompLit("Alt"), [Button_Alt] = CompLit("Alt"),
[Button_Up] = CompLit("Up"), [Button_Up] = CompLit("Up"),
[Button_Left] = CompLit("Left"), [Button_Left] = CompLit("Left"),
[Button_Down] = CompLit("Down"), [Button_Down] = CompLit("Down"),
[Button_Right] = CompLit("Right"), [Button_Right] = CompLit("Right"),
[Button_PageUp] = CompLit("PageUp"), [Button_PageUp] = CompLit("PageUp"),
[Button_PageDown] = CompLit("PageDown"), [Button_PageDown] = CompLit("PageDown"),
[Button_Home] = CompLit("Home"), [Button_Home] = CompLit("Home"),
[Button_End] = CompLit("End"), [Button_End] = CompLit("End"),
[Button_ForwardSlash] = CompLit("Slash"), [Button_ForwardSlash] = CompLit("Slash"),
[Button_Period] = CompLit("Period"), [Button_Period] = CompLit("Period"),
[Button_Comma] = CompLit("Comma"), [Button_Comma] = CompLit("Comma"),
[Button_Quote] = CompLit("Quote"), [Button_Quote] = CompLit("Quote"),
[Button_LeftBracket] = CompLit("Left Bracket"), [Button_LeftBracket] = CompLit("Left Bracket"),
[Button_RightBracket] = CompLit("Right Bracket"), [Button_RightBracket] = CompLit("Right Bracket"),
[Button_Insert] = CompLit("Insert"), [Button_Insert] = CompLit("Insert"),
[Button_Semicolon] = CompLit("Semicolon"), [Button_Semicolon] = CompLit("Semicolon"),
}; };
String name = Lit("None"); String name = Lit("None");
if (button > 0 && button < countof(names)) if (button > 0 && button < countof(names))
{ {
name = names[button]; name = names[button];
} }
return name; return name;
} }

View File

@ -3,110 +3,110 @@
Enum(Button) Enum(Button)
{ {
Button_None, Button_None,
//- Mouse buttons //- Mouse buttons
Button_M1, Button_M1,
Button_M2, Button_M2,
Button_M3, Button_M3,
Button_M4, Button_M4,
Button_M5, Button_M5,
//- Mouse wheel //- Mouse wheel
Button_MWheelUp, Button_MWheelUp,
Button_MWheelDown, Button_MWheelDown,
//- Keyboard buttons //- Keyboard buttons
Button_Escape, Button_Escape,
Button_F1, Button_F1,
Button_F2, Button_F2,
Button_F3, Button_F3,
Button_F4, Button_F4,
Button_F5, Button_F5,
Button_F6, Button_F6,
Button_F7, Button_F7,
Button_F8, Button_F8,
Button_F9, Button_F9,
Button_F10, Button_F10,
Button_F11, Button_F11,
Button_F12, Button_F12,
Button_F13, Button_F13,
Button_F14, Button_F14,
Button_F15, Button_F15,
Button_F16, Button_F16,
Button_F17, Button_F17,
Button_F18, Button_F18,
Button_F19, Button_F19,
Button_F20, Button_F20,
Button_F21, Button_F21,
Button_F22, Button_F22,
Button_F23, Button_F23,
Button_F24, Button_F24,
Button_GraveAccent, Button_GraveAccent,
Button_0, Button_0,
Button_1, Button_1,
Button_2, Button_2,
Button_3, Button_3,
Button_4, Button_4,
Button_5, Button_5,
Button_6, Button_6,
Button_7, Button_7,
Button_8, Button_8,
Button_9, Button_9,
Button_Minus, Button_Minus,
Button_Equal, Button_Equal,
Button_Backspace, Button_Backspace,
Button_Delete, Button_Delete,
Button_Tab, Button_Tab,
Button_A, Button_A,
Button_B, Button_B,
Button_C, Button_C,
Button_D, Button_D,
Button_E, Button_E,
Button_F, Button_F,
Button_G, Button_G,
Button_H, Button_H,
Button_I, Button_I,
Button_J, Button_J,
Button_K, Button_K,
Button_L, Button_L,
Button_M, Button_M,
Button_N, Button_N,
Button_O, Button_O,
Button_P, Button_P,
Button_Q, Button_Q,
Button_R, Button_R,
Button_S, Button_S,
Button_T, Button_T,
Button_U, Button_U,
Button_V, Button_V,
Button_W, Button_W,
Button_X, Button_X,
Button_Y, Button_Y,
Button_Z, Button_Z,
Button_Space, Button_Space,
Button_Enter, Button_Enter,
Button_Ctrl, Button_Ctrl,
Button_Shift, Button_Shift,
Button_Alt, Button_Alt,
Button_Up, Button_Up,
Button_Left, Button_Left,
Button_Down, Button_Down,
Button_Right, Button_Right,
Button_PageUp, Button_PageUp,
Button_PageDown, Button_PageDown,
Button_Home, Button_Home,
Button_End, Button_End,
Button_ForwardSlash, Button_ForwardSlash,
Button_Period, Button_Period,
Button_Comma, Button_Comma,
Button_Quote, Button_Quote,
Button_LeftBracket, Button_LeftBracket,
Button_RightBracket, Button_RightBracket,
Button_Insert, Button_Insert,
Button_Semicolon, Button_Semicolon,
Button_Count Button_Count
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -114,44 +114,44 @@ Enum(Button)
Enum(ControllerEventKind) Enum(ControllerEventKind)
{ {
ControllerEventKind_None, ControllerEventKind_None,
ControllerEventKind_ButtonDown, ControllerEventKind_ButtonDown,
ControllerEventKind_ButtonUp, ControllerEventKind_ButtonUp,
ControllerEventKind_CursorMove, ControllerEventKind_CursorMove,
ControllerEventKind_MouseMove, ControllerEventKind_MouseMove,
ControllerEventKind_Text, ControllerEventKind_Text,
ControllerEventKind_Quit, ControllerEventKind_Quit,
ControllerEventKind_Count ControllerEventKind_Count
}; };
Struct(ControllerEvent) Struct(ControllerEvent)
{ {
ControllerEventKind kind; ControllerEventKind kind;
/* ControllerEventKind_ButtonDown */ /* ControllerEventKind_ButtonDown */
/* ControllerEventKind_ButtonUp */ /* ControllerEventKind_ButtonUp */
Button button; Button button;
b32 is_repeat; b32 is_repeat;
/* ControllerEventKind_Text */ /* ControllerEventKind_Text */
u32 text_codepoint; u32 text_codepoint;
/* ControllerEventKind_CursorMove */ /* ControllerEventKind_CursorMove */
Vec2I32 cursor_pos; Vec2I32 cursor_pos;
/* ControllerEventKind_MouseMove */ /* ControllerEventKind_MouseMove */
Vec2I32 mouse_delta; Vec2I32 mouse_delta;
}; };
Struct(ControllerEventsArray) Struct(ControllerEventsArray)
{ {
u64 count; u64 count;
ControllerEvent *events; ControllerEvent *events;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////

View File

@ -3,15 +3,15 @@
Enum(OS_FileFlag) Enum(OS_FileFlag)
{ {
OS_FileFlag_None = 0, OS_FileFlag_None = 0,
OS_FileFlag_Read = (1 << 0), OS_FileFlag_Read = (1 << 0),
OS_FileFlag_Write = (1 << 1), OS_FileFlag_Write = (1 << 1),
OS_FileFlag_Create = (1 << 2), OS_FileFlag_Create = (1 << 2),
}; };
Struct(OS_File) Struct(OS_File)
{ {
u64 handle; u64 handle;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////

View File

@ -5,17 +5,17 @@
Struct(GstatCtx) Struct(GstatCtx)
{ {
Atomic64Padded SockBytesSent; Atomic64Padded SockBytesSent;
Atomic64Padded SockBytesReceived; Atomic64Padded SockBytesReceived;
Atomic64Padded DebugSteps; Atomic64Padded DebugSteps;
Atomic64Padded NumArenas; Atomic64Padded NumArenas;
Atomic64Padded ArenaMemoryCommitted; Atomic64Padded ArenaMemoryCommitted;
Atomic64Padded ArenaMemoryReserved; Atomic64Padded ArenaMemoryReserved;
Atomic64Padded NumGpuArenas; Atomic64Padded NumGpuArenas;
Atomic64Padded DedicatedGpuArenaMemoryCommitted; Atomic64Padded DedicatedGpuArenaMemoryCommitted;
Atomic64Padded SharedGpuArenaMemoryCommitted; Atomic64Padded SharedGpuArenaMemoryCommitted;
}; };

View File

@ -5,53 +5,53 @@
//- Api //- Api
#include "base.cgh" #include "base.cgh"
#if IsLanguageC #if IsLanguageC
# include "base_intrinsics.h" #include "base_intrinsics.h"
# include "base_memory.h" #include "base_memory.h"
# include "base_arena.h" #include "base_arena.h"
# include "base_futex.h" #include "base_futex.h"
# include "base_sync.h" #include "base_sync.h"
# include "base_time.h" #include "base_time.h"
# include "base_uid.h" #include "base_uid.h"
# include "base_math.h" #include "base_math.h"
# include "base_wave.h" #include "base_wave.h"
# include "base_string.h" #include "base_string.h"
# include "base_cmdline.h" #include "base_cmdline.h"
# include "base_log.h" #include "base_log.h"
# include "base_uni.h" #include "base_uni.h"
# include "base_gstat.h" #include "base_gstat.h"
# include "base_buddy.h" #include "base_buddy.h"
# include "base_rand.h" #include "base_rand.h"
# include "base_util.h" #include "base_util.h"
# include "base_bitbuff.h" #include "base_bitbuff.h"
# include "base_resource.h" #include "base_resource.h"
# include "base_controller.h" #include "base_controller.h"
# include "base_async.h" #include "base_async.h"
# include "base_state.h" #include "base_state.h"
#elif IsLanguageG #elif IsLanguageG
# include "base_shader.gh" #include "base_shader.gh"
#endif #endif
//- Impl //- Impl
#if IsLanguageC #if IsLanguageC
# include "base_memory.c" #include "base_memory.c"
# include "base_arena.c" #include "base_arena.c"
# include "base_sync.c" #include "base_sync.c"
# include "base_uid.c" #include "base_uid.c"
# include "base_string.c" #include "base_string.c"
# include "base_cmdline.c" #include "base_cmdline.c"
# include "base_uni.c" #include "base_uni.c"
# include "base_buddy.c" #include "base_buddy.c"
# include "base_math.c" #include "base_math.c"
# include "base_wave.c" #include "base_wave.c"
# include "base_rand.c" #include "base_rand.c"
# include "base_bitbuff.c" #include "base_bitbuff.c"
# include "base_resource.c" #include "base_resource.c"
# include "base_controller.c" #include "base_controller.c"
# include "base_async.c" #include "base_async.c"
# include "base_state.c" #include "base_state.c"
#endif #endif
//- Include base_win32 //- Include base_win32
#if IsLanguageC && IsPlatformWindows #if IsLanguageC && IsPlatformWindows
# include "base_win32/base_win32_inc.h" #include "base_win32/base_win32_inc.h"
#endif #endif

View File

@ -3,23 +3,23 @@
Inline f32 IxSqrtF32(f32 f) Inline f32 IxSqrtF32(f32 f)
{ {
__m128 n = _mm_set_ss(f); __m128 n = _mm_set_ss(f);
n = _mm_sqrt_ss(n); n = _mm_sqrt_ss(n);
return _mm_cvtss_f32(n); return _mm_cvtss_f32(n);
} }
Inline f64 IxSqrtF64(f64 f) Inline f64 IxSqrtF64(f64 f)
{ {
__m128d n = _mm_set_sd(f); __m128d n = _mm_set_sd(f);
n = _mm_sqrt_sd(_mm_setzero_pd(), n); n = _mm_sqrt_sd(_mm_setzero_pd(), n);
return _mm_cvtsd_f64(n); return _mm_cvtsd_f64(n);
} }
Inline f32 IxRsqrtF32(f32 f) Inline f32 IxRsqrtF32(f32 f)
{ {
__m128 n = _mm_set_ss(f); __m128 n = _mm_set_ss(f);
n = _mm_rsqrt_ss(n); n = _mm_rsqrt_ss(n);
return _mm_cvtss_f32(n); return _mm_cvtss_f32(n);
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -27,22 +27,22 @@ Inline f32 IxRsqrtF32(f32 f)
Inline i32 IxRoundF32ToI32(f32 f) Inline i32 IxRoundF32ToI32(f32 f)
{ {
return _mm_cvtss_si32(_mm_round_ss(_mm_setzero_ps(), _mm_set_ss(f), _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC)); return _mm_cvtss_si32(_mm_round_ss(_mm_setzero_ps(), _mm_set_ss(f), _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC));
} }
Inline f32 IxRoundF32ToF32(f32 f) Inline f32 IxRoundF32ToF32(f32 f)
{ {
return _mm_cvtss_f32(_mm_round_ss(_mm_setzero_ps(), _mm_set_ss(f), _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC)); return _mm_cvtss_f32(_mm_round_ss(_mm_setzero_ps(), _mm_set_ss(f), _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC));
} }
Inline i64 IxRoundF64ToI64(f64 f) Inline i64 IxRoundF64ToI64(f64 f)
{ {
return _mm_cvtsd_si64(_mm_round_sd(_mm_setzero_pd(), _mm_set_sd(f), _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC)); return _mm_cvtsd_si64(_mm_round_sd(_mm_setzero_pd(), _mm_set_sd(f), _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC));
} }
Inline f64 IxRoundF64ToF64(f64 f) Inline f64 IxRoundF64ToF64(f64 f)
{ {
return _mm_cvtsd_f64(_mm_round_sd(_mm_setzero_pd(), _mm_set_sd(f), _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC)); return _mm_cvtsd_f64(_mm_round_sd(_mm_setzero_pd(), _mm_set_sd(f), _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC));
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -50,22 +50,22 @@ Inline f64 IxRoundF64ToF64(f64 f)
Inline i32 IxFloorF32ToI32(f32 f) Inline i32 IxFloorF32ToI32(f32 f)
{ {
return _mm_cvtss_si32(_mm_floor_ss(_mm_setzero_ps(), _mm_set_ss(f))); return _mm_cvtss_si32(_mm_floor_ss(_mm_setzero_ps(), _mm_set_ss(f)));
} }
Inline f32 IxFloorF32ToF32(f32 f) Inline f32 IxFloorF32ToF32(f32 f)
{ {
return _mm_cvtss_f32(_mm_floor_ss(_mm_setzero_ps(), _mm_set_ss(f))); return _mm_cvtss_f32(_mm_floor_ss(_mm_setzero_ps(), _mm_set_ss(f)));
} }
Inline i64 IxFloorF64ToI64(f64 f) Inline i64 IxFloorF64ToI64(f64 f)
{ {
return _mm_cvtsd_si64(_mm_floor_sd(_mm_setzero_pd(), _mm_set_sd(f))); return _mm_cvtsd_si64(_mm_floor_sd(_mm_setzero_pd(), _mm_set_sd(f)));
} }
Inline f64 IxFloorF64ToF64(f64 f) Inline f64 IxFloorF64ToF64(f64 f)
{ {
return _mm_cvtsd_f64(_mm_floor_sd(_mm_setzero_pd(), _mm_set_sd(f))); return _mm_cvtsd_f64(_mm_floor_sd(_mm_setzero_pd(), _mm_set_sd(f)));
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -73,22 +73,22 @@ Inline f64 IxFloorF64ToF64(f64 f)
Inline i32 IxCeilF32ToI32(f32 f) Inline i32 IxCeilF32ToI32(f32 f)
{ {
return _mm_cvtss_si32(_mm_ceil_ss(_mm_setzero_ps(), _mm_set_ss(f))); return _mm_cvtss_si32(_mm_ceil_ss(_mm_setzero_ps(), _mm_set_ss(f)));
} }
Inline f32 IxCeilF32ToF32(f32 f) Inline f32 IxCeilF32ToF32(f32 f)
{ {
return _mm_cvtss_f32(_mm_ceil_ss(_mm_setzero_ps(), _mm_set_ss(f))); return _mm_cvtss_f32(_mm_ceil_ss(_mm_setzero_ps(), _mm_set_ss(f)));
} }
Inline i64 IxCeilF64ToI64(f64 f) Inline i64 IxCeilF64ToI64(f64 f)
{ {
return _mm_cvtsd_si64(_mm_ceil_sd(_mm_setzero_pd(), _mm_set_sd(f))); return _mm_cvtsd_si64(_mm_ceil_sd(_mm_setzero_pd(), _mm_set_sd(f)));
} }
Inline f64 IxCeilF64ToF64(f64 f) Inline f64 IxCeilF64ToF64(f64 f)
{ {
return _mm_cvtsd_f64(_mm_ceil_sd(_mm_setzero_pd(), _mm_set_sd(f))); return _mm_cvtsd_f64(_mm_ceil_sd(_mm_setzero_pd(), _mm_set_sd(f)));
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -96,10 +96,10 @@ Inline f64 IxCeilF64ToF64(f64 f)
Inline f32 IxTruncF32ToF32(f32 f) Inline f32 IxTruncF32ToF32(f32 f)
{ {
return _mm_cvtss_f32(_mm_round_ss(_mm_setzero_ps(), _mm_set_ss(f), _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC)); return _mm_cvtss_f32(_mm_round_ss(_mm_setzero_ps(), _mm_set_ss(f), _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC));
} }
Inline f64 IxTruncF64ToF64(f64 f) Inline f64 IxTruncF64ToF64(f64 f)
{ {
return _mm_cvtsd_f64(_mm_round_sd(_mm_setzero_pd(), _mm_set_sd(f), _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC)); return _mm_cvtsd_f64(_mm_round_sd(_mm_setzero_pd(), _mm_set_sd(f), _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC));
} }

View File

@ -3,22 +3,22 @@
Struct(LogEvent) Struct(LogEvent)
{ {
u64 id; u64 id;
u64 level_id; u64 level_id;
DateTime datetime; DateTime datetime;
i64 time_ns; i64 time_ns;
String msg; String msg;
i32 level; i32 level;
i32 thread_id; i32 thread_id;
}; };
Struct(LogEventsArray) Struct(LogEventsArray)
{ {
u64 count; u64 count;
LogEvent *logs; LogEvent *logs;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -28,11 +28,11 @@ Struct(LogEventsArray)
/* Log level configuration */ /* Log level configuration */
#ifndef LogLevel_CompTime #ifndef LogLevel_CompTime
# if IsRtcEnabled #if IsRtcEnabled
# define LogLevel_CompTime LogLevel_Debug #define LogLevel_CompTime LogLevel_Debug
# else #else
# define LogLevel_CompTime LogLevel_Info #define LogLevel_CompTime LogLevel_Info
# endif #endif
#endif #endif
#define LogLevel_None -1 #define LogLevel_None -1
@ -49,84 +49,84 @@ Struct(LogEventsArray)
Struct(LogLevelSettings) Struct(LogLevelSettings)
{ {
String shorthand; String shorthand;
}; };
Global Readonly LogLevelSettings log_settings[LogLevel_Count] = { Global Readonly LogLevelSettings log_settings[LogLevel_Count] = {
[LogLevel_Critical] = { [LogLevel_Critical] = {
CompLit("CRITICAL"), CompLit("CRITICAL"),
}, },
[LogLevel_Error] = { [LogLevel_Error] = {
CompLit("ERROR"), CompLit("ERROR"),
}, },
[LogLevel_Warning] = { [LogLevel_Warning] = {
CompLit("WARNING"), CompLit("WARNING"),
}, },
[LogLevel_Success] = { [LogLevel_Success] = {
CompLit("SUCCESS"), CompLit("SUCCESS"),
}, },
[LogLevel_Info] = { [LogLevel_Info] = {
CompLit("INFO"), CompLit("INFO"),
}, },
[LogLevel_Debug] = { [LogLevel_Debug] = {
CompLit("DEBUG"), CompLit("DEBUG"),
} }
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Compile-time logging macros //~ Compile-time logging macros
#if LogLevel(LogLevel_Critical) #if LogLevel(LogLevel_Critical)
# define LogCritical(msg) Log_(LogLevel_Critical, msg) #define LogCritical(msg) Log_(LogLevel_Critical, msg)
# define LogCriticalF(fmt_lit, ...) LogF_(LogLevel_Critical, Lit(fmt_lit) , ## __VA_ARGS__, FmtEnd) #define LogCriticalF(fmt_lit, ...) LogF_(LogLevel_Critical, Lit(fmt_lit) , ## __VA_ARGS__, FmtEnd)
#else #else
# define LogCritical(msg) #define LogCritical(msg)
# define LogCriticalF(...) #define LogCriticalF(...)
#endif #endif
#if LogLevel(LogLevel_Error) #if LogLevel(LogLevel_Error)
# define LogError(msg) Log_(LogLevel_Error, msg) #define LogError(msg) Log_(LogLevel_Error, msg)
# define LogErrorF(fmt_lit, ...) LogF_(LogLevel_Error, Lit(fmt_lit) , ## __VA_ARGS__, FmtEnd) #define LogErrorF(fmt_lit, ...) LogF_(LogLevel_Error, Lit(fmt_lit) , ## __VA_ARGS__, FmtEnd)
#else #else
# define LogError(msg) #define LogError(msg)
# define LogErrorF(...) #define LogErrorF(...)
#endif #endif
#if LogLevel(LogLevel_Warning) #if LogLevel(LogLevel_Warning)
# define LogWarning(msg) Log_(LogLevel_Warning, msg) #define LogWarning(msg) Log_(LogLevel_Warning, msg)
# define LogWarningF(fmt_lit, ...) LogF_(LogLevel_Warning, Lit(fmt_lit) , ## __VA_ARGS__, FmtEnd) #define LogWarningF(fmt_lit, ...) LogF_(LogLevel_Warning, Lit(fmt_lit) , ## __VA_ARGS__, FmtEnd)
#else #else
# define LogWarning(msg) #define LogWarning(msg)
# define LogWarningF(...) #define LogWarningF(...)
#endif #endif
#if LogLevel(LogLevel_Success) #if LogLevel(LogLevel_Success)
# define LogSuccess(msg) Log_(LogLevel_Success, msg) #define LogSuccess(msg) Log_(LogLevel_Success, msg)
# define LogSuccessF(fmt_lit, ...) LogF_(LogLevel_Success, Lit(fmt_lit) , ## __VA_ARGS__, FmtEnd) #define LogSuccessF(fmt_lit, ...) LogF_(LogLevel_Success, Lit(fmt_lit) , ## __VA_ARGS__, FmtEnd)
#else #else
# define LogSuccess(msg) #define LogSuccess(msg)
# define LogSuccessF(...) #define LogSuccessF(...)
#endif #endif
#if LogLevel(LogLevel_Info) #if LogLevel(LogLevel_Info)
# define LogInfo(msg) Log_(LogLevel_Info, msg) #define LogInfo(msg) Log_(LogLevel_Info, msg)
# define LogInfoF(fmt_lit, ...) LogF_(LogLevel_Info, Lit(fmt_lit) , ## __VA_ARGS__, FmtEnd) #define LogInfoF(fmt_lit, ...) LogF_(LogLevel_Info, Lit(fmt_lit) , ## __VA_ARGS__, FmtEnd)
#else #else
# define LogInfo(msg) #define LogInfo(msg)
# define LogInfoF(...) #define LogInfoF(...)
#endif #endif
#if LogLevel(LogLevel_Debug) #if LogLevel(LogLevel_Debug)
# define LogDebug(msg) Log_(LogLevel_Debug, msg) #define LogDebug(msg) Log_(LogLevel_Debug, msg)
# define LogDebugF(fmt_lit, ...) LogF_(LogLevel_Debug, Lit(fmt_lit) , ## __VA_ARGS__, FmtEnd) #define LogDebugF(fmt_lit, ...) LogF_(LogLevel_Debug, Lit(fmt_lit) , ## __VA_ARGS__, FmtEnd)
#else #else
# define LogDebug(msg) #define LogDebug(msg)
# define LogDebugF(...) #define LogDebugF(...)
#endif #endif
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////

File diff suppressed because it is too large Load Diff

View File

@ -9,12 +9,12 @@
Enum(Axis) Enum(Axis)
{ {
Axis_X = 0, Axis_X = 0,
Axis_Y = 1, Axis_Y = 1,
Axis_Z = 2, Axis_Z = 2,
Axis_CountXY = 2, Axis_CountXY = 2,
Axis_CountXYZ = 3 Axis_CountXYZ = 3
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -145,17 +145,17 @@ Struct(Rng3U64) { Vec3U64 p0; Vec3U64 p1; };
Struct(Xform) Struct(Xform)
{ {
Vec2 bx; /* X basis vector (x axis) */ Vec2 bx; /* X basis vector (x axis) */
Vec2 by; /* Y basis vector (y axis)*/ Vec2 by; /* Y basis vector (y axis)*/
Vec2 og; /* Translation vector (origin) */ Vec2 og; /* Translation vector (origin) */
}; };
/* (T)ranslation, (R)otation, (S)cale */ /* (T)ranslation, (R)otation, (S)cale */
Struct(Trs) Struct(Trs)
{ {
Vec2 t; Vec2 t;
Vec2 s; Vec2 s;
f32 r; f32 r;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -163,9 +163,9 @@ Struct(Trs)
Struct(SoftSpring) Struct(SoftSpring)
{ {
f32 bias_rate; f32 bias_rate;
f32 mass_scale; f32 mass_scale;
f32 impulse_scale; f32 impulse_scale;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -173,11 +173,11 @@ Struct(SoftSpring)
Struct(Mat4x4) Struct(Mat4x4)
{ {
union union
{ {
struct { Vec4 bx, by, bz, bw; }; struct { Vec4 bx, by, bz, bw; };
f32 e[4][4]; f32 e[4][4];
}; };
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////

View File

@ -7,43 +7,43 @@
__attribute((section(".text.memcpy"))) __attribute((section(".text.memcpy")))
void *memcpy(void *__restrict dst, const void *__restrict src, u64 count) void *memcpy(void *__restrict dst, const void *__restrict src, u64 count)
{ {
char *dst_pchar = dst; char *dst_pchar = dst;
char *src_pchar = src; char *src_pchar = src;
for (u64 i = 0; i < count; ++i) for (u64 i = 0; i < count; ++i)
{ {
dst_pchar[i] = src_pchar[i]; dst_pchar[i] = src_pchar[i];
} }
return dst; return dst;
} }
//- memset //- memset
__attribute((section(".text.memset"))) __attribute((section(".text.memset")))
void *memset(void *dst, i32 c, u64 count) void *memset(void *dst, i32 c, u64 count)
{ {
char *dst_pchar = dst; char *dst_pchar = dst;
for (u64 i = 0; i < count; ++i) for (u64 i = 0; i < count; ++i)
{ {
dst_pchar[i] = (char)c; dst_pchar[i] = (char)c;
} }
return dst; return dst;
} }
//- memcmp //- memcmp
__attribute((section(".text.memcmp"))) __attribute((section(".text.memcmp")))
i32 memcmp(const void *p1, const void *p2, u64 count) i32 memcmp(const void *p1, const void *p2, u64 count)
{ {
i32 result = 0; i32 result = 0;
char *p1_pchar = p1; char *p1_pchar = p1;
char *p2_pchar = p2; char *p2_pchar = p2;
for (u64 i = 0; i < count; ++i) for (u64 i = 0; i < count; ++i)
{
result = p1_pchar[i] - p2_pchar[i];
if (result != 0)
{ {
result = p1_pchar[i] - p2_pchar[i]; break;
if (result != 0)
{
break;
}
} }
return result; }
return result;
} }
#endif /* !IsCrtlibEnabled */ #endif /* !IsCrtlibEnabled */

View File

@ -34,9 +34,9 @@ void SetMemoryReadWrite(void *address, u64 size);
//~ Crtlib stubs //~ Crtlib stubs
#if IsCrtlibEnabled #if IsCrtlibEnabled
# include <memory.h> #include <memory.h>
#else #else
void *memcpy(void *__restrict dst, const void *__restrict src, u64 n); void *memcpy(void *__restrict dst, const void *__restrict src, u64 n);
void *memset(void *dst, i32 c, u64 n); void *memset(void *dst, i32 c, u64 n);
i32 memcmp(const void *p1, const void *p2, u64 n); i32 memcmp(const void *p1, const void *p2, u64 n);
#endif #endif

View File

@ -1,17 +1,17 @@
u64 RandU64FromState(RandState *state) u64 RandU64FromState(RandState *state)
{ {
u64 seed = state->seed; u64 seed = state->seed;
if (seed == 0) if (seed == 0)
{ {
TrueRand(StringFromStruct(&seed)); TrueRand(StringFromStruct(&seed));
state->seed = seed; state->seed = seed;
} }
return seed ^ RandU64FromSeed(++state->counter); return seed ^ RandU64FromSeed(++state->counter);
} }
f64 RandF64FromState(RandState *state, f64 range_start, f64 range_end) f64 RandF64FromState(RandState *state, f64 range_start, f64 range_end)
{ {
return range_start + (range_end - range_start) * ((f64)(RandU64FromState(state) % RandMaxF64) / (f64)RandMaxF64); return range_start + (range_end - range_start) * ((f64)(RandU64FromState(state) % RandMaxF64) / (f64)RandMaxF64);
} }
/* Based on Jon Maiga's "mx3" /* Based on Jon Maiga's "mx3"
@ -19,19 +19,19 @@ f64 RandF64FromState(RandState *state, f64 range_start, f64 range_end)
*/ */
u64 RandU64FromSeed(u64 seed) u64 RandU64FromSeed(u64 seed)
{ {
seed = (seed ^ (seed >> 32)) * 0xbea225f9eb34556d; seed = (seed ^ (seed >> 32)) * 0xbea225f9eb34556d;
seed = (seed ^ (seed >> 29)) * 0xbea225f9eb34556d; seed = (seed ^ (seed >> 29)) * 0xbea225f9eb34556d;
seed = (seed ^ (seed >> 32)) * 0xbea225f9eb34556d; seed = (seed ^ (seed >> 32)) * 0xbea225f9eb34556d;
seed = (seed ^ (seed >> 29)); seed = (seed ^ (seed >> 29));
return seed; return seed;
} }
u64 RandU64FromSeeds(u64 seed_a, u64 seed_b) u64 RandU64FromSeeds(u64 seed_a, u64 seed_b)
{ {
return RandU64FromSeed((seed_a * 3) + seed_b); return RandU64FromSeed((seed_a * 3) + seed_b);
} }
f64 RandF64FromSeed(u64 seed, f64 range_start, f64 range_end) f64 RandF64FromSeed(u64 seed, f64 range_start, f64 range_end)
{ {
return range_start + (range_end - range_start) * ((f64)(RandU64FromSeed(seed) % RandMaxF64) / (f64)RandMaxF64); return range_start + (range_end - range_start) * ((f64)(RandU64FromSeed(seed) % RandMaxF64) / (f64)RandMaxF64);
} }

View File

@ -3,8 +3,8 @@
Struct(RandState) Struct(RandState)
{ {
u64 seed; /* If a state's seed == 0 upon a call to a related function, it will be initialized using platform's true rng source */ u64 seed; /* If a state's seed == 0 upon a call to a related function, it will be initialized using platform's true rng source */
u64 counter; u64 counter;
}; };
/* TODO: Use a value that gives good precision when dividing into range 0 -> 1 */ /* TODO: Use a value that gives good precision when dividing into range 0 -> 1 */

View File

@ -3,39 +3,39 @@
void BootstrapResources(u64 archive_strings_count, String *archive_strings) void BootstrapResources(u64 archive_strings_count, String *archive_strings)
{ {
Arena *perm = PermArena(); Arena *perm = PermArena();
for (u64 archive_string_index = 0; archive_string_index < archive_strings_count; ++archive_string_index) for (u64 archive_string_index = 0; archive_string_index < archive_strings_count; ++archive_string_index)
{
String archive = archive_strings[archive_string_index];
if (archive.len > 0)
{ {
String archive = archive_strings[archive_string_index]; BB_Buff bb = BB_BuffFromString(archive);
if (archive.len > 0) BB_Reader br = BB_ReaderFromBuff(&bb);
{
BB_Buff bb = BB_BuffFromString(archive);
BB_Reader br = BB_ReaderFromBuff(&bb);
u64 magic = BB_ReadUBits(&br, 64); u64 magic = BB_ReadUBits(&br, 64);
Assert(magic == ResourceEmbeddedMagic); Assert(magic == ResourceEmbeddedMagic);
/* Create & insert entries */ /* Create & insert entries */
u64 num_entries = BB_ReadUBits(&br, 64); u64 num_entries = BB_ReadUBits(&br, 64);
for (u64 i = 0; i < num_entries; ++i) for (u64 i = 0; i < num_entries; ++i)
{ {
u64 name_start = BB_ReadUBits(&br, 64); u64 name_start = BB_ReadUBits(&br, 64);
u64 name_len = BB_ReadUBits(&br, 64); u64 name_len = BB_ReadUBits(&br, 64);
u64 data_start = BB_ReadUBits(&br, 64); u64 data_start = BB_ReadUBits(&br, 64);
u64 data_len = BB_ReadUBits(&br, 64); u64 data_len = BB_ReadUBits(&br, 64);
ResourceEntry *entry = PushStruct(perm, ResourceEntry); ResourceEntry *entry = PushStruct(perm, ResourceEntry);
entry->name = STRING(name_len, archive.text + name_start); entry->name = STRING(name_len, archive.text + name_start);
entry->data = STRING(data_len, archive.text + data_start); entry->data = STRING(data_len, archive.text + data_start);
entry->hash = HashFnv64(Fnv64Basis, entry->name); entry->hash = HashFnv64(Fnv64Basis, entry->name);
ResourceEntryBin *bin = &Base.resource.bins[entry->hash % countof(Base.resource.bins)]; ResourceEntryBin *bin = &Base.resource.bins[entry->hash % countof(Base.resource.bins)];
SllQueuePushN(bin->first, bin->last, entry, next_in_bin); SllQueuePushN(bin->first, bin->last, entry, next_in_bin);
SllQueuePushN(Base.resource.first_entry, Base.resource.last_entry, entry, next); SllQueuePushN(Base.resource.first_entry, Base.resource.last_entry, entry, next);
} }
Base.resource.entries_count += num_entries; Base.resource.entries_count += num_entries;
}
} }
}
} }
@ -44,49 +44,49 @@ void BootstrapResources(u64 archive_strings_count, String *archive_strings)
b32 IsResourceNil(ResourceKey resource) b32 IsResourceNil(ResourceKey resource)
{ {
return resource.v == 0; return resource.v == 0;
} }
ResourceKey ResourceKeyFromStore(ResourceStore *store, String name) ResourceKey ResourceKeyFromStore(ResourceStore *store, String name)
{ {
ResourceKey result = Zi; ResourceKey result = Zi;
result.v = HashFnv64(store->v, name); result.v = HashFnv64(store->v, name);
return result; return result;
} }
ResourceEntry *ResourceEntryFromHash(u64 hash) ResourceEntry *ResourceEntryFromHash(u64 hash)
{ {
ResourceEntry *result = 0; ResourceEntry *result = 0;
ResourceEntryBin *bin = &Base.resource.bins[hash % countof(Base.resource.bins)]; ResourceEntryBin *bin = &Base.resource.bins[hash % countof(Base.resource.bins)];
for (ResourceEntry *e = bin->first; e; e = e->next_in_bin) for (ResourceEntry *e = bin->first; e; e = e->next_in_bin)
{
if (e->hash == hash)
{ {
if (e->hash == hash) result = e;
{ break;
result = e;
break;
}
} }
return result; }
return result;
} }
String DataFromResource(ResourceKey resource) String DataFromResource(ResourceKey resource)
{ {
String result = Zi; String result = Zi;
ResourceEntry *entry = ResourceEntryFromHash(resource.v); ResourceEntry *entry = ResourceEntryFromHash(resource.v);
if (entry) if (entry)
{ {
result = entry->data; result = entry->data;
} }
return result; return result;
} }
String NameFromResource(ResourceKey resource) String NameFromResource(ResourceKey resource)
{ {
String result = Zi; String result = Zi;
ResourceEntry *entry = ResourceEntryFromHash(resource.v); ResourceEntry *entry = ResourceEntryFromHash(resource.v);
if (entry) if (entry)
{ {
result = entry->name; result = entry->name;
} }
return result; return result;
} }

View File

@ -3,26 +3,26 @@
Struct(ResourceEntry) Struct(ResourceEntry)
{ {
ResourceEntry *next; ResourceEntry *next;
ResourceEntry *next_in_bin; ResourceEntry *next_in_bin;
u64 hash; u64 hash;
String name; String name;
String data; String data;
}; };
Struct(ResourceEntryBin) Struct(ResourceEntryBin)
{ {
ResourceEntry *first; ResourceEntry *first;
ResourceEntry *last; ResourceEntry *last;
}; };
Struct(ResourceCtx) Struct(ResourceCtx)
{ {
u64 entries_count; u64 entries_count;
ResourceEntry *first_entry; ResourceEntry *first_entry;
ResourceEntry *last_entry; ResourceEntry *last_entry;
ResourceEntryBin bins[4096]; ResourceEntryBin bins[4096];
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////

View File

@ -42,7 +42,7 @@ Struct(Rng3U32) { Vec3U32 p0; Vec3U32 p1; };
template<typename T, u32 N> template<typename T, u32 N>
u32 countof(T arr[N]) u32 countof(T arr[N])
{ {
return N; return N;
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -81,46 +81,46 @@ u32 countof(T arr[N])
Vec4 Vec4FromU32(u32 v) Vec4 Vec4FromU32(u32 v)
{ {
Vec4 result; Vec4 result;
result.x = ((v >> 0) & 0xFF) / 255.0; result.x = ((v >> 0) & 0xFF) / 255.0;
result.y = ((v >> 8) & 0xFF) / 255.0; result.y = ((v >> 8) & 0xFF) / 255.0;
result.z = ((v >> 16) & 0xFF) / 255.0; result.z = ((v >> 16) & 0xFF) / 255.0;
result.w = ((v >> 24) & 0xFF) / 255.0; result.w = ((v >> 24) & 0xFF) / 255.0;
return result; return result;
} }
u32 U32FromVec4(Vec4 v) u32 U32FromVec4(Vec4 v)
{ {
u32 result; u32 result;
result |= (((u32)(v.x * 255.0)) & 0xFF) << 0; result |= (((u32)(v.x * 255.0)) & 0xFF) << 0;
result |= (((u32)(v.y * 255.0)) & 0xFF) << 8; result |= (((u32)(v.y * 255.0)) & 0xFF) << 8;
result |= (((u32)(v.z * 255.0)) & 0xFF) << 16; result |= (((u32)(v.z * 255.0)) & 0xFF) << 16;
result |= (((u32)(v.w * 255.0)) & 0xFF) << 24; result |= (((u32)(v.w * 255.0)) & 0xFF) << 24;
return result; return result;
} }
f32 LinearFromSrgbF32(f32 srgb) f32 LinearFromSrgbF32(f32 srgb)
{ {
f32 result; f32 result;
if (srgb <= 0.04045f) if (srgb <= 0.04045f)
{ {
result = srgb / 12.92f; result = srgb / 12.92f;
} }
else else
{ {
result = pow((srgb + 0.055f) / 1.055f, 2.4f); result = pow((srgb + 0.055f) / 1.055f, 2.4f);
} }
return result; return result;
} }
Vec4 LinearFromSrgb(Vec4 srgb) Vec4 LinearFromSrgb(Vec4 srgb)
{ {
Vec4 result; Vec4 result;
result.x = LinearFromSrgbF32(srgb.x); result.x = LinearFromSrgbF32(srgb.x);
result.y = LinearFromSrgbF32(srgb.y); result.y = LinearFromSrgbF32(srgb.y);
result.z = LinearFromSrgbF32(srgb.z); result.z = LinearFromSrgbF32(srgb.z);
result.w = srgb.w; result.w = srgb.w;
return result; return result;
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -128,13 +128,13 @@ Vec4 LinearFromSrgb(Vec4 srgb)
Vec2 RectUvFromVertexId(u32 id) Vec2 RectUvFromVertexId(u32 id)
{ {
static const Vec2 uvs[4] = { static const Vec2 uvs[4] = {
Vec2(0, 0), Vec2(0, 0),
Vec2(1, 0), Vec2(1, 0),
Vec2(1, 1), Vec2(1, 1),
Vec2(0, 1) Vec2(0, 1)
}; };
return uvs[id]; return uvs[id];
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -142,20 +142,20 @@ Vec2 RectUvFromVertexId(u32 id)
Vec2 NdcFromPos(Vec2 pos, Vec2 size) Vec2 NdcFromPos(Vec2 pos, Vec2 size)
{ {
Vec2 result; Vec2 result;
result = pos / size; result = pos / size;
result *= Vec2(2, -2); result *= Vec2(2, -2);
result += Vec2(-1, 1); result += Vec2(-1, 1);
return result; return result;
} }
Vec2 NdcFromUv(Vec2 uv) Vec2 NdcFromUv(Vec2 uv)
{ {
Vec2 result; Vec2 result;
result = uv; result = uv;
result *= Vec2(2, -2); result *= Vec2(2, -2);
result += Vec2(-1, 1); result += Vec2(-1, 1);
return result; return result;
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -165,195 +165,195 @@ Vec2 NdcFromUv(Vec2 uv)
template<typename T> template<typename T>
u32 U32FromChar(in T c) u32 U32FromChar(in T c)
{ {
if(c == ' ') if(c == ' ')
return 32; return 32;
if(c == '!') if(c == '!')
return 33; return 33;
if(c == '\"' || c == '\"') if(c == '\"' || c == '\"')
return 34; return 34;
if(c == '#') if(c == '#')
return 35; return 35;
if(c == '$') if(c == '$')
return 36; return 36;
if(c == '%') if(c == '%')
return 37; return 37;
if(c == '&') if(c == '&')
return 38; return 38;
if(c == '\'') if(c == '\'')
return 39; return 39;
if(c == '(') if(c == '(')
return 40; return 40;
if(c == ')') if(c == ')')
return 41; return 41;
if(c == '*') if(c == '*')
return 42; return 42;
if(c == '+') if(c == '+')
return 43; return 43;
if(c == ',') if(c == ',')
return 44; return 44;
if(c == '-') if(c == '-')
return 45; return 45;
if(c == '.') if(c == '.')
return 46; return 46;
if(c == '/') if(c == '/')
return 47; return 47;
if(c == '0') if(c == '0')
return 48; return 48;
if(c == '1') if(c == '1')
return 49; return 49;
if(c == '2') if(c == '2')
return 50; return 50;
if(c == '3') if(c == '3')
return 51; return 51;
if(c == '4') if(c == '4')
return 52; return 52;
if(c == '5') if(c == '5')
return 53; return 53;
if(c == '6') if(c == '6')
return 54; return 54;
if(c == '7') if(c == '7')
return 55; return 55;
if(c == '8') if(c == '8')
return 56; return 56;
if(c == '9') if(c == '9')
return 57; return 57;
if(c == ':') if(c == ':')
return 58; return 58;
if(c == ';') if(c == ';')
return 59; return 59;
if(c == '<') if(c == '<')
return 60; return 60;
if(c == '=') if(c == '=')
return 61; return 61;
if(c == '>') if(c == '>')
return 62; return 62;
if(c == '?') if(c == '?')
return 63; return 63;
if(c == '@') if(c == '@')
return 64; return 64;
if(c == 'A') if(c == 'A')
return 65; return 65;
if(c == 'B') if(c == 'B')
return 66; return 66;
if(c == 'C') if(c == 'C')
return 67; return 67;
if(c == 'D') if(c == 'D')
return 68; return 68;
if(c == 'E') if(c == 'E')
return 69; return 69;
if(c == 'F') if(c == 'F')
return 70; return 70;
if(c == 'G') if(c == 'G')
return 71; return 71;
if(c == 'H') if(c == 'H')
return 72; return 72;
if(c == 'I') if(c == 'I')
return 73; return 73;
if(c == 'J') if(c == 'J')
return 74; return 74;
if(c == 'K') if(c == 'K')
return 75; return 75;
if(c == 'L') if(c == 'L')
return 76; return 76;
if(c == 'M') if(c == 'M')
return 77; return 77;
if(c == 'N') if(c == 'N')
return 78; return 78;
if(c == 'O') if(c == 'O')
return 79; return 79;
if(c == 'P') if(c == 'P')
return 80; return 80;
if(c == 'Q') if(c == 'Q')
return 81; return 81;
if(c == 'R') if(c == 'R')
return 82; return 82;
if(c == 'S') if(c == 'S')
return 83; return 83;
if(c == 'T') if(c == 'T')
return 84; return 84;
if(c == 'U') if(c == 'U')
return 85; return 85;
if(c == 'V') if(c == 'V')
return 86; return 86;
if(c == 'W') if(c == 'W')
return 87; return 87;
if(c == 'X') if(c == 'X')
return 88; return 88;
if(c == 'Y') if(c == 'Y')
return 89; return 89;
if(c == 'Z') if(c == 'Z')
return 90; return 90;
if(c == '[') if(c == '[')
return 91; return 91;
if(c == '\\') if(c == '\\')
return 92; return 92;
if(c == ']') if(c == ']')
return 93; return 93;
if(c == '^') if(c == '^')
return 94; return 94;
if(c == '_') if(c == '_')
return 95; return 95;
if(c == '`') if(c == '`')
return 96; return 96;
if(c == 'a') if(c == 'a')
return 97; return 97;
if(c == 'b') if(c == 'b')
return 98; return 98;
if(c == 'c') if(c == 'c')
return 99; return 99;
if(c == 'd') if(c == 'd')
return 100; return 100;
if(c == 'e') if(c == 'e')
return 101; return 101;
if(c == 'f') if(c == 'f')
return 102; return 102;
if(c == 'g') if(c == 'g')
return 103; return 103;
if(c == 'h') if(c == 'h')
return 104; return 104;
if(c == 'i') if(c == 'i')
return 105; return 105;
if(c == 'j') if(c == 'j')
return 106; return 106;
if(c == 'k') if(c == 'k')
return 107; return 107;
if(c == 'l') if(c == 'l')
return 108; return 108;
if(c == 'm') if(c == 'm')
return 109; return 109;
if(c == 'n') if(c == 'n')
return 110; return 110;
if(c == 'o') if(c == 'o')
return 111; return 111;
if(c == 'p') if(c == 'p')
return 112; return 112;
if(c == 'q') if(c == 'q')
return 113; return 113;
if(c == 'r') if(c == 'r')
return 114; return 114;
if(c == 's') if(c == 's')
return 115; return 115;
if(c == 't') if(c == 't')
return 116; return 116;
if(c == 'u') if(c == 'u')
return 117; return 117;
if(c == 'v') if(c == 'v')
return 118; return 118;
if(c == 'w') if(c == 'w')
return 119; return 119;
if(c == 'x') if(c == 'x')
return 120; return 120;
if(c == 'y') if(c == 'y')
return 121; return 121;
if(c == 'z') if(c == 'z')
return 122; return 122;
if(c == '{') if(c == '{')
return 123; return 123;
if(c == '|') if(c == '|')
return 124; return 124;
if(c == '}') if(c == '}')
return 125; return 125;
if(c == '~') if(c == '~')
return 126; return 126;
return 0; return 0;
} }

View File

@ -3,10 +3,10 @@
Struct(BaseCtx) Struct(BaseCtx)
{ {
CmdLineCtx cmdline; CmdLineCtx cmdline;
ResourceCtx resource; ResourceCtx resource;
GstatCtx gstat; GstatCtx gstat;
AsyncCtx async; AsyncCtx async;
}; };
extern BaseCtx Base; extern BaseCtx Base;
@ -16,7 +16,7 @@ extern BaseCtx Base;
Struct(BaseThreadLocalCtx) Struct(BaseThreadLocalCtx)
{ {
ThreadLocalArenaCtx arenas; ThreadLocalArenaCtx arenas;
}; };
extern ThreadLocal BaseThreadLocalCtx Base_tl; extern ThreadLocal BaseThreadLocalCtx Base_tl;

File diff suppressed because it is too large Load Diff

View File

@ -6,60 +6,60 @@
Enum(FmtArgKind) Enum(FmtArgKind)
{ {
FmtArgKind_None, FmtArgKind_None,
/* Arbitrary magic numbers for argument validation */ /* Arbitrary magic numbers for argument validation */
FmtArgKind_Char = 0xf5281df, FmtArgKind_Char = 0xf5281df,
FmtArgKind_String = 0xa5ffa9a, FmtArgKind_String = 0xa5ffa9a,
FmtArgKind_Uint = 0x746f19b, FmtArgKind_Uint = 0x746f19b,
FmtArgKind_Uint2 = 0x83429d9, FmtArgKind_Uint2 = 0x83429d9,
FmtArgKind_Uint3 = 0x1b4b749, FmtArgKind_Uint3 = 0x1b4b749,
FmtArgKind_Uint4 = 0xf8eb3cf, FmtArgKind_Uint4 = 0xf8eb3cf,
FmtArgKind_Sint = 0x8603694, FmtArgKind_Sint = 0x8603694,
FmtArgKind_Sint2 = 0x335a803, FmtArgKind_Sint2 = 0x335a803,
FmtArgKind_Sint3 = 0xe5e4ab1, FmtArgKind_Sint3 = 0xe5e4ab1,
FmtArgKind_Sint4 = 0xe1fd7ad, FmtArgKind_Sint4 = 0xe1fd7ad,
FmtArgKind_Float = 0x4814143, FmtArgKind_Float = 0x4814143,
FmtArgKind_Float2 = 0x4260065, FmtArgKind_Float2 = 0x4260065,
FmtArgKind_Float3 = 0x0d28ab7, FmtArgKind_Float3 = 0x0d28ab7,
FmtArgKind_Float4 = 0x76fe314, FmtArgKind_Float4 = 0x76fe314,
FmtArgKind_Hex = 0xa3d0792, FmtArgKind_Hex = 0xa3d0792,
FmtArgKind_Ptr = 0xc4519e4, FmtArgKind_Ptr = 0xc4519e4,
FmtArgKind_Uid = 0xd1cd407, FmtArgKind_Uid = 0xd1cd407,
FmtArgKind_Handle = 0xead3bec, FmtArgKind_Handle = 0xead3bec,
FmtArgKind_End = 0xecbc5ae FmtArgKind_End = 0xecbc5ae
}; };
Struct(FmtArg) Struct(FmtArg)
{ {
FmtArgKind kind; FmtArgKind kind;
u32 p; /* Precision */ u32 p; /* Precision */
u32 z; /* Z-fill */ u32 z; /* Z-fill */
union union
{
u8 c;
String string;
Vec4U64 uints;
Vec4I64 sints;
Vec4F64 floats;
void *ptr;
Uid uid;
struct
{ {
u8 c; u64 h64[2];
String string; } handle;
Vec4U64 uints; } value;
Vec4I64 sints;
Vec4F64 floats;
void *ptr;
Uid uid;
struct
{
u64 h64[2];
} handle;
} value;
}; };
Struct(FmtArgArray) Struct(FmtArgArray)
{ {
u64 count; u64 count;
FmtArg *args; FmtArg *args;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -67,11 +67,11 @@ Struct(FmtArgArray)
Struct(CodepointIter) Struct(CodepointIter)
{ {
u32 codepoint; u32 codepoint;
/* Internal */ /* Internal */
String src; String src;
u64 pos; u64 pos;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////

View File

@ -4,135 +4,135 @@
//- Exclusive mutex lock //- Exclusive mutex lock
Lock LockSpinE(Mutex *m, i32 spin) Lock LockSpinE(Mutex *m, i32 spin)
{ {
b32 locked = 0; b32 locked = 0;
i32 spin_cnt = 0; i32 spin_cnt = 0;
while (!locked) while (!locked)
{
++spin_cnt;
u32 v = Atomic32FetchTestSet(&m->v, 0, 0x80000000);
if (v == 0)
{ {
++spin_cnt; locked = 1;
u32 v = Atomic32FetchTestSet(&m->v, 0, 0x80000000);
if (v == 0)
{
locked = 1;
}
else if (v == 0x40000000)
{
/* Lock has pending bit set, try to lock */
u32 swp = Atomic32FetchTestSet(&m->v, v, 0x80000000);
while (swp != v && swp == 0x40000000)
{
v = swp;
swp = Atomic32FetchTestSet(&m->v, v, 0x80000000);
}
v = swp;
if (v == 0x40000000)
{
locked = 1;
}
}
if (!locked && (v & 0xC0000000) == 0)
{
/* Lock has shared lockers and no pending waiter, set pending bit */
u32 swp = Atomic32FetchTestSet(&m->v, v, v | 0x40000000);
while (swp != v && (swp & 0xC0000000) == 0 && swp != 0)
{
v = swp;
swp = Atomic32FetchTestSet(&m->v, v, v | 0x40000000);
}
v = swp;
}
/* Pause or wait */
if (!locked && v != 0 && v != 0x40000000)
{
if (spin_cnt < spin)
{
_mm_pause();
}
else
{
FutexYieldNeq(&m->v, &v, 4);
spin_cnt = 0;
}
}
} }
else if (v == 0x40000000)
{
/* Lock has pending bit set, try to lock */
u32 swp = Atomic32FetchTestSet(&m->v, v, 0x80000000);
while (swp != v && swp == 0x40000000)
{
v = swp;
swp = Atomic32FetchTestSet(&m->v, v, 0x80000000);
}
v = swp;
if (v == 0x40000000)
{
locked = 1;
}
}
if (!locked && (v & 0xC0000000) == 0)
{
/* Lock has shared lockers and no pending waiter, set pending bit */
u32 swp = Atomic32FetchTestSet(&m->v, v, v | 0x40000000);
while (swp != v && (swp & 0xC0000000) == 0 && swp != 0)
{
v = swp;
swp = Atomic32FetchTestSet(&m->v, v, v | 0x40000000);
}
v = swp;
}
/* Pause or wait */
if (!locked && v != 0 && v != 0x40000000)
{
if (spin_cnt < spin)
{
_mm_pause();
}
else
{
FutexYieldNeq(&m->v, &v, 4);
spin_cnt = 0;
}
}
}
#if IsRtcEnabled #if IsRtcEnabled
Atomic32Set(&m->exclusive_thread_id, ThreadId()); Atomic32Set(&m->exclusive_thread_id, ThreadId());
#endif #endif
Lock lock = Zi; Lock lock = Zi;
lock.exclusive = 1; lock.exclusive = 1;
lock.mutex = m; lock.mutex = m;
return lock; return lock;
} }
//- Shared mutex lock //- Shared mutex lock
Lock LockSpinS(Mutex *m, i32 spin) Lock LockSpinS(Mutex *m, i32 spin)
{ {
b32 locked = 0; b32 locked = 0;
i32 spin_cnt = 0; i32 spin_cnt = 0;
while (!locked) while (!locked)
{
++spin_cnt;
u32 v = Atomic32Fetch(&m->v);
while (!locked && (v & 0xC0000000) == 0)
{ {
++spin_cnt; /* Lock has no exclusive or pending exclusive lock, increment shared count */
u32 v = Atomic32Fetch(&m->v); u32 swp = Atomic32FetchTestSet(&m->v, v, v + 1);
while (!locked && (v & 0xC0000000) == 0) if (v == swp)
{ {
/* Lock has no exclusive or pending exclusive lock, increment shared count */ locked = 1;
u32 swp = Atomic32FetchTestSet(&m->v, v, v + 1); }
if (v == swp) else
{ {
locked = 1; v = swp;
} }
else
{
v = swp;
}
}
/* Pause or wait */
if (!locked)
{
if (spin_cnt < spin)
{
_mm_pause();
}
else
{
FutexYieldNeq(&m->v, &v, 4);
spin_cnt = 0;
}
}
} }
Lock lock = Zi; /* Pause or wait */
lock.mutex = m; if (!locked)
return lock; {
if (spin_cnt < spin)
{
_mm_pause();
}
else
{
FutexYieldNeq(&m->v, &v, 4);
spin_cnt = 0;
}
}
}
Lock lock = Zi;
lock.mutex = m;
return lock;
} }
//- Mutex lock wrappers //- Mutex lock wrappers
Lock LockE(Mutex *m) Lock LockE(Mutex *m)
{ {
return LockSpinE(m, DefaultMutexSpin); return LockSpinE(m, DefaultMutexSpin);
} }
Lock LockS(Mutex *m) Lock LockS(Mutex *m)
{ {
return LockSpinS(m, DefaultMutexSpin); return LockSpinS(m, DefaultMutexSpin);
} }
void Unlock(Lock *l) void Unlock(Lock *l)
{ {
Mutex *m = l->mutex; Mutex *m = l->mutex;
if (l->exclusive) if (l->exclusive)
{ {
#if IsRtcEnabled #if IsRtcEnabled
Atomic32Set(&m->exclusive_thread_id, 0); Atomic32Set(&m->exclusive_thread_id, 0);
#endif #endif
Atomic32Set(&m->v, 0); Atomic32Set(&m->v, 0);
} }
else else
{ {
Atomic32FetchAdd(&m->v, -1); Atomic32FetchAdd(&m->v, -1);
} }
FutexWakeNeq(&m->v); FutexWakeNeq(&m->v);
ZeroStruct(l); ZeroStruct(l);
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -140,29 +140,29 @@ void Unlock(Lock *l)
void YieldOnCv(Cv *cv, Lock *l) void YieldOnCv(Cv *cv, Lock *l)
{ {
u64 old_wake_gen = Atomic64Fetch(&cv->wake_gen); u64 old_wake_gen = Atomic64Fetch(&cv->wake_gen);
Mutex *mutex = l->mutex; Mutex *mutex = l->mutex;
b32 exclusive = l->exclusive; b32 exclusive = l->exclusive;
{
Unlock(l);
{ {
Unlock(l); FutexYieldNeq(&cv->wake_gen, &old_wake_gen, sizeof(old_wake_gen));
{
FutexYieldNeq(&cv->wake_gen, &old_wake_gen, sizeof(old_wake_gen));
}
if (exclusive)
{
*l = LockE(mutex);
}
else
{
*l = LockS(mutex);
}
} }
if (exclusive)
{
*l = LockE(mutex);
}
else
{
*l = LockS(mutex);
}
}
} }
void SignalCv(Cv *cv) void SignalCv(Cv *cv)
{ {
Atomic64FetchAdd(&cv->wake_gen, 1); Atomic64FetchAdd(&cv->wake_gen, 1);
FutexWakeNeq(&cv->wake_gen); FutexWakeNeq(&cv->wake_gen);
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -170,36 +170,36 @@ void SignalCv(Cv *cv)
i64 FetchFence(Fence *fence) i64 FetchFence(Fence *fence)
{ {
return Atomic64Fetch(&fence->v.v); return Atomic64Fetch(&fence->v.v);
} }
void SetFence(Fence *fence, i64 x) void SetFence(Fence *fence, i64 x)
{ {
Atomic64Set(&fence->v.v, x); Atomic64Set(&fence->v.v, x);
FutexWakeGte(&fence->v.v); FutexWakeGte(&fence->v.v);
} }
i64 FetchSetFence(Fence *fence, i64 x) i64 FetchSetFence(Fence *fence, i64 x)
{ {
i64 fetch = Atomic64FetchSet(&fence->v.v, x); i64 fetch = Atomic64FetchSet(&fence->v.v, x);
FutexWakeGte(&fence->v.v); FutexWakeGte(&fence->v.v);
return fetch; return fetch;
} }
i64 FetchAddFence(Fence *fence, i64 x) i64 FetchAddFence(Fence *fence, i64 x)
{ {
i64 fetch = Atomic64FetchAdd(&fence->v.v, x); i64 fetch = Atomic64FetchAdd(&fence->v.v, x);
FutexWakeGte(&fence->v.v); FutexWakeGte(&fence->v.v);
return fetch; return fetch;
} }
i64 YieldOnFence(Fence *fence, i64 target) i64 YieldOnFence(Fence *fence, i64 target)
{ {
i64 v = Atomic64Fetch(&fence->v.v); i64 v = Atomic64Fetch(&fence->v.v);
while (v < target) while (v < target)
{ {
FutexYieldGte(&fence->v.v, &v, sizeof(v)); FutexYieldGte(&fence->v.v, &v, sizeof(v));
v = Atomic64Fetch(&fence->v.v); v = Atomic64Fetch(&fence->v.v);
} }
return v; return v;
} }

View File

@ -53,11 +53,11 @@ void Unlock(Lock *lock);
//- Lock assertion //- Lock assertion
#if IsRtcEnabled #if IsRtcEnabled
# define AssertLockedE(l, m) Assert((l)->mutex == (m) && (l)->exclusive == 1) #define AssertLockedE(l, m) Assert((l)->mutex == (m) && (l)->exclusive == 1)
# define AssertLockedES(l, m) Assert((l)->mutex == (m)) #define AssertLockedES(l, m) Assert((l)->mutex == (m))
#else #else
# define AssertLockedE(l, m) #define AssertLockedE(l, m)
# define AssertLockedES(l, m) #define AssertLockedES(l, m)
#endif #endif
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////

View File

@ -3,14 +3,14 @@
Struct(DateTime) Struct(DateTime)
{ {
u32 year; u32 year;
u32 month; u32 month;
u32 day_of_week; u32 day_of_week;
u32 day; u32 day;
u32 hour; u32 hour;
u32 minute; u32 minute;
u32 second; u32 second;
u32 milliseconds; u32 milliseconds;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////

View File

@ -1,22 +1,22 @@
/* Returns a uid generated from the system's random number generator */ /* Returns a uid generated from the system's random number generator */
Uid UidFromTrueRand(void) Uid UidFromTrueRand(void)
{ {
Uid result = Zi; Uid result = Zi;
TrueRand(StringFromStruct(&result)); TrueRand(StringFromStruct(&result));
return result; return result;
} }
/* Combines 2 uids into a new uid */ /* Combines 2 uids into a new uid */
Uid CombineUid(Uid a, Uid b) Uid CombineUid(Uid a, Uid b)
{ {
Uid result; Uid result;
result.hi = (a.hi * 3) + b.hi; result.hi = (a.hi * 3) + b.hi;
result.lo = (a.lo * 3) + b.lo; result.lo = (a.lo * 3) + b.lo;
result.hi += result.lo; result.hi += result.lo;
result.lo += result.hi; result.lo += result.hi;
result.hi = RandU64FromSeed(result.hi); result.hi = RandU64FromSeed(result.hi);
result.lo = RandU64FromSeed(result.lo); result.lo = RandU64FromSeed(result.lo);
result.hi += result.lo; result.hi += result.lo;
result.lo += result.hi; result.lo += result.hi;
return result; return result;
} }

View File

@ -3,8 +3,8 @@
Struct(Uid) Struct(Uid)
{ {
u64 hi; u64 hi;
u64 lo; u64 lo;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////

View File

@ -5,126 +5,130 @@
Utf8DecodeResult DecodeUtf8(String str) Utf8DecodeResult DecodeUtf8(String str)
{ {
const u8 lengths[32] = { const u8 lengths[32] = {
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,2,2,2,2,3,3,4,5 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,2,2,2,2,3,3,4,5
}; };
Utf8DecodeResult result = Zi; Utf8DecodeResult result = Zi;
u32 codepoint = U32Max; u32 codepoint = U32Max;
u32 advance = 0; u32 advance = 0;
if (str.len > 0) if (str.len > 0)
{
u8 c0 = str.text[0];
u8 utf8_len = lengths[c0 >> 3];
advance = 1;
switch (utf8_len)
{ {
u8 c0 = str.text[0]; default: break;
u8 utf8_len = lengths[c0 >> 3];
advance = 1; case 1:
switch (utf8_len) {
codepoint = c0;
} break;
case 2:
{
if (str.len >= 2)
{ {
default: break; u8 c1 = str.text[1];
if (lengths[c1 >> 3] == 0)
case 1: {
{ codepoint = (c1 & 0x3F) << 0;
codepoint = c0; codepoint |= (c0 & 0x1F) << 6;
} break; advance = 2;
}
case 2:
{
if (str.len >= 2)
{
u8 c1 = str.text[1];
if (lengths[c1 >> 3] == 0)
{
codepoint = (c1 & 0x3F) << 0;
codepoint |= (c0 & 0x1F) << 6;
advance = 2;
}
}
} break;
case 3:
{
if (str.len >= 3)
{
u8 c1 = str.text[1];
u8 c2 = str.text[2];
if (lengths[c1 >> 3] == 0 &&
lengths[c2 >> 3] == 0)
{
codepoint = (c2 & 0x3F) << 0;
codepoint |= (c1 & 0x3F) << 6;
codepoint |= (c0 & 0x0F) << 12;
advance = 3;
}
}
} break;
case 4:
{
if (str.len >= 4)
{
u8 c1 = str.text[1];
u8 c2 = str.text[2];
u8 c3 = str.text[3];
if (lengths[c1 >> 3] == 0 &&
lengths[c2 >> 3] == 0 &&
lengths[c3 >> 3] == 0)
{
codepoint = (c3 & 0x3F) << 0;
codepoint |= (c2 & 0x3F) << 6;
codepoint |= (c1 & 0x3F) << 12;
codepoint |= (c0 & 0x07) << 16;
advance = 3;
}
}
} break;
} }
} } break;
result.advance8 = advance; case 3:
result.codepoint = codepoint; {
return result; if (str.len >= 3)
{
u8 c1 = str.text[1];
u8 c2 = str.text[2];
if (
lengths[c1 >> 3] == 0 &&
lengths[c2 >> 3] == 0
)
{
codepoint = (c2 & 0x3F) << 0;
codepoint |= (c1 & 0x3F) << 6;
codepoint |= (c0 & 0x0F) << 12;
advance = 3;
}
}
} break;
case 4:
{
if (str.len >= 4)
{
u8 c1 = str.text[1];
u8 c2 = str.text[2];
u8 c3 = str.text[3];
if (
lengths[c1 >> 3] == 0 &&
lengths[c2 >> 3] == 0 &&
lengths[c3 >> 3] == 0
)
{
codepoint = (c3 & 0x3F) << 0;
codepoint |= (c2 & 0x3F) << 6;
codepoint |= (c1 & 0x3F) << 12;
codepoint |= (c0 & 0x07) << 16;
advance = 3;
}
}
} break;
}
}
result.advance8 = advance;
result.codepoint = codepoint;
return result;
} }
//- Encode //- Encode
Utf8EncodeResult EncodeUtf8(u32 codepoint) Utf8EncodeResult EncodeUtf8(u32 codepoint)
{ {
Utf8EncodeResult result = Zi; Utf8EncodeResult result = Zi;
if (codepoint <= 0x7F) if (codepoint <= 0x7F)
{ {
result.count8 = 1; result.count8 = 1;
result.chars8[0] = codepoint; result.chars8[0] = codepoint;
} }
else if (codepoint <= 0x7FF) else if (codepoint <= 0x7FF)
{ {
result.count8 = 2; result.count8 = 2;
result.chars8[1] = 0x80 | ((codepoint >> 0) & 0x3F); result.chars8[1] = 0x80 | ((codepoint >> 0) & 0x3F);
result.chars8[0] = 0xC0 | ((codepoint >> 6) & 0x1F); result.chars8[0] = 0xC0 | ((codepoint >> 6) & 0x1F);
} }
else if (codepoint <= 0xFFFF) else if (codepoint <= 0xFFFF)
{ {
result.count8 = 3; result.count8 = 3;
result.chars8[2] = 0x80 | ((codepoint >> 0) & 0x3F); result.chars8[2] = 0x80 | ((codepoint >> 0) & 0x3F);
result.chars8[1] = 0x80 | ((codepoint >> 6) & 0x3F); result.chars8[1] = 0x80 | ((codepoint >> 6) & 0x3F);
result.chars8[0] = 0xE0 | ((codepoint >> 12) & 0x0F); result.chars8[0] = 0xE0 | ((codepoint >> 12) & 0x0F);
} }
else if (codepoint <= 0x10FFFF) else if (codepoint <= 0x10FFFF)
{ {
result.count8 = 4; result.count8 = 4;
result.chars8[3] = 0x80 | ((codepoint >> 0) & 0x3F); result.chars8[3] = 0x80 | ((codepoint >> 0) & 0x3F);
result.chars8[2] = 0x80 | ((codepoint >> 6) & 0x3F); result.chars8[2] = 0x80 | ((codepoint >> 6) & 0x3F);
result.chars8[1] = 0x80 | ((codepoint >> 12) & 0x3F); result.chars8[1] = 0x80 | ((codepoint >> 12) & 0x3F);
result.chars8[0] = 0xF0 | ((codepoint >> 18) & 0x07); result.chars8[0] = 0xF0 | ((codepoint >> 18) & 0x07);
} }
else else
{ {
/* Invalid codepoint */ /* Invalid codepoint */
result.count8 = 1; result.count8 = 1;
result.chars8[0] = '?'; result.chars8[0] = '?';
} }
return result; return result;
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -134,69 +138,69 @@ Utf8EncodeResult EncodeUtf8(u32 codepoint)
Utf16DecodeResult DecodeUtf16(String16 str) Utf16DecodeResult DecodeUtf16(String16 str)
{ {
Utf16DecodeResult result = Zi; Utf16DecodeResult result = Zi;
u32 codepoint = U32Max; u32 codepoint = U32Max;
u32 advance = 0; u32 advance = 0;
if (str.len >= 1) if (str.len >= 1)
{
u16 c0 = str.text[0];
codepoint = c0;
advance = 1;
if (str.len >= 2)
{ {
u16 c0 = str.text[0]; u16 c1 = str.text[1];
codepoint = c0; if ((0xD800 <= c0 && c0 < 0xDC00) && (0xDC00 <= c1 && c1 < 0xE000))
advance = 1; {
if (str.len >= 2) codepoint = (c1 & 0x3FF) << 0;
{ codepoint |= (c0 & 0x3FF) << 10;
u16 c1 = str.text[1]; advance = 2;
if ((0xD800 <= c0 && c0 < 0xDC00) && (0xDC00 <= c1 && c1 < 0xE000)) }
{
codepoint = (c1 & 0x3FF) << 0;
codepoint |= (c0 & 0x3FF) << 10;
advance = 2;
}
}
} }
}
result.advance16 = advance; result.advance16 = advance;
result.codepoint = codepoint; result.codepoint = codepoint;
return result; return result;
} }
//- Encode //- Encode
Utf16EncodeResult EncodeUtf16(u32 codepoint) Utf16EncodeResult EncodeUtf16(u32 codepoint)
{ {
Utf16EncodeResult result = Zi; Utf16EncodeResult result = Zi;
if (codepoint <= 0xFFFF) if (codepoint <= 0xFFFF)
{ {
result.count16 = 1; result.count16 = 1;
result.chars16[0] = codepoint; result.chars16[0] = codepoint;
} }
else if (codepoint <= 0x10FFFF) else if (codepoint <= 0x10FFFF)
{ {
result.count16 = 2; result.count16 = 2;
result.chars16[1] = 0xDC00 | ((codepoint >> 0) & 0x3FF); result.chars16[1] = 0xDC00 | ((codepoint >> 0) & 0x3FF);
result.chars16[0] = 0xD800 | ((codepoint >> 10) & 0x3FF); result.chars16[0] = 0xD800 | ((codepoint >> 10) & 0x3FF);
} }
else else
{ {
/* Invalid codepoint */ /* Invalid codepoint */
result.count16 = 1; result.count16 = 1;
result.chars16[0] = '?'; result.chars16[0] = '?';
} }
return result; return result;
} }
//- Surrogate check //- Surrogate check
b32 IsUtf16HighSurrogate(u16 c) b32 IsUtf16HighSurrogate(u16 c)
{ {
return 0xD800 <= c && c < 0xDC00; return 0xD800 <= c && c < 0xDC00;
} }
b32 IsUtf16LowSurrogate(u16 c) b32 IsUtf16LowSurrogate(u16 c)
{ {
return 0xDC00 <= c && c < 0xE000; return 0xDC00 <= c && c < 0xE000;
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -206,40 +210,40 @@ b32 IsUtf16LowSurrogate(u16 c)
Utf32DecodeResult DecodeUtf32(String32 str) Utf32DecodeResult DecodeUtf32(String32 str)
{ {
Utf32DecodeResult result = Zi; Utf32DecodeResult result = Zi;
u32 codepoint = U32Max; u32 codepoint = U32Max;
u32 advance = 0; u32 advance = 0;
if (str.len >= 1) if (str.len >= 1)
{
u32 c = str.text[0];
advance = 1;
if (c <= 0x10FFFF)
{ {
u32 c = str.text[0]; codepoint = c;
advance = 1;
if (c <= 0x10FFFF)
{
codepoint = c;
}
} }
}
result.advance32 = advance; result.advance32 = advance;
result.codepoint = codepoint; result.codepoint = codepoint;
return result; return result;
} }
//- Encode //- Encode
Utf32EncodeResult EncodeUtf32(u32 codepoint) Utf32EncodeResult EncodeUtf32(u32 codepoint)
{ {
Utf32EncodeResult result = Zi; Utf32EncodeResult result = Zi;
if (codepoint <= 0x10FFFF) if (codepoint <= 0x10FFFF)
{ {
result.chars32 = codepoint; result.chars32 = codepoint;
} }
else else
{ {
/* Invalid codepoint */ /* Invalid codepoint */
result.chars32 = '?'; result.chars32 = '?';
} }
return result; return result;
} }

View File

@ -3,14 +3,14 @@
Struct(Utf8DecodeResult) Struct(Utf8DecodeResult)
{ {
u32 advance8; u32 advance8;
u32 codepoint; u32 codepoint;
}; };
Struct(Utf8EncodeResult) Struct(Utf8EncodeResult)
{ {
u32 count8; u32 count8;
u8 chars8[4]; u8 chars8[4];
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -18,14 +18,14 @@ Struct(Utf8EncodeResult)
Struct(Utf16DecodeResult) Struct(Utf16DecodeResult)
{ {
u32 advance16; u32 advance16;
u32 codepoint; u32 codepoint;
}; };
Struct(Utf16EncodeResult) Struct(Utf16EncodeResult)
{ {
u32 count16; u32 count16;
u16 chars16[2]; u16 chars16[2];
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -33,13 +33,13 @@ Struct(Utf16EncodeResult)
Struct(Utf32DecodeResult) Struct(Utf32DecodeResult)
{ {
u32 advance32; u32 advance32;
u32 codepoint; u32 codepoint;
}; };
Struct(Utf32EncodeResult) Struct(Utf32EncodeResult)
{ {
u32 chars32; u32 chars32;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////

View File

@ -19,27 +19,27 @@ typedef MergesortCompareFuncDef(MergesortCompareFunc, a, b, udata);
Struct(DictEntry) Struct(DictEntry)
{ {
u64 hash; u64 hash;
u64 value; u64 value;
DictEntry *prev_in_bin; DictEntry *prev_in_bin;
DictEntry *next_in_bin; DictEntry *next_in_bin;
DictEntry *prev; DictEntry *prev;
DictEntry *next; DictEntry *next;
}; };
Struct(DictBin) Struct(DictBin)
{ {
DictEntry *first; DictEntry *first;
DictEntry *last; DictEntry *last;
}; };
Struct(Dict) Struct(Dict)
{ {
u64 bins_count; u64 bins_count;
DictBin *bins; DictBin *bins;
DictEntry *first_free; DictEntry *first_free;
DictEntry *first; DictEntry *first;
DictEntry *last; DictEntry *last;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -50,31 +50,31 @@ Struct(Dict)
*/ */
Inline u64 HashFnv64(u64 seed, String s) Inline u64 HashFnv64(u64 seed, String s)
{ {
u64 hash = seed; u64 hash = seed;
for (u64 i = 0; i < s.len; ++i) for (u64 i = 0; i < s.len; ++i)
{ {
hash ^= (u8)s.text[i]; hash ^= (u8)s.text[i];
hash *= 0x100000001B3; hash *= 0x100000001B3;
} }
return hash; return hash;
} }
#define HashF(fmt_cstr, ...) HashF_(StringFromCstrNoLimit(fmt_cstr), __VA_ARGS__, FmtEnd) #define HashF(fmt_cstr, ...) HashF_(StringFromCstrNoLimit(fmt_cstr), __VA_ARGS__, FmtEnd)
Inline u64 HashF_(String fmt, ...) Inline u64 HashF_(String fmt, ...)
{ {
u64 result = 0; u64 result = 0;
TempArena scratch = BeginScratchNoConflict(); TempArena scratch = BeginScratchNoConflict();
{
va_list args;
va_start(args, fmt);
{ {
va_list args; String str = FormatString(scratch.arena, fmt, FmtArgsFromVaList(scratch.arena, args));
va_start(args, fmt); result = HashFnv64(Fnv64Basis, str);
{
String str = FormatString(scratch.arena, fmt, FmtArgsFromVaList(scratch.arena, args));
result = HashFnv64(Fnv64Basis, str);
}
va_end(args);
} }
EndScratch(scratch); va_end(args);
return result; }
EndScratch(scratch);
return result;
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -82,67 +82,67 @@ Inline u64 HashF_(String fmt, ...)
Inline void MergesortInternal(u8 *left, u8 *right, u8 *items, u64 left_count, u64 right_count, u64 item_size, MergesortCompareFunc *callback, void *udata) Inline void MergesortInternal(u8 *left, u8 *right, u8 *items, u64 left_count, u64 right_count, u64 item_size, MergesortCompareFunc *callback, void *udata)
{ {
/* Sort */ /* Sort */
u64 i = 0; u64 i = 0;
u64 l = 0; u64 l = 0;
u64 r = 0; u64 r = 0;
while (l < left_count && r < right_count) while (l < left_count && r < right_count)
{
u8 *dst = items + (i * item_size);
u8 *left_item = left + (l * item_size);
u8 *right_item = right + (r * item_size);
++i;
if (callback(left_item, right_item, udata) > 0)
{ {
u8 *dst = items + (i * item_size); CopyBytes(dst, left_item, item_size);
u8 *left_item = left + (l * item_size); ++l;
u8 *right_item = right + (r * item_size);
++i;
if (callback(left_item, right_item, udata) > 0)
{
CopyBytes(dst, left_item, item_size);
++l;
}
else
{
CopyBytes(dst, right_item, item_size);
++r;
}
} }
/* Copy remaining */ else
if (l != left_count)
{ {
u64 remaining_count = left_count - l; CopyBytes(dst, right_item, item_size);
u64 remaining_bytes = remaining_count * item_size; ++r;
u8 *dst = items + (i * item_size);
u8 *src = left + (l * item_size);
CopyBytes(dst, src, remaining_bytes);
}
else if (r != right_count)
{
u64 remaining_count = right_count - r;
u64 remaining_bytes = remaining_count * item_size;
u8 *dst = items + (i * item_size);
u8 *src = right + (r * item_size);
CopyBytes(dst, src, remaining_bytes);
} }
}
/* Copy remaining */
if (l != left_count)
{
u64 remaining_count = left_count - l;
u64 remaining_bytes = remaining_count * item_size;
u8 *dst = items + (i * item_size);
u8 *src = left + (l * item_size);
CopyBytes(dst, src, remaining_bytes);
}
else if (r != right_count)
{
u64 remaining_count = right_count - r;
u64 remaining_bytes = remaining_count * item_size;
u8 *dst = items + (i * item_size);
u8 *src = right + (r * item_size);
CopyBytes(dst, src, remaining_bytes);
}
} }
Inline void Mergesort(void *items, u64 item_count, u64 item_size, MergesortCompareFunc *callback, void *udata) Inline void Mergesort(void *items, u64 item_count, u64 item_size, MergesortCompareFunc *callback, void *udata)
{ {
if (item_count > 1) if (item_count > 1)
{ {
TempArena scratch = BeginScratchNoConflict(); TempArena scratch = BeginScratchNoConflict();
u64 left_count = item_count / 2; u64 left_count = item_count / 2;
u64 right_count = item_count - left_count; u64 right_count = item_count - left_count;
u64 left_size = left_count * item_size; u64 left_size = left_count * item_size;
u64 right_size = right_count * item_size; u64 right_size = right_count * item_size;
u8 *left = PushStructsNoZero(scratch.arena, u8, left_size); u8 *left = PushStructsNoZero(scratch.arena, u8, left_size);
u8 *right = PushStructsNoZero(scratch.arena, u8, right_size); u8 *right = PushStructsNoZero(scratch.arena, u8, right_size);
CopyBytes(left, items, left_size); CopyBytes(left, items, left_size);
CopyBytes(right, (u8 *)items + left_size, right_size); CopyBytes(right, (u8 *)items + left_size, right_size);
Mergesort(left, left_count, item_size, callback, udata); Mergesort(left, left_count, item_size, callback, udata);
Mergesort(right, right_count, item_size, callback, udata); Mergesort(right, right_count, item_size, callback, udata);
MergesortInternal(left, right, (u8 *)items, left_count, right_count, item_size, callback, udata); MergesortInternal(left, right, (u8 *)items, left_count, right_count, item_size, callback, udata);
EndScratch(scratch); EndScratch(scratch);
} }
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -152,164 +152,164 @@ Inline void Mergesort(void *items, u64 item_count, u64 item_size, MergesortCompa
Inline Dict *InitDict(Arena *arena, u64 bins_count) Inline Dict *InitDict(Arena *arena, u64 bins_count)
{ {
Dict *dict = PushStruct(arena, Dict); Dict *dict = PushStruct(arena, Dict);
dict->bins_count = MaxU64(bins_count, 1); /* Ensure at least 1 bin */ dict->bins_count = MaxU64(bins_count, 1); /* Ensure at least 1 bin */
dict->bins = PushStructs(arena, DictBin, dict->bins_count); dict->bins = PushStructs(arena, DictBin, dict->bins_count);
return dict; return dict;
} }
Inline void ResetDict(Dict *dict) Inline void ResetDict(Dict *dict)
{ {
ZeroBytes(dict->bins, sizeof(*dict->bins) * dict->bins_count); ZeroBytes(dict->bins, sizeof(*dict->bins) * dict->bins_count);
if (dict->first) if (dict->first)
{ {
dict->last->next = dict->first_free; dict->last->next = dict->first_free;
dict->first_free = dict->first; dict->first_free = dict->first;
} }
} }
//- Dict set //- Dict set
Inline DictEntry *EnsureDictEntry(Arena *arena, Dict *dict, u64 hash) Inline DictEntry *EnsureDictEntry(Arena *arena, Dict *dict, u64 hash)
{ {
DictBin *bin = &dict->bins[hash % dict->bins_count]; DictBin *bin = &dict->bins[hash % dict->bins_count];
DictEntry *entry = bin->first; DictEntry *entry = bin->first;
while (entry) while (entry)
{
if (hash == entry->hash)
{ {
if (hash == entry->hash) /* Existing match found */
{ break;
/* Existing match found */
break;
}
entry = entry->next_in_bin;
} }
entry = entry->next_in_bin;
}
/* No match found, create new entry */ /* No match found, create new entry */
if (!entry) if (!entry)
{
if (dict->first_free)
{ {
if (dict->first_free) entry = dict->first_free;
{ dict->first_free = entry->next;
entry = dict->first_free;
dict->first_free = entry->next;
}
else
{
entry = PushStructNoZero(arena, DictEntry);
}
ZeroStruct(entry);
entry->hash = hash;
if (bin->last)
{
bin->last->next_in_bin = entry;
entry->prev_in_bin = bin->last;
}
else
{
bin->first = entry;
}
bin->last = entry;
if (dict->last)
{
dict->last->next = entry;
entry->prev = dict->last;
}
else
{
dict->first = entry;
}
dict->last = entry;
} }
else
{
entry = PushStructNoZero(arena, DictEntry);
}
ZeroStruct(entry);
entry->hash = hash;
if (bin->last)
{
bin->last->next_in_bin = entry;
entry->prev_in_bin = bin->last;
}
else
{
bin->first = entry;
}
bin->last = entry;
if (dict->last)
{
dict->last->next = entry;
entry->prev = dict->last;
}
else
{
dict->first = entry;
}
dict->last = entry;
}
return entry; return entry;
} }
Inline void SetDictValue(Arena *arena, Dict *dict, u64 hash, u64 value) Inline void SetDictValue(Arena *arena, Dict *dict, u64 hash, u64 value)
{ {
DictEntry *entry = EnsureDictEntry(arena, dict, hash); DictEntry *entry = EnsureDictEntry(arena, dict, hash);
entry->value = value; entry->value = value;
} }
//- Dict remove //- Dict remove
Inline void RemoveDictEntry(Dict *dict, DictEntry *entry) Inline void RemoveDictEntry(Dict *dict, DictEntry *entry)
{ {
/* Remove from bin */ /* Remove from bin */
{
DictBin *bin = &dict->bins[entry->hash % dict->bins_count];
DictEntry *prev_in_bin = entry->prev_in_bin;
DictEntry *next_in_bin = entry->next_in_bin;
if (prev_in_bin)
{ {
DictBin *bin = &dict->bins[entry->hash % dict->bins_count]; prev_in_bin->next_in_bin = next_in_bin;
DictEntry *prev_in_bin = entry->prev_in_bin;
DictEntry *next_in_bin = entry->next_in_bin;
if (prev_in_bin)
{
prev_in_bin->next_in_bin = next_in_bin;
}
else
{
bin->first = next_in_bin;
}
if (next_in_bin)
{
next_in_bin->prev_in_bin = prev_in_bin;
}
else
{
bin->last = prev_in_bin;
}
} }
/* Remove from list */ else
{ {
DictEntry *prev = entry->prev; bin->first = next_in_bin;
DictEntry *next = entry->next;
if (prev)
{
prev->next = next;
}
else
{
dict->first = next;
}
if (next)
{
next->prev = prev;
}
else
{
dict->last = prev;
}
} }
/* Insert into free list */ if (next_in_bin)
{ {
entry->next = dict->first_free; next_in_bin->prev_in_bin = prev_in_bin;
dict->first_free = entry;
} }
else
{
bin->last = prev_in_bin;
}
}
/* Remove from list */
{
DictEntry *prev = entry->prev;
DictEntry *next = entry->next;
if (prev)
{
prev->next = next;
}
else
{
dict->first = next;
}
if (next)
{
next->prev = prev;
}
else
{
dict->last = prev;
}
}
/* Insert into free list */
{
entry->next = dict->first_free;
dict->first_free = entry;
}
} }
//- Dict index //- Dict index
Inline DictEntry *DictEntryFromHash(Dict *dict, u64 hash) Inline DictEntry *DictEntryFromHash(Dict *dict, u64 hash)
{ {
DictEntry *result = 0; DictEntry *result = 0;
DictBin *bin = &dict->bins[hash % dict->bins_count]; DictBin *bin = &dict->bins[hash % dict->bins_count];
for (DictEntry *entry = bin->first; entry; entry = entry->next_in_bin) for (DictEntry *entry = bin->first; entry; entry = entry->next_in_bin)
{
if (hash == entry->hash)
{ {
if (hash == entry->hash) /* Match found */
{ result = entry;
/* Match found */ break;
result = entry;
break;
}
} }
return result; }
return result;
} }
Inline u64 DictValueFromHash(Dict *dict, u64 hash) Inline u64 DictValueFromHash(Dict *dict, u64 hash)
{ {
DictEntry *entry = DictEntryFromHash(dict, hash); DictEntry *entry = DictEntryFromHash(dict, hash);
return entry ? entry->value : 0; return entry ? entry->value : 0;
} }
Inline u64 DictValueOrNilFromHash(Dict *dict, u64 hash, u64 nil) Inline u64 DictValueOrNilFromHash(Dict *dict, u64 hash, u64 nil)
{ {
DictEntry *entry = DictEntryFromHash(dict, hash); DictEntry *entry = DictEntryFromHash(dict, hash);
return entry ? entry->value : nil; return entry ? entry->value : nil;
} }

View File

@ -3,108 +3,108 @@
void WaveSyncEx(WaveLaneCtx *lane, u64 spin_count) void WaveSyncEx(WaveLaneCtx *lane, u64 spin_count)
{ {
WaveCtx *wave = lane->wave; WaveCtx *wave = lane->wave;
i32 lanes_count = wave->lanes_count; i32 lanes_count = wave->lanes_count;
if (lanes_count > 1) if (lanes_count > 1)
{
i64 sync_gen = Atomic64Fetch(&wave->sync_gen.v);
i32 blocked_count = Atomic32FetchAdd(&wave->sync_count.v, 1) + 1;
if (blocked_count == lanes_count)
{ {
i64 sync_gen = Atomic64Fetch(&wave->sync_gen.v); Atomic32Set(&wave->sync_count.v, 0);
i32 blocked_count = Atomic32FetchAdd(&wave->sync_count.v, 1) + 1; Atomic64Set(&wave->sync_gen.v, sync_gen + 1);
if (blocked_count == lanes_count) FutexWakeNeq(&wave->sync_gen.v);
}
else
{
u64 remaining_spins = spin_count;
while (Atomic64Fetch(&wave->sync_gen.v) == sync_gen)
{
if (remaining_spins > 0)
{ {
Atomic32Set(&wave->sync_count.v, 0); --remaining_spins;
Atomic64Set(&wave->sync_gen.v, sync_gen + 1); _mm_pause();
FutexWakeNeq(&wave->sync_gen.v);
} }
else else
{ {
u64 remaining_spins = spin_count; FutexYieldNeq(&wave->sync_gen.v, &sync_gen, sizeof(sync_gen));
while (Atomic64Fetch(&wave->sync_gen.v) == sync_gen)
{
if (remaining_spins > 0)
{
--remaining_spins;
_mm_pause();
}
else
{
FutexYieldNeq(&wave->sync_gen.v, &sync_gen, sizeof(sync_gen));
}
}
} }
}
} }
}
} }
void WaveSyncBroadcastEx_(WaveLaneCtx *lane, u32 broadcast_lane_idx, void *broadcast_ptr, u64 broadcast_size, u64 spin_count) void WaveSyncBroadcastEx_(WaveLaneCtx *lane, u32 broadcast_lane_idx, void *broadcast_ptr, u64 broadcast_size, u64 spin_count)
{ {
WaveCtx *wave = lane->wave; WaveCtx *wave = lane->wave;
i32 lanes_count = wave->lanes_count; i32 lanes_count = wave->lanes_count;
if (lanes_count > 1) if (lanes_count > 1)
{
u32 lane_idx = lane->idx;
if (lane_idx == broadcast_lane_idx)
{ {
u32 lane_idx = lane->idx; /* Broadcast */
wave->broadcast_data = broadcast_ptr;
i64 ack_gen = Atomic64Fetch(&wave->ack_gen.v);
lane->seen_broadcast_gen = Atomic64FetchAdd(&wave->broadcast_gen.v, 1) + 1;
FutexWakeNeq(&wave->broadcast_gen.v);
if (lane_idx == broadcast_lane_idx) /* Wait for ack */
{
u64 remaining_spins = spin_count;
while (Atomic64Fetch(&wave->ack_gen.v) == ack_gen)
{ {
/* Broadcast */ if (remaining_spins > 0)
wave->broadcast_data = broadcast_ptr; {
i64 ack_gen = Atomic64Fetch(&wave->ack_gen.v); --remaining_spins;
lane->seen_broadcast_gen = Atomic64FetchAdd(&wave->broadcast_gen.v, 1) + 1; _mm_pause();
FutexWakeNeq(&wave->broadcast_gen.v); }
else
/* Wait for ack */ {
{ FutexYieldNeq(&wave->ack_gen.v, &ack_gen, sizeof(ack_gen));
u64 remaining_spins = spin_count; }
while (Atomic64Fetch(&wave->ack_gen.v) == ack_gen)
{
if (remaining_spins > 0)
{
--remaining_spins;
_mm_pause();
}
else
{
FutexYieldNeq(&wave->ack_gen.v, &ack_gen, sizeof(ack_gen));
}
}
}
}
else
{
/* Wait for broadcast */
i64 seen_broadcast_gen = lane->seen_broadcast_gen++;
{
u64 remaining_spins = spin_count;
while (Atomic64Fetch(&wave->broadcast_gen.v) == seen_broadcast_gen)
{
if (remaining_spins > 0)
{
--remaining_spins;
_mm_pause();
}
else
{
FutexYieldNeq(&wave->broadcast_gen.v, &seen_broadcast_gen, sizeof(seen_broadcast_gen));
}
}
}
/* Copy broadcast data */
CopyBytes(broadcast_ptr, wave->broadcast_data, broadcast_size);
/* Ack */
i32 ack_count = Atomic32FetchAdd(&wave->ack_count.v, 1) + 1;
if (ack_count == lanes_count - 1)
{
Atomic32Set(&wave->ack_count.v, 0);
Atomic64FetchAdd(&wave->ack_gen.v, 1);
FutexWakeNeq(&wave->ack_gen.v);
}
} }
}
} }
else
{
/* Wait for broadcast */
i64 seen_broadcast_gen = lane->seen_broadcast_gen++;
{
u64 remaining_spins = spin_count;
while (Atomic64Fetch(&wave->broadcast_gen.v) == seen_broadcast_gen)
{
if (remaining_spins > 0)
{
--remaining_spins;
_mm_pause();
}
else
{
FutexYieldNeq(&wave->broadcast_gen.v, &seen_broadcast_gen, sizeof(seen_broadcast_gen));
}
}
}
/* Copy broadcast data */
CopyBytes(broadcast_ptr, wave->broadcast_data, broadcast_size);
/* Ack */
i32 ack_count = Atomic32FetchAdd(&wave->ack_count.v, 1) + 1;
if (ack_count == lanes_count - 1)
{
Atomic32Set(&wave->ack_count.v, 0);
Atomic64FetchAdd(&wave->ack_gen.v, 1);
FutexWakeNeq(&wave->ack_gen.v);
}
}
}
} }
void SetWaveLaneDefaultSpin(WaveLaneCtx *lane, u64 n) void SetWaveLaneDefaultSpin(WaveLaneCtx *lane, u64 n)
{ {
lane->default_spin_count = n; lane->default_spin_count = n;
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -112,30 +112,30 @@ void SetWaveLaneDefaultSpin(WaveLaneCtx *lane, u64 n)
i32 WaveLaneIdxFromTaskIdx(WaveLaneCtx *lane, u64 task_idx) i32 WaveLaneIdxFromTaskIdx(WaveLaneCtx *lane, u64 task_idx)
{ {
WaveCtx *wave = lane->wave; WaveCtx *wave = lane->wave;
return task_idx % wave->lanes_count; return task_idx % wave->lanes_count;
} }
RngU64 WaveIdxRangeFromCount(WaveLaneCtx *lane, u64 tasks_count) RngU64 WaveIdxRangeFromCount(WaveLaneCtx *lane, u64 tasks_count)
{ {
u64 lanes_count = lane->wave->lanes_count; u64 lanes_count = lane->wave->lanes_count;
u64 lane_idx = lane->idx; u64 lane_idx = lane->idx;
u64 tasks_per_lane = tasks_count / lanes_count; u64 tasks_per_lane = tasks_count / lanes_count;
u64 tasks_overflow = tasks_count % lanes_count; u64 tasks_overflow = tasks_count % lanes_count;
u64 start = lane_idx * tasks_per_lane; u64 start = lane_idx * tasks_per_lane;
u64 end = start + tasks_per_lane; u64 end = start + tasks_per_lane;
if (lane_idx < tasks_overflow) if (lane_idx < tasks_overflow)
{ {
start += lane_idx; start += lane_idx;
end += lane_idx + 1; end += lane_idx + 1;
} }
else else
{ {
start += tasks_overflow; start += tasks_overflow;
end += tasks_overflow; end += tasks_overflow;
} }
return RNGU64(start, end); return RNGU64(start, end);
} }

View File

@ -6,26 +6,26 @@
AlignedStruct(WaveCtx, CachelineSize) AlignedStruct(WaveCtx, CachelineSize)
{ {
i32 lanes_count; i32 lanes_count;
void *udata; void *udata;
/* Sync barrier */ /* Sync barrier */
Atomic32Padded sync_count; Atomic32Padded sync_count;
Atomic64Padded sync_gen; Atomic64Padded sync_gen;
/* Broadcast barrier */ /* Broadcast barrier */
void *broadcast_data; void *broadcast_data;
Atomic64Padded broadcast_gen; Atomic64Padded broadcast_gen;
Atomic32Padded ack_count; Atomic32Padded ack_count;
Atomic64Padded ack_gen; Atomic64Padded ack_gen;
}; };
AlignedStruct(WaveLaneCtx, CachelineSize) AlignedStruct(WaveLaneCtx, CachelineSize)
{ {
i32 idx; i32 idx;
WaveCtx *wave; WaveCtx *wave;
u64 default_spin_count; u64 default_spin_count;
i64 seen_broadcast_gen; i64 seen_broadcast_gen;
}; };
typedef void WaveLaneEntryFunc(WaveLaneCtx *lane); typedef void WaveLaneEntryFunc(WaveLaneCtx *lane);
@ -34,14 +34,16 @@ typedef void WaveLaneEntryFunc(WaveLaneCtx *lane);
//~ Wave sync ops //~ Wave sync ops
void WaveSyncEx(WaveLaneCtx *lane, u64 spin_count); void WaveSyncEx(WaveLaneCtx *lane, u64 spin_count);
#define WaveSync(lane) \
WaveSyncEx((lane), (lane)->default_spin_count)
void WaveSyncBroadcastEx_(WaveLaneCtx *lane, u32 broadcast_lane_idx, void *broadcast_ptr, u64 broadcast_size, u64 spin_count); void WaveSyncBroadcastEx_(WaveLaneCtx *lane, u32 broadcast_lane_idx, void *broadcast_ptr, u64 broadcast_size, u64 spin_count);
#define WaveSync(lane) \
WaveSyncEx((lane), (lane)->default_spin_count)
#define WaveSyncBroadcastEx(lane, broadcast_lane_idx, broadcast_ptr, spin_count) \ #define WaveSyncBroadcastEx(lane, broadcast_lane_idx, broadcast_ptr, spin_count) \
WaveSyncBroadcastEx_((lane), (broadcast_lane_idx), (broadcast_ptr), sizeof(*(broadcast_ptr)), (spin_count)) WaveSyncBroadcastEx_((lane), (broadcast_lane_idx), (broadcast_ptr), sizeof(*(broadcast_ptr)), (spin_count))
#define WaveSyncBroadcast(lane, broadcast_lane_idx, broadcast_ptr) \ #define WaveSyncBroadcast(lane, broadcast_lane_idx, broadcast_ptr) \
WaveSyncBroadcastEx_((lane), (broadcast_lane_idx), (broadcast_ptr), sizeof(*(broadcast_ptr)), (lane)->default_spin_count) WaveSyncBroadcastEx_((lane), (broadcast_lane_idx), (broadcast_ptr), sizeof(*(broadcast_ptr)), (lane)->default_spin_count)
void SetWaveLaneDefaultSpin(WaveLaneCtx *lane, u64 n); void SetWaveLaneDefaultSpin(WaveLaneCtx *lane, u64 n);

View File

@ -5,34 +5,34 @@ W32_Ctx W32 = Zi;
BOOL W32_FindEmbeddedRcData(HMODULE module, LPCWSTR type, LPWSTR wstr_entry_name, LONG_PTR udata) BOOL W32_FindEmbeddedRcData(HMODULE module, LPCWSTR type, LPWSTR wstr_entry_name, LONG_PTR udata)
{ {
W32_FindEmbeddedDataCtx *ctx = (W32_FindEmbeddedDataCtx *)udata; W32_FindEmbeddedDataCtx *ctx = (W32_FindEmbeddedDataCtx *)udata;
TempArena scratch = BeginScratchNoConflict(); TempArena scratch = BeginScratchNoConflict();
String entry_name = StringFromWstrNoLimit(scratch.arena, (LPWSTR)wstr_entry_name); String entry_name = StringFromWstrNoLimit(scratch.arena, (LPWSTR)wstr_entry_name);
String embedded_data_prefix = Lit(Stringize(W32_EmbeddedDataPrefix)); String embedded_data_prefix = Lit(Stringize(W32_EmbeddedDataPrefix));
if (StringBeginsWith(entry_name, embedded_data_prefix)) if (StringBeginsWith(entry_name, embedded_data_prefix))
{
HRSRC hres = FindResourceW(module, wstr_entry_name, type);
if (hres)
{ {
HRSRC hres = FindResourceW(module, wstr_entry_name, type); HGLOBAL hg = LoadResource(module, hres);
if (hres) if (hg)
{
if (ctx->embedded_strings_count < countof(ctx->embedded_strings))
{ {
HGLOBAL hg = LoadResource(module, hres); String embedded = Zi;
if (hg) embedded.len = SizeofResource(module, hres);
{ embedded.text = LockResource(hg);
if (ctx->embedded_strings_count < countof(ctx->embedded_strings)) ctx->embedded_strings[ctx->embedded_strings_count++] = embedded;
{
String embedded = Zi;
embedded.len = SizeofResource(module, hres);
embedded.text = LockResource(hg);
ctx->embedded_strings[ctx->embedded_strings_count++] = embedded;
}
else
{
Panic(Lit("Maximum number of embedded resource entries exceeded"));
}
}
} }
else
{
Panic(Lit("Maximum number of embedded resource entries exceeded"));
}
}
} }
EndScratch(scratch); }
return 1; EndScratch(scratch);
return 1;
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -40,141 +40,141 @@ BOOL W32_FindEmbeddedRcData(HMODULE module, LPCWSTR type, LPWSTR wstr_entry_name
StringList GetRawCommandline(void) StringList GetRawCommandline(void)
{ {
return W32.raw_command_line; return W32.raw_command_line;
} }
void Echo(String msg) void Echo(String msg)
{ {
HANDLE console_handle = GetStdHandle(STD_OUTPUT_HANDLE); HANDLE console_handle = GetStdHandle(STD_OUTPUT_HANDLE);
if (console_handle && console_handle != INVALID_HANDLE_VALUE) if (console_handle && console_handle != INVALID_HANDLE_VALUE)
{ {
WriteFile(console_handle, msg.text, msg.len, 0, 0); WriteFile(console_handle, msg.text, msg.len, 0, 0);
} }
else if (IsRunningInDebugger()) else if (IsRunningInDebugger())
{ {
char msg_cstr[16384]; char msg_cstr[16384];
u64 len = MinU64(countof(msg_cstr) - 1, msg.len); u64 len = MinU64(countof(msg_cstr) - 1, msg.len);
CopyBytes(msg_cstr, msg.text, len); CopyBytes(msg_cstr, msg.text, len);
msg_cstr[len] = 0; msg_cstr[len] = 0;
OutputDebugStringA(msg_cstr); OutputDebugStringA(msg_cstr);
} }
} }
b32 Panic(String msg) b32 Panic(String msg)
{ {
LogPanic(msg); LogPanic(msg);
char msg_cstr[4096]; char msg_cstr[4096];
CstrFromStringToBuff(StringFromFixedArray(msg_cstr), msg); CstrFromStringToBuff(StringFromFixedArray(msg_cstr), msg);
{ {
u32 mb_flags = MB_SETFOREGROUND | MB_ICONERROR; u32 mb_flags = MB_SETFOREGROUND | MB_ICONERROR;
MessageBoxExA(0, msg_cstr, "Fatal error", mb_flags, 0); MessageBoxExA(0, msg_cstr, "Fatal error", mb_flags, 0);
} }
HANDLE console_handle = GetStdHandle(STD_ERROR_HANDLE); HANDLE console_handle = GetStdHandle(STD_ERROR_HANDLE);
if (console_handle != INVALID_HANDLE_VALUE) if (console_handle != INVALID_HANDLE_VALUE)
{ {
WriteFile(console_handle, msg.text, msg.len, 0, 0); WriteFile(console_handle, msg.text, msg.len, 0, 0);
} }
if (IsRunningInDebugger()) if (IsRunningInDebugger())
{ {
Assert(0); Assert(0);
} }
else else
{ {
ExitProcess(1); ExitProcess(1);
} }
return 0; return 0;
} }
b32 IsRunningInDebugger(void) b32 IsRunningInDebugger(void)
{ {
return IsDebuggerPresent(); return IsDebuggerPresent();
} }
i64 TimeNs(void) i64 TimeNs(void)
{ {
LARGE_INTEGER qpc; LARGE_INTEGER qpc;
QueryPerformanceCounter(&qpc); QueryPerformanceCounter(&qpc);
i64 result = (qpc.QuadPart - W32.timer_start_qpc) * W32.ns_per_qpc; i64 result = (qpc.QuadPart - W32.timer_start_qpc) * W32.ns_per_qpc;
return result; return result;
} }
void TrueRand(String buffer) void TrueRand(String buffer)
{ {
BCryptGenRandom(BCRYPT_RNG_ALG_HANDLE, (u8 *)buffer.text, buffer.len, 0); BCryptGenRandom(BCRYPT_RNG_ALG_HANDLE, (u8 *)buffer.text, buffer.len, 0);
} }
CpuTopologyInfo GetCpuTopologyInfo(void) CpuTopologyInfo GetCpuTopologyInfo(void)
{ {
TempArena scratch = BeginScratchNoConflict(); TempArena scratch = BeginScratchNoConflict();
CpuTopologyInfo res = Zi; CpuTopologyInfo res = Zi;
{
DWORD infos_buff_size = 0;
u8 *infos_buff = 0;
b32 ok = 0;
{ {
DWORD infos_buff_size = 0; GetLogicalProcessorInformationEx(RelationProcessorCore, 0, &infos_buff_size);
u8 *infos_buff = 0; infos_buff = PushStructsNoZero(scratch.arena, u8, infos_buff_size);
b32 ok = 0; ok = GetLogicalProcessorInformationEx(RelationProcessorCore, (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)infos_buff, &infos_buff_size);
{
GetLogicalProcessorInformationEx(RelationProcessorCore, 0, &infos_buff_size);
infos_buff = PushStructsNoZero(scratch.arena, u8, infos_buff_size);
ok = GetLogicalProcessorInformationEx(RelationProcessorCore, (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)infos_buff, &infos_buff_size);
}
if (ok)
{
/* Determine max efficiency class */
i32 max_efficiency_class = 0;
{
DWORD pos = 0;
while (pos < infos_buff_size)
{
SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *info = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)&infos_buff[pos];
max_efficiency_class = MaxI32(max_efficiency_class, info->Processor.EfficiencyClass);
pos += info->Size;
}
}
/* Generate physical core info */
{
DWORD pos = 0;
while (pos < infos_buff_size)
{
SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *info = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)&infos_buff[pos];
++res.num_physical_cores;
++res.num_logical_cores;
if (info->Processor.Flags & LTP_PC_SMT)
{
/* Core has SMT sibling */
++res.num_logical_cores;
}
if (info->Processor.EfficiencyClass == max_efficiency_class)
{
/* Core is P-core */
++res.num_physical_performance_cores;
}
else
{
/* Core is not a P-core */
++res.num_physical_non_performance_cores;
}
pos += info->Size;
}
}
}
} }
res.num_logical_cores = MaxI32(res.num_logical_cores, 1); if (ok)
res.num_physical_cores = MaxI32(res.num_physical_cores, 1); {
res.num_physical_performance_cores = MaxI32(res.num_physical_performance_cores, 1); /* Determine max efficiency class */
EndScratch(scratch); i32 max_efficiency_class = 0;
return res; {
DWORD pos = 0;
while (pos < infos_buff_size)
{
SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *info = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)&infos_buff[pos];
max_efficiency_class = MaxI32(max_efficiency_class, info->Processor.EfficiencyClass);
pos += info->Size;
}
}
/* Generate physical core info */
{
DWORD pos = 0;
while (pos < infos_buff_size)
{
SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *info = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)&infos_buff[pos];
++res.num_physical_cores;
++res.num_logical_cores;
if (info->Processor.Flags & LTP_PC_SMT)
{
/* Core has SMT sibling */
++res.num_logical_cores;
}
if (info->Processor.EfficiencyClass == max_efficiency_class)
{
/* Core is P-core */
++res.num_physical_performance_cores;
}
else
{
/* Core is not a P-core */
++res.num_physical_non_performance_cores;
}
pos += info->Size;
}
}
}
}
res.num_logical_cores = MaxI32(res.num_logical_cores, 1);
res.num_physical_cores = MaxI32(res.num_physical_cores, 1);
res.num_physical_performance_cores = MaxI32(res.num_physical_performance_cores, 1);
EndScratch(scratch);
return res;
} }
void SleepSeconds(f64 seconds) void SleepSeconds(f64 seconds)
{ {
f64 ms = seconds * 1000.0; f64 ms = seconds * 1000.0;
if (ms > 4000000000) if (ms > 4000000000)
{ {
Sleep(INFINITE); Sleep(INFINITE);
} }
else else
{ {
Sleep((u32)ms); Sleep((u32)ms);
} }
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -182,60 +182,60 @@ void SleepSeconds(f64 seconds)
b32 IsSwappedIn(void) b32 IsSwappedIn(void)
{ {
return IsHotSwappingEnabled; return IsHotSwappingEnabled;
} }
b32 IsSwappingOut(void) b32 IsSwappingOut(void)
{ {
return IsHotSwappingEnabled; return IsHotSwappingEnabled;
} }
String SwappedStateFromName(Arena *arena, String name) String SwappedStateFromName(Arena *arena, String name)
{ {
TempArena scratch = BeginScratch(arena); TempArena scratch = BeginScratch(arena);
String result = Zi; String result = Zi;
String path = StringF(scratch.arena, "ppswap/%F.swp", FmtString(name)); String path = StringF(scratch.arena, "ppswap/%F.swp", FmtString(name));
wchar_t *path_wstr = WstrFromString(scratch.arena, path); wchar_t *path_wstr = WstrFromString(scratch.arena, path);
HANDLE handle = CreateFileW(path_wstr, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); HANDLE handle = CreateFileW(path_wstr, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if (handle != INVALID_HANDLE_VALUE) if (handle != INVALID_HANDLE_VALUE)
{
u32 chunk_size = Kibi(64);
result.text = ArenaNext(arena, u8);
for (;;)
{ {
u32 chunk_size = Kibi(64); u8 *chunk = PushStructsNoZero(arena, u8, chunk_size);
result.text = ArenaNext(arena, u8); u32 chunk_bytes_read = 0;
for (;;) ReadFile(handle, chunk, chunk_size, (LPDWORD)&chunk_bytes_read, 0);
{ result.len += chunk_bytes_read;
u8 *chunk = PushStructsNoZero(arena, u8, chunk_size); if (chunk_bytes_read < chunk_size)
u32 chunk_bytes_read = 0; {
ReadFile(handle, chunk, chunk_size, (LPDWORD)&chunk_bytes_read, 0); PopStructsNoCopy(arena, u8, chunk_size - chunk_bytes_read);
result.len += chunk_bytes_read; break;
if (chunk_bytes_read < chunk_size) }
{
PopStructsNoCopy(arena, u8, chunk_size - chunk_bytes_read);
break;
}
}
} }
CloseHandle(handle); }
EndScratch(scratch); CloseHandle(handle);
return result; EndScratch(scratch);
return result;
} }
void WriteSwappedState(String name, String data) void WriteSwappedState(String name, String data)
{ {
TempArena scratch = BeginScratchNoConflict(); TempArena scratch = BeginScratchNoConflict();
/* TODO: Use directory non-relative to executable */ /* TODO: Use directory non-relative to executable */
CreateDirectoryW(L"ppswap", 0); CreateDirectoryW(L"ppswap", 0);
String result = Zi; String result = Zi;
String path = StringF(scratch.arena, "ppswap/%F.swp", FmtString(name)); String path = StringF(scratch.arena, "ppswap/%F.swp", FmtString(name));
wchar_t *path_wstr = WstrFromString(scratch.arena, path); wchar_t *path_wstr = WstrFromString(scratch.arena, path);
HANDLE handle = CreateFileW(path_wstr, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, 0, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); HANDLE handle = CreateFileW(path_wstr, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, 0, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
if (handle != INVALID_HANDLE_VALUE) if (handle != INVALID_HANDLE_VALUE)
{ {
SetFilePointer(handle, 0, 0, FILE_BEGIN); SetFilePointer(handle, 0, 0, FILE_BEGIN);
SetEndOfFile(handle); SetEndOfFile(handle);
WriteFile(handle, data.text, data.len, 0, 0); WriteFile(handle, data.text, data.len, 0, 0);
} }
CloseHandle(handle); CloseHandle(handle);
EndScratch(scratch); EndScratch(scratch);
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -243,23 +243,23 @@ void WriteSwappedState(String name, String data)
void OnExit(ExitFunc *func) void OnExit(ExitFunc *func)
{ {
i32 index = Atomic32FetchAdd(&W32.num_exit_funcs, 1); i32 index = Atomic32FetchAdd(&W32.num_exit_funcs, 1);
if (index >= countof(W32.exit_funcs)) if (index >= countof(W32.exit_funcs))
{ {
Panic(Lit("Maximum on exit functions registered")); Panic(Lit("Maximum on exit functions registered"));
} }
W32.exit_funcs[index] = func; W32.exit_funcs[index] = func;
} }
void SignalExit(i32 code) void SignalExit(i32 code)
{ {
Atomic32Set(&W32.exit_code, code); Atomic32Set(&W32.exit_code, code);
SetEvent(W32.exit_event); SetEvent(W32.exit_event);
} }
void ExitNow(i32 code) void ExitNow(i32 code)
{ {
ExitProcess(code); ExitProcess(code);
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -267,88 +267,88 @@ void ExitNow(i32 code)
void W32_BootstrapLogs(String logfile_path) void W32_BootstrapLogs(String logfile_path)
{ {
W32.logs_arena = AcquireArena(Gibi(64)); W32.logs_arena = AcquireArena(Gibi(64));
W32.log_msgs_arena = AcquireArena(Gibi(64)); W32.log_msgs_arena = AcquireArena(Gibi(64));
W32.readable_log_events = ArenaNext(W32.logs_arena, LogEvent); W32.readable_log_events = ArenaNext(W32.logs_arena, LogEvent);
if (logfile_path.len > 0) if (logfile_path.len > 0)
{
TempArena scratch = BeginScratchNoConflict();
{ {
TempArena scratch = BeginScratchNoConflict(); wchar_t *path_wstr = WstrFromString(scratch.arena, logfile_path);
{ W32.logfile = CreateFileW(
wchar_t *path_wstr = WstrFromString(scratch.arena, logfile_path); path_wstr,
W32.logfile = CreateFileW( FILE_APPEND_DATA,
path_wstr, FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_APPEND_DATA, 0,
FILE_SHARE_READ | FILE_SHARE_WRITE, CREATE_ALWAYS,
0, FILE_ATTRIBUTE_NORMAL,
CREATE_ALWAYS, 0
FILE_ATTRIBUTE_NORMAL, );
0
);
}
EndScratch(scratch);
} }
Atomic32Set(&W32.logs_initialized, 1); EndScratch(scratch);
}
Atomic32Set(&W32.logs_initialized, 1);
} }
void W32_Log(i32 level, String msg) void W32_Log(i32 level, String msg)
{ {
TempArena scratch = BeginScratchNoConflict(); TempArena scratch = BeginScratchNoConflict();
if (Atomic32Fetch(&W32.logs_initialized)) if (Atomic32Fetch(&W32.logs_initialized))
{
LogLevelSettings settings = log_settings[level];
if (level < 0 || level >= LogLevel_Count)
{ {
LogLevelSettings settings = log_settings[level]; Panic(Lit("Invalid log level"));
if (level < 0 || level >= LogLevel_Count)
{
Panic(Lit("Invalid log level"));
}
DateTime datetime = LocalDateTime();
i64 now_ns = TimeNs();
i32 thread_id = GetCurrentThreadId();
//- Log message to file
/* TODO: Log asynchronously */
{
String shorthand = settings.shorthand;
String msg_formatted = StringF(
scratch.arena,
"[%F:%F:%F.%F] <%F> [%F] %F\n",
/* Time */
FmtUint(datetime.hour, .z = 2),
FmtUint(datetime.minute, .z = 2),
FmtUint(datetime.second, .z = 2),
FmtUint(datetime.milliseconds, .z = 3),
/* Thread id */
FmtUint(thread_id, .z = 5),
/* Level */
FmtString(shorthand),
/* Message */
FmtString(msg)
);
WriteFile(W32.logfile, msg_formatted.text, msg_formatted.len, 0, 0);
}
//- Log message to queue
/* TODO: Log asynchronously */
LockTicketMutex(&W32.logs_tm);
{
/* Get staged data */
LogEvent *ev = PushStruct(W32.logs_arena, LogEvent);
ev->msg = PushString(W32.log_msgs_arena, msg);
ev->datetime = datetime;
ev->time_ns = now_ns;
ev->level = level;
ev->thread_id = thread_id;
ev->id = W32.logs_count++;
ev->level_id = W32.log_level_counts[level]++;
Atomic64Set(&W32.readable_logs_count, W32.logs_count);
}
UnlockTicketMutex(&W32.logs_tm);
} }
EndScratch(scratch);
DateTime datetime = LocalDateTime();
i64 now_ns = TimeNs();
i32 thread_id = GetCurrentThreadId();
//- Log message to file
/* TODO: Log asynchronously */
{
String shorthand = settings.shorthand;
String msg_formatted = StringF(
scratch.arena,
"[%F:%F:%F.%F] <%F> [%F] %F\n",
/* Time */
FmtUint(datetime.hour, .z = 2),
FmtUint(datetime.minute, .z = 2),
FmtUint(datetime.second, .z = 2),
FmtUint(datetime.milliseconds, .z = 3),
/* Thread id */
FmtUint(thread_id, .z = 5),
/* Level */
FmtString(shorthand),
/* Message */
FmtString(msg)
);
WriteFile(W32.logfile, msg_formatted.text, msg_formatted.len, 0, 0);
}
//- Log message to queue
/* TODO: Log asynchronously */
LockTicketMutex(&W32.logs_tm);
{
/* Get staged data */
LogEvent *ev = PushStruct(W32.logs_arena, LogEvent);
ev->msg = PushString(W32.log_msgs_arena, msg);
ev->datetime = datetime;
ev->time_ns = now_ns;
ev->level = level;
ev->thread_id = thread_id;
ev->id = W32.logs_count++;
ev->level_id = W32.log_level_counts[level]++;
Atomic64Set(&W32.readable_logs_count, W32.logs_count);
}
UnlockTicketMutex(&W32.logs_tm);
}
EndScratch(scratch);
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -358,46 +358,46 @@ void W32_Log(i32 level, String msg)
* immediately writing to log file. */ * immediately writing to log file. */
void LogPanic(String msg) void LogPanic(String msg)
{ {
if (Atomic32Fetch(&W32.logs_initialized)) if (Atomic32Fetch(&W32.logs_initialized))
{ {
String beg = Lit("******** PANICKING ********\n"); String beg = Lit("******** PANICKING ********\n");
String end = Lit("\n***************************\n"); String end = Lit("\n***************************\n");
WriteFile(W32.logfile, beg.text, beg.len, 0, 0); WriteFile(W32.logfile, beg.text, beg.len, 0, 0);
WriteFile(W32.logfile, msg.text, msg.len, 0, 0); WriteFile(W32.logfile, msg.text, msg.len, 0, 0);
WriteFile(W32.logfile, end.text, end.len, 0, 0); WriteFile(W32.logfile, end.text, end.len, 0, 0);
} }
} }
void Log_(i32 level, String msg) void Log_(i32 level, String msg)
{ {
W32_Log(level, msg); W32_Log(level, msg);
} }
void LogF_(i32 level, String fmt, ...) void LogF_(i32 level, String fmt, ...)
{ {
if (Atomic32Fetch(&W32.logs_initialized)) if (Atomic32Fetch(&W32.logs_initialized))
{
TempArena scratch = BeginScratchNoConflict();
va_list args;
va_start(args, fmt);
{ {
TempArena scratch = BeginScratchNoConflict(); String msg = FormatString(scratch.arena, fmt, FmtArgsFromVaList(scratch.arena, args));
va_list args; W32_Log(level, msg);
va_start(args, fmt);
{
String msg = FormatString(scratch.arena, fmt, FmtArgsFromVaList(scratch.arena, args));
W32_Log(level, msg);
}
va_end(args);
EndScratch(scratch);
} }
va_end(args);
EndScratch(scratch);
}
} }
LogEventsArray GetLogEvents(void) LogEventsArray GetLogEvents(void)
{ {
LogEventsArray result = Zi; LogEventsArray result = Zi;
result.count = Atomic64Fetch(&W32.readable_logs_count); result.count = Atomic64Fetch(&W32.readable_logs_count);
if (result.count > 0) if (result.count > 0)
{ {
result.logs = W32.readable_log_events; result.logs = W32.readable_log_events;
} }
return result; return result;
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -405,150 +405,148 @@ LogEventsArray GetLogEvents(void)
i32 W32_Main(void) i32 W32_Main(void)
{ {
/* Init time */ /* Init time */
{
LARGE_INTEGER qpf;
QueryPerformanceFrequency(&qpf);
W32.ns_per_qpc = 1000000000 / qpf.QuadPart;
}
{
LARGE_INTEGER qpc;
QueryPerformanceCounter(&qpc);
W32.timer_start_qpc = qpc.QuadPart;
}
/* Setup events */
W32.panic_event = CreateEventW(0, 1, 0, 0);
W32.exit_event = CreateEventW(0, 1, 0, 0);
W32.main_thread_id = GetCurrentThreadId();
SetThreadDescription(GetCurrentThread(), L"Main thread");
/* Query system info */
GetSystemInfo(&W32.info);
/* Init main thread */
W32_InitCurrentThread(Lit("Main"));
/* Get raw args from command line */
{
Arena *perm = PermArena();
StringList args_list = Zi;
{ {
LARGE_INTEGER qpf; LPCWSTR cmdline_wstr = GetCommandLineW();
QueryPerformanceFrequency(&qpf); i32 argc = 0;
W32.ns_per_qpc = 1000000000 / qpf.QuadPart; LPWSTR *argv = CommandLineToArgvW(cmdline_wstr, &argc);
for (i32 i = 0; i < argc; ++i)
{
wchar_t *arg_wstr = argv[i];
String arg = StringFromWstrNoLimit(perm, arg_wstr);
PushStringToList(perm, &args_list, arg);
}
} }
W32.raw_command_line = args_list;
}
//////////////////////////////
//- Bootstrap
/* Bootstrap command line */
BootstrapCmdline();
/* Bootstrap log system */
/* FIXME: Remove hardcoded log path */
W32_BootstrapLogs(Lit("log.log"));
LogInfoF("Main thread ID: %F", FmtUint(ThreadId()));
/* Bootstrap resource system */
{
W32_FindEmbeddedDataCtx ctx = Zi;
EnumResourceNamesW(0, RT_RCDATA, &W32_FindEmbeddedRcData, (LONG_PTR)&ctx);
BootstrapResources(ctx.embedded_strings_count, ctx.embedded_strings);
}
/* Bootstrap async */
BootstrapAsync();
/* Bootstrap layers */
if (!Atomic32Fetch(&W32.panicking))
{
BootstrapLayers();
}
//////////////////////////////
//- Wait for exit signal
/* Wait for exit start or panic */
if (!Atomic32Fetch(&W32.panicking))
{
HANDLE handles[] = {
W32.exit_event,
W32.panic_event,
};
DWORD wake = WaitForMultipleObjects(countof(handles), handles, 0, INFINITE);
}
//////////////////////////////
//- Shutdown
/* Run exit callbacks */
if (!Atomic32Fetch(&W32.panicking))
{
i32 num_funcs = Atomic32Fetch(&W32.num_exit_funcs);
for (i32 idx = num_funcs - 1; idx >= 0; --idx)
{ {
LARGE_INTEGER qpc; ExitFunc *func = W32.exit_funcs[idx];
QueryPerformanceCounter(&qpc); func();
W32.timer_start_qpc = qpc.QuadPart;
} }
}
/* Setup events */ /* Exit */
W32.panic_event = CreateEventW(0, 1, 0, 0); if (Atomic32Fetch(&W32.panicking))
W32.exit_event = CreateEventW(0, 1, 0, 0); {
WaitForSingleObject(W32.panic_event, INFINITE);
W32.main_thread_id = GetCurrentThreadId(); MessageBoxExW(0, W32.panic_wstr, L"Fatal error", MB_ICONSTOP | MB_SETFOREGROUND | MB_TOPMOST, 0);
SetThreadDescription(GetCurrentThread(), L"Main thread"); Atomic32FetchTestSet(&W32.exit_code, 0, 1);
}
/* Query system info */ return Atomic32Fetch(&W32.exit_code);
GetSystemInfo(&W32.info);
/* Init main thread */
W32_InitCurrentThread(Lit("Main"));
/* Get raw args from command line */
{
Arena *perm = PermArena();
StringList args_list = Zi;
{
LPCWSTR cmdline_wstr = GetCommandLineW();
i32 argc = 0;
LPWSTR *argv = CommandLineToArgvW(cmdline_wstr, &argc);
for (i32 i = 0; i < argc; ++i)
{
wchar_t *arg_wstr = argv[i];
String arg = StringFromWstrNoLimit(perm, arg_wstr);
PushStringToList(perm, &args_list, arg);
}
}
W32.raw_command_line = args_list;
}
//////////////////////////////
//- Bootstrap
/* Bootstrap command line */
BootstrapCmdline();
/* Bootstrap log system */
/* FIXME: Remove hardcoded log path */
W32_BootstrapLogs(Lit("log.log"));
LogInfoF("Main thread ID: %F", FmtUint(ThreadId()));
/* Bootstrap resource system */
{
W32_FindEmbeddedDataCtx ctx = Zi;
EnumResourceNamesW(0, RT_RCDATA, &W32_FindEmbeddedRcData, (LONG_PTR)&ctx);
BootstrapResources(ctx.embedded_strings_count, ctx.embedded_strings);
}
/* Bootstrap async */
BootstrapAsync();
/* Bootstrap layers */
if (!Atomic32Fetch(&W32.panicking))
{
BootstrapLayers();
}
//////////////////////////////
//- Wait for exit signal
/* Wait for exit start or panic */
if (!Atomic32Fetch(&W32.panicking))
{
HANDLE handles[] = {
W32.exit_event,
W32.panic_event,
};
DWORD wake = WaitForMultipleObjects(countof(handles), handles, 0, INFINITE);
}
//////////////////////////////
//- Shutdown
/* Run exit callbacks */
if (!Atomic32Fetch(&W32.panicking))
{
i32 num_funcs = Atomic32Fetch(&W32.num_exit_funcs);
for (i32 idx = num_funcs - 1; idx >= 0; --idx)
{
ExitFunc *func = W32.exit_funcs[idx];
func();
}
}
/* Exit */
if (Atomic32Fetch(&W32.panicking))
{
WaitForSingleObject(W32.panic_event, INFINITE);
MessageBoxExW(0, W32.panic_wstr, L"Fatal error", MB_ICONSTOP | MB_SETFOREGROUND | MB_TOPMOST, 0);
Atomic32FetchTestSet(&W32.exit_code, 0, 1);
}
return Atomic32Fetch(&W32.exit_code);
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Crt main //~ Crt main
#if IsCrtlibEnabled #if IsCrtlibEnabled
# if IsConsoleApp #if IsConsoleApp
int main(char **argc, int argv) int main(char **argc, int argv)
{ {
return W32_Main(); return W32_Main();
} }
# else #else
int CALLBACK wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev_instance, _In_ LPWSTR cmdline_wstr, _In_ int show_code) int CALLBACK wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev_instance, _In_ LPWSTR cmdline_wstr, _In_ int show_code)
{ {
return W32_Main(); return W32_Main();
} }
# endif /* IsConsoleApp */ #endif /* IsConsoleApp */
#endif /* IsCrtlibEnabled */ #endif /* IsCrtlibEnabled */
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Crt stub //~ Crt stub
#if !IsCrtlibEnabled #if !IsCrtlibEnabled
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wmissing-variable-declarations"
#pragma clang diagnostic ignored "-Wmissing-prototypes"
#pragma clang diagnostic push /* Enable floating point */
#pragma clang diagnostic ignored "-Wmissing-variable-declarations" __attribute((used))
#pragma clang diagnostic ignored "-Wmissing-prototypes" int _fltused;
/* Enable floating point */ __attribute((used))
__attribute((used)) void __stdcall wWinMainCRTStartup(void)
int _fltused; {
__attribute((used))
void __stdcall wWinMainCRTStartup(void)
{
i32 result = W32_Main(); i32 result = W32_Main();
ExitProcess(result); ExitProcess(result);
} }
#pragma clang diagnostic pop
#pragma clang diagnostic pop
#endif /* !IsCrtlibEnabled */ #endif /* !IsCrtlibEnabled */

View File

@ -7,28 +7,28 @@
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
#define UNICODE #define UNICODE
#pragma warning(push, 0) #pragma warning(push, 0)
#include <Windows.h> #include <Windows.h>
#include <combaseapi.h> #include <combaseapi.h>
#include <dcommon.h> #include <dcommon.h>
#include <initguid.h> #include <initguid.h>
#include <unknwn.h> #include <unknwn.h>
#include <objbase.h> #include <objbase.h>
#include <uuids.h> #include <uuids.h>
#include <Knownfolders.h> #include <Knownfolders.h>
#include <WinSock2.h> #include <WinSock2.h>
#include <TlHelp32.h> #include <TlHelp32.h>
#include <WS2tcpip.h> #include <WS2tcpip.h>
#include <windowsx.h> #include <windowsx.h>
#include <ShlObj_core.h> #include <ShlObj_core.h>
#include <fileapi.h> #include <fileapi.h>
#include <dwmapi.h> #include <dwmapi.h>
#include <avrt.h> #include <avrt.h>
#include <shellapi.h> #include <shellapi.h>
#pragma warning(pop) #pragma warning(pop)
#ifndef BCRYPT_RNG_ALG_HANDLE #ifndef BCRYPT_RNG_ALG_HANDLE
#define BCRYPT_RNG_ALG_HANDLE ((void *)0x00000081) #define BCRYPT_RNG_ALG_HANDLE ((void *)0x00000081)
u32 BCryptGenRandom(void *algorithm, u8 *buffer, u32 buffer_size, u32 flags); u32 BCryptGenRandom(void *algorithm, u8 *buffer, u32 buffer_size, u32 flags);
#endif #endif
//- Windows libs //- Windows libs
@ -49,8 +49,8 @@ u32 BCryptGenRandom(void *algorithm, u8 *buffer, u32 buffer_size, u32 flags);
Struct(W32_FindEmbeddedDataCtx) Struct(W32_FindEmbeddedDataCtx)
{ {
u64 embedded_strings_count; u64 embedded_strings_count;
String embedded_strings[64]; String embedded_strings[64];
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -58,41 +58,41 @@ Struct(W32_FindEmbeddedDataCtx)
Struct(W32_Ctx) Struct(W32_Ctx)
{ {
SYSTEM_INFO info; SYSTEM_INFO info;
u32 main_thread_id; u32 main_thread_id;
Atomic32 shutdown; Atomic32 shutdown;
Atomic32 exit_code; Atomic32 exit_code;
i64 timer_start_qpc; i64 timer_start_qpc;
i64 ns_per_qpc; i64 ns_per_qpc;
StringList raw_command_line; StringList raw_command_line;
//- Application control flow //- Application control flow
Atomic32 panicking; Atomic32 panicking;
wchar_t panic_wstr[4096]; wchar_t panic_wstr[4096];
HANDLE panic_event; HANDLE panic_event;
HANDLE exit_event; HANDLE exit_event;
//- Exit funcs //- Exit funcs
Atomic32 num_exit_funcs; Atomic32 num_exit_funcs;
ExitFunc *exit_funcs[4096]; ExitFunc *exit_funcs[4096];
//- Logs //- Logs
HANDLE logfile; HANDLE logfile;
Atomic32 logs_initialized; Atomic32 logs_initialized;
TicketMutex logs_tm; TicketMutex logs_tm;
Arena *log_msgs_arena; Arena *log_msgs_arena;
Arena *logs_arena; Arena *logs_arena;
u64 logs_count; u64 logs_count;
u64 log_level_counts[LogLevel_Count]; u64 log_level_counts[LogLevel_Count];
LogEvent *readable_log_events; LogEvent *readable_log_events;
Atomic64 readable_logs_count; Atomic64 readable_logs_count;
}; };
extern W32_Ctx W32; extern W32_Ctx W32;

View File

@ -3,12 +3,12 @@
void FutexYieldNeq(volatile void *addr, void *cmp, u8 cmp_size) void FutexYieldNeq(volatile void *addr, void *cmp, u8 cmp_size)
{ {
WaitOnAddress(addr, cmp, cmp_size, INFINITE); WaitOnAddress(addr, cmp, cmp_size, INFINITE);
} }
void FutexWakeNeq(void *addr) void FutexWakeNeq(void *addr)
{ {
WakeByAddressAll(addr); WakeByAddressAll(addr);
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -16,12 +16,12 @@ void FutexWakeNeq(void *addr)
void FutexYieldGte(volatile void *addr, void *cmp, u8 cmp_size) void FutexYieldGte(volatile void *addr, void *cmp, u8 cmp_size)
{ {
/* TODO: Actually implement this. Just emulating via neq for now. */ /* TODO: Actually implement this. Just emulating via neq for now. */
FutexYieldNeq(addr, cmp, cmp_size); FutexYieldNeq(addr, cmp, cmp_size);
} }
void FutexWakeGte(void *addr) void FutexWakeGte(void *addr)
{ {
/* TODO: Actually implement this. Just emulating via neq for now. */ /* TODO: Actually implement this. Just emulating via neq for now. */
FutexWakeNeq(addr); FutexWakeNeq(addr);
} }

View File

@ -5,38 +5,38 @@
void *ReserveMemory(u64 size) void *ReserveMemory(u64 size)
{ {
void *ptr = VirtualAlloc(0, size, MEM_RESERVE, PAGE_NOACCESS); void *ptr = VirtualAlloc(0, size, MEM_RESERVE, PAGE_NOACCESS);
return ptr; return ptr;
} }
void ReleaseMemory(void *address) void ReleaseMemory(void *address)
{ {
VirtualFree(address, 0, MEM_RELEASE); VirtualFree(address, 0, MEM_RELEASE);
} }
//- Commit //- Commit
void *CommitMemory(void *address, u64 size) void *CommitMemory(void *address, u64 size)
{ {
void *ptr = VirtualAlloc(address, size, MEM_COMMIT, PAGE_READWRITE); void *ptr = VirtualAlloc(address, size, MEM_COMMIT, PAGE_READWRITE);
return ptr; return ptr;
} }
void DecommitMemory(void *address, u64 size) void DecommitMemory(void *address, u64 size)
{ {
VirtualFree(address, size, MEM_DECOMMIT); VirtualFree(address, size, MEM_DECOMMIT);
} }
//- Protect //- Protect
void SetMemoryReadonly(void *address, u64 size) void SetMemoryReadonly(void *address, u64 size)
{ {
DWORD old; DWORD old;
VirtualProtect(address, size, PAGE_READONLY, &old); VirtualProtect(address, size, PAGE_READONLY, &old);
} }
void SetMemoryReadWrite(void *address, u64 size) void SetMemoryReadWrite(void *address, u64 size)
{ {
DWORD old; DWORD old;
VirtualProtect(address, size, PAGE_READWRITE, &old); VirtualProtect(address, size, PAGE_READWRITE, &old);
} }

View File

@ -3,18 +3,18 @@
DateTime LocalDateTime(void) DateTime LocalDateTime(void)
{ {
DateTime result = Zi; DateTime result = Zi;
{ {
SYSTEMTIME lt; SYSTEMTIME lt;
GetLocalTime(&lt); GetLocalTime(&lt);
result.year = lt.wYear; result.year = lt.wYear;
result.month = lt.wMonth; result.month = lt.wMonth;
result.day_of_week = lt.wDayOfWeek; result.day_of_week = lt.wDayOfWeek;
result.day = lt.wDay; result.day = lt.wDay;
result.hour = lt.wHour; result.hour = lt.wHour;
result.minute = lt.wMinute; result.minute = lt.wMinute;
result.second = lt.wSecond; result.second = lt.wSecond;
result.milliseconds = lt.wMilliseconds; result.milliseconds = lt.wMilliseconds;
} }
return result; return result;
} }

View File

@ -3,31 +3,31 @@
void W32_InitCurrentThread(String name) void W32_InitCurrentThread(String name)
{ {
/* Init thread arenas */ /* Init thread arenas */
{
Base_tl.arenas.perm = AcquireArena(Gibi(64));
for (i32 i = 0; i < (i32)countof(Base_tl.arenas.scratch); ++i)
{ {
Base_tl.arenas.perm = AcquireArena(Gibi(64)); Base_tl.arenas.scratch[i] = AcquireArena(Gibi(64));
for (i32 i = 0; i < (i32)countof(Base_tl.arenas.scratch); ++i)
{
Base_tl.arenas.scratch[i] = AcquireArena(Gibi(64));
}
} }
Arena *perm = PermArena(); }
Arena *perm = PermArena();
/* Set thread name */ /* Set thread name */
wchar_t *thread_name_wstr = WstrFromString(perm, name); wchar_t *thread_name_wstr = WstrFromString(perm, name);
SetThreadDescription(GetCurrentThread(), thread_name_wstr); SetThreadDescription(GetCurrentThread(), thread_name_wstr);
/* Initialize COM */ /* Initialize COM */
CoInitializeEx(0, COINIT_MULTITHREADED); CoInitializeEx(0, COINIT_MULTITHREADED);
} }
DWORD WINAPI W32_ThreadProc(LPVOID thread_args_vp) DWORD WINAPI W32_ThreadProc(LPVOID thread_args_vp)
{ {
W32_ThreadArgs *thread_args = (W32_ThreadArgs *)thread_args_vp; W32_ThreadArgs *thread_args = (W32_ThreadArgs *)thread_args_vp;
W32_InitCurrentThread(thread_args->name); W32_InitCurrentThread(thread_args->name);
LogInfoF("New thread \"%F\" created with ID %F", FmtString(thread_args->name), FmtUint(ThreadId())); LogInfoF("New thread \"%F\" created with ID %F", FmtString(thread_args->name), FmtUint(ThreadId()));
thread_args->entry(thread_args->lane); thread_args->entry(thread_args->lane);
return 0; return 0;
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -35,58 +35,58 @@ DWORD WINAPI W32_ThreadProc(LPVOID thread_args_vp)
void DispatchWave(String name, u32 num_lanes, WaveLaneEntryFunc *entry, void *udata) void DispatchWave(String name, u32 num_lanes, WaveLaneEntryFunc *entry, void *udata)
{ {
Arena *perm = PermArena(); Arena *perm = PermArena();
PERSIST Atomic64 num_threads_allocated = Zi; PERSIST Atomic64 num_threads_allocated = Zi;
/* Catch high lane count to prevent OS crash */ /* Catch high lane count to prevent OS crash */
i64 old_num_threads_allocated = Atomic64FetchAdd(&num_threads_allocated, num_lanes); i64 old_num_threads_allocated = Atomic64FetchAdd(&num_threads_allocated, num_lanes);
i64 new_num_threads_allocated = old_num_threads_allocated + num_lanes; i64 new_num_threads_allocated = old_num_threads_allocated + num_lanes;
if (new_num_threads_allocated > MaxThreads) if (new_num_threads_allocated > MaxThreads)
{
if (old_num_threads_allocated < MaxThreads)
{ {
if (old_num_threads_allocated < MaxThreads) Panic(StringF(perm, "Maximum number of threads reached (%F)", FmtUint(MaxThreads)));
{ }
Panic(StringF(perm, "Maximum number of threads reached (%F)", FmtUint(MaxThreads))); else
} {
else /* Sleep until panic */
{ Sleep(INFINITE);
/* Sleep until panic */ }
Sleep(INFINITE); }
}
WaveCtx *wave_ctx = PushStruct(perm, WaveCtx);
wave_ctx->lanes_count = num_lanes;
wave_ctx->udata = udata;
for (u32 lane_idx = 0; lane_idx < num_lanes; ++lane_idx)
{
WaveLaneCtx *lane_ctx = PushStruct(perm, WaveLaneCtx);
lane_ctx->idx = lane_idx;
lane_ctx->wave = wave_ctx;
lane_ctx->default_spin_count = DefaultWaveLaneSpinCount;
String thread_name = Zi;
if (num_lanes > 1)
{
thread_name = StringF(perm, "%F:%F", FmtString(name), FmtUint(lane_idx));
}
else
{
thread_name = PushString(perm, name);
} }
WaveCtx *wave_ctx = PushStruct(perm, WaveCtx); W32_ThreadArgs *thread_args = PushStruct(perm, W32_ThreadArgs);
wave_ctx->lanes_count = num_lanes; thread_args->lane = lane_ctx;
wave_ctx->udata = udata; thread_args->udata = udata;
thread_args->entry = entry;
thread_args->name = thread_name;
for (u32 lane_idx = 0; lane_idx < num_lanes; ++lane_idx) HANDLE handle = CreateThread(0, Mebi(4), W32_ThreadProc, thread_args, 0, 0);
if (!handle)
{ {
WaveLaneCtx *lane_ctx = PushStruct(perm, WaveLaneCtx); Panic(Lit("Failed to create thread"));
lane_ctx->idx = lane_idx;
lane_ctx->wave = wave_ctx;
lane_ctx->default_spin_count = DefaultWaveLaneSpinCount;
String thread_name = Zi;
if (num_lanes > 1)
{
thread_name = StringF(perm, "%F:%F", FmtString(name), FmtUint(lane_idx));
}
else
{
thread_name = PushString(perm, name);
}
W32_ThreadArgs *thread_args = PushStruct(perm, W32_ThreadArgs);
thread_args->lane = lane_ctx;
thread_args->udata = udata;
thread_args->entry = entry;
thread_args->name = thread_name;
HANDLE handle = CreateThread(0, Mebi(4), W32_ThreadProc, thread_args, 0, 0);
if (!handle)
{
Panic(Lit("Failed to create thread"));
}
} }
}
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -94,5 +94,5 @@ void DispatchWave(String name, u32 num_lanes, WaveLaneEntryFunc *entry, void *ud
i32 ThreadId(void) i32 ThreadId(void)
{ {
return GetCurrentThreadId(); return GetCurrentThreadId();
} }

View File

@ -3,10 +3,10 @@
Struct(W32_ThreadArgs) Struct(W32_ThreadArgs)
{ {
void *udata; void *udata;
WaveLaneCtx *lane; WaveLaneCtx *lane;
WaveLaneEntryFunc *entry; WaveLaneEntryFunc *entry;
String name; String name;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////

File diff suppressed because it is too large Load Diff

View File

@ -15,9 +15,9 @@
Struct(CLD_Shape) Struct(CLD_Shape)
{ {
Vec2 points[8]; Vec2 points[8];
u32 count; u32 count;
f32 radius; f32 radius;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -25,27 +25,27 @@ Struct(CLD_Shape)
Struct(CLD_SupportPoint) Struct(CLD_SupportPoint)
{ {
Vec2 p; Vec2 p;
u32 i; /* Index of original point in shape */ u32 i; /* Index of original point in shape */
}; };
Struct(CLD_MenkowskiPoint) Struct(CLD_MenkowskiPoint)
{ {
Vec2 p; /* Menkowski difference point */ Vec2 p; /* Menkowski difference point */
CLD_SupportPoint s0; /* Support point of first shape in dir */ CLD_SupportPoint s0; /* Support point of first shape in dir */
CLD_SupportPoint s1; /* Support point of second shape in -dir */ CLD_SupportPoint s1; /* Support point of second shape in -dir */
}; };
Struct(CLD_MenkowskiSimplex) Struct(CLD_MenkowskiSimplex)
{ {
u32 len; u32 len;
CLD_MenkowskiPoint a, b, c; CLD_MenkowskiPoint a, b, c;
}; };
Struct(CLD_MenkowskiFeature) Struct(CLD_MenkowskiFeature)
{ {
u32 len; u32 len;
CLD_MenkowskiPoint a, b; CLD_MenkowskiPoint a, b;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -53,42 +53,42 @@ Struct(CLD_MenkowskiFeature)
Struct(CLD_CollisionPoint) Struct(CLD_CollisionPoint)
{ {
Vec2 point; Vec2 point;
f32 separation; f32 separation;
u32 id; /* Based on polygon edge-to-edge */ u32 id; /* Based on polygon edge-to-edge */
}; };
Struct(CLD_Prototype) Struct(CLD_Prototype)
{ {
Vec2 points[64]; Vec2 points[64];
u32 len; u32 len;
}; };
Struct(CLD_CollisionData) Struct(CLD_CollisionData)
{ {
Vec2 normal; Vec2 normal;
CLD_CollisionPoint points[2]; CLD_CollisionPoint points[2];
u32 num_points; u32 num_points;
/* For debugging */ /* For debugging */
b32 solved; b32 solved;
CLD_MenkowskiSimplex simplex; CLD_MenkowskiSimplex simplex;
CLD_Prototype prototype; CLD_Prototype prototype;
/* For debugging */ /* For debugging */
Vec2 a0, b0, a1, b1; Vec2 a0, b0, a1, b1;
Vec2 a0_clipped, b0_clipped, a1_clipped, b1_clipped; Vec2 a0_clipped, b0_clipped, a1_clipped, b1_clipped;
}; };
Struct(CLD_ClosestPointData) Struct(CLD_ClosestPointData)
{ {
Vec2 p0, p1; Vec2 p0, p1;
b32 colliding; b32 colliding;
/* For debugging */ /* For debugging */
b32 solved; b32 solved;
CLD_MenkowskiSimplex simplex; CLD_MenkowskiSimplex simplex;
CLD_Prototype prototype; CLD_Prototype prototype;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -96,8 +96,8 @@ Struct(CLD_ClosestPointData)
Struct(CLD_ClippedLine) Struct(CLD_ClippedLine)
{ {
Vec2 a0_clipped, b0_clipped; Vec2 a0_clipped, b0_clipped;
Vec2 a1_clipped, b1_clipped; Vec2 a1_clipped, b1_clipped;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -105,16 +105,16 @@ Struct(CLD_ClippedLine)
Struct(CLD_GjkData) Struct(CLD_GjkData)
{ {
CLD_MenkowskiSimplex simplex; CLD_MenkowskiSimplex simplex;
Vec2 final_dir; Vec2 final_dir;
/* If 1, simplex represents triangle inside of CLD_Menkowski difference /* If 1, simplex represents triangle inside of CLD_Menkowski difference
* encapsulating the origin. If 0, simplex represents the closest * encapsulating the origin. If 0, simplex represents the closest
* feature on CLD_Menkowski difference to the origin. */ * feature on CLD_Menkowski difference to the origin. */
b32 overlapping; b32 overlapping;
#if COLLIDER_DEBUG #if COLLIDER_DEBUG
u32 dbg_step; u32 dbg_step;
#endif #endif
}; };
@ -123,12 +123,12 @@ Struct(CLD_GjkData)
Struct(CLD_EpaData) Struct(CLD_EpaData)
{ {
Vec2 normal; Vec2 normal;
CLD_MenkowskiFeature closest_feature; /* Represents closest feature (edge or point) to origin on CLD_Menkowski difference */ CLD_MenkowskiFeature closest_feature; /* Represents closest feature (edge or point) to origin on CLD_Menkowski difference */
#if COLLIDER_DEBUG #if COLLIDER_DEBUG
CLD_Prototype prototype; CLD_Prototype prototype;
u32 dbg_step; u32 dbg_step;
#endif #endif
}; };
@ -139,17 +139,17 @@ Struct(CLD_EpaData)
void CLD_DebugBreakable(void); void CLD_DebugBreakable(void);
#define CLD_DBGSTEP \ #define CLD_DBGSTEP \
dbg_step++; \ dbg_step++; \
if (dbg_step >= GetGstat(DebugSteps)) \ if (dbg_step >= GetGstat(DebugSteps)) \
{ \ { \
goto abort; \ goto abort; \
} \ } \
else if (dbg_step >= GetGstat(DebugSteps) - 1) \ else if (dbg_step >= GetGstat(DebugSteps) - 1) \
{ \ { \
CLD_DebugBreakable(); \ CLD_DebugBreakable(); \
} (void)0 } (void)0
#else #else
#define CLD_DBGSTEP #define CLD_DBGSTEP
#endif #endif
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////

View File

@ -4,17 +4,17 @@
/* Window title */ /* Window title */
#if IsRtcEnabled #if IsRtcEnabled
# if IsDeveloperModeEnabled #if IsDeveloperModeEnabled
# define WINDOW_TITLE "Debug (Developer Build)" #define WINDOW_TITLE "Debug (Developer Build)"
# else #else
# define WINDOW_TITLE "Debug" #define WINDOW_TITLE "Debug"
# endif #endif
#else #else
# if IsDeveloperModeEnabled #if IsDeveloperModeEnabled
# define WINDOW_TITLE "Power Play (Developer Build)" #define WINDOW_TITLE "Power Play (Developer Build)"
# else #else
# define WINDOW_TITLE "Power Play" #define WINDOW_TITLE "Power Play"
# endif #endif
#endif #endif
#define DEFAULT_CAMERA_WIDTH (16) #define DEFAULT_CAMERA_WIDTH (16)
@ -33,7 +33,7 @@
#define USER_INTERP_RATIO 1.2 #define USER_INTERP_RATIO 1.2
#define USER_INTERP_ENABLED 1 #define USER_INTERP_ENABLED 1
/* 64^2 = 4096 bins */ /* 64^2 = 4096 bins */
#define SPACE_CELL_BINS_SQRT (64) #define SPACE_CELL_BINS_SQRT (64)
#define SPACE_CELL_SIZE (1) #define SPACE_CELL_SIZE (1)
@ -56,11 +56,11 @@
#define SIM_PLAYER_AIM 1 #define SIM_PLAYER_AIM 1
#if 0 #if 0
# define SIM_MAX_LINEAR_VELOCITY 500 #define SIM_MAX_LINEAR_VELOCITY 500
# define SIM_MAX_ANGULAR_VELOCITY (Tau * 20) #define SIM_MAX_ANGULAR_VELOCITY (Tau * 20)
#else #else
# define SIM_MAX_LINEAR_VELOCITY F32Infinity #define SIM_MAX_LINEAR_VELOCITY F32Infinity
# define SIM_MAX_ANGULAR_VELOCITY F32Infinity #define SIM_MAX_ANGULAR_VELOCITY F32Infinity
#endif #endif
#define COLLIDER_DEBUG 0 #define COLLIDER_DEBUG 0

View File

@ -5,9 +5,9 @@ D_SharedState D_shared_state = ZI;
void D_Bootstrap(void) void D_Bootstrap(void)
{ {
D_SharedState *g = &D_shared_state; D_SharedState *g = &D_shared_state;
u32 pixel_white = 0xFFFFFFFF; u32 pixel_white = 0xFFFFFFFF;
g->solid_white_texture = GPU_AcquireTexture(GP_TEXTURE_FORMAT_R8G8B8A8_UNORM, 0, VEC2I32(1, 1), &pixel_white); g->solid_white_texture = GPU_AcquireTexture(GP_TEXTURE_FORMAT_R8G8B8A8_UNORM, 0, VEC2I32(1, 1), &pixel_white);
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -15,15 +15,15 @@ void D_Bootstrap(void)
void D_DrawMaterial(GPU_RenderSig *sig, D_MaterialParams params) void D_DrawMaterial(GPU_RenderSig *sig, D_MaterialParams params)
{ {
GPU_RenderCmdDesc cmd = ZI; GPU_RenderCmdDesc cmd = ZI;
cmd.kind = GP_RENDER_CMD_KIND_DRAW_MATERIAL; cmd.kind = GP_RENDER_CMD_KIND_DRAW_MATERIAL;
cmd.material.xf = params.xf; cmd.material.xf = params.xf;
cmd.material.texture = params.texture; cmd.material.texture = params.texture;
cmd.material.clip = params.clip; cmd.material.clip = params.clip;
cmd.material.tint = params.tint; cmd.material.tint = params.tint;
cmd.material.is_light = params.is_light; cmd.material.is_light = params.is_light;
cmd.material.light_emittance = params.light_emittance; cmd.material.light_emittance = params.light_emittance;
GPU_PushRenderCmd(sig, &cmd); GPU_PushRenderCmd(sig, &cmd);
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -31,75 +31,75 @@ void D_DrawMaterial(GPU_RenderSig *sig, D_MaterialParams params)
void D_DrawPolyEx(GPU_RenderSig *sig, Vec2Array vertices, GPU_Indices indices, u32 color) void D_DrawPolyEx(GPU_RenderSig *sig, Vec2Array vertices, GPU_Indices indices, u32 color)
{ {
GPU_RenderCmdDesc cmd = ZI; GPU_RenderCmdDesc cmd = ZI;
cmd.kind = GP_RENDER_CMD_KIND_DRAW_UI_SHAPE; cmd.kind = GP_RENDER_CMD_KIND_DRAW_UI_SHAPE;
cmd.ui_shape.vertices = vertices; cmd.ui_shape.vertices = vertices;
cmd.ui_shape.indices = indices; cmd.ui_shape.indices = indices;
cmd.ui_shape.color = color; cmd.ui_shape.color = color;
GPU_PushRenderCmd(sig, &cmd); GPU_PushRenderCmd(sig, &cmd);
} }
/* Draws a filled polygon using triangles in a fan pattern */ /* Draws a filled polygon using triangles in a fan pattern */
void D_DrawPoly(GPU_RenderSig *sig, Vec2Array vertices, u32 color) void D_DrawPoly(GPU_RenderSig *sig, Vec2Array vertices, u32 color)
{ {
if (vertices.count >= 3) if (vertices.count >= 3)
{
TempArena scratch = BeginScratchNoConflict();
u32 num_tris = vertices.count - 2;
u32 num_indices = num_tris * 3;
/* Generate indices in a fan pattern */
GPU_Indices indices = ZI;
indices.count = num_indices;
indices.indices = PushStructsNoZero(scratch.arena, u32, num_indices);
for (u32 i = 0; i < num_tris; ++i)
{ {
TempArena scratch = BeginScratchNoConflict(); u32 tri_offset = i * 3;
indices.indices[tri_offset + 0] = 0;
u32 num_tris = vertices.count - 2; indices.indices[tri_offset + 1] = (i + 1);
u32 num_indices = num_tris * 3; indices.indices[tri_offset + 2] = (i + 2);
/* Generate indices in a fan pattern */
GPU_Indices indices = ZI;
indices.count = num_indices;
indices.indices = PushStructsNoZero(scratch.arena, u32, num_indices);
for (u32 i = 0; i < num_tris; ++i)
{
u32 tri_offset = i * 3;
indices.indices[tri_offset + 0] = 0;
indices.indices[tri_offset + 1] = (i + 1);
indices.indices[tri_offset + 2] = (i + 2);
}
D_DrawPolyEx(sig, vertices, indices, color);
EndScratch(scratch);
} }
D_DrawPolyEx(sig, vertices, indices, color);
EndScratch(scratch);
}
} }
void D_DrawCircle(GPU_RenderSig *sig, Vec2 pos, f32 radius, u32 color, u32 detail) void D_DrawCircle(GPU_RenderSig *sig, Vec2 pos, f32 radius, u32 color, u32 detail)
{ {
TempArena scratch = BeginScratchNoConflict(); TempArena scratch = BeginScratchNoConflict();
Vec2 *points = PushStructsNoZero(scratch.arena, Vec2, detail); Vec2 *points = PushStructsNoZero(scratch.arena, Vec2, detail);
for (u32 i = 0; i < detail; ++i) for (u32 i = 0; i < detail; ++i)
{ {
f32 angle = ((f32)i / (f32)detail) * Tau; f32 angle = ((f32)i / (f32)detail) * Tau;
Vec2 p = VEC2( Vec2 p = VEC2(
radius * CosF32(angle), radius * CosF32(angle),
radius * SinF32(angle) radius * SinF32(angle)
); );
points[i] = AddVec2(pos, p); points[i] = AddVec2(pos, p);
} }
Vec2Array vertices = { Vec2Array vertices = {
.points = points, .points = points,
.count = detail .count = detail
}; };
D_DrawPoly(sig, vertices, color); D_DrawPoly(sig, vertices, color);
EndScratch(scratch); EndScratch(scratch);
} }
void D_DrawQuad(GPU_RenderSig *sig, Quad quad, u32 color) void D_DrawQuad(GPU_RenderSig *sig, Quad quad, u32 color)
{ {
PERSIST const u32 indices_array[6] = { PERSIST const u32 indices_array[6] = {
0, 1, 2, 0, 1, 2,
0, 2, 3 0, 2, 3
}; };
Vec2Array vertices = { .count = 4, .points = quad.e }; Vec2Array vertices = { .count = 4, .points = quad.e };
GPU_Indices indices = { .count = 6, .indices = indices_array }; GPU_Indices indices = { .count = 6, .indices = indices_array };
D_DrawPolyEx(sig, vertices, indices, color); D_DrawPolyEx(sig, vertices, indices, color);
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -108,144 +108,144 @@ void D_DrawQuad(GPU_RenderSig *sig, Quad quad, u32 color)
void D_DrawLineGradient(GPU_RenderSig *sig, Vec2 start, Vec2 end, f32 thickness, u32 start_color, u32 end_color) void D_DrawLineGradient(GPU_RenderSig *sig, Vec2 start, Vec2 end, f32 thickness, u32 start_color, u32 end_color)
{ {
#if 0 #if 0
D_SharedState *g = &D_shared_state; D_SharedState *g = &D_shared_state;
Quad quad = QuadFromLine(start, end, thickness); Quad quad = QuadFromLine(start, end, thickness);
D_DrawMaterial(sig, D_MATERIALPARAMS(.texture = g->solid_white_texture, .tint0 = start_color, .tint1 = end_color, .quad = quad)); D_DrawMaterial(sig, D_MATERIALPARAMS(.texture = g->solid_white_texture, .tint0 = start_color, .tint1 = end_color, .quad = quad));
#else #else
/* Placeholder */ /* Placeholder */
Quad quad = QuadFromLine(start, end, thickness); Quad quad = QuadFromLine(start, end, thickness);
D_DrawQuad(sig, quad, start_color); D_DrawQuad(sig, quad, start_color);
#endif #endif
} }
void D_DrawLine(GPU_RenderSig *sig, Vec2 start, Vec2 end, f32 thickness, u32 color) void D_DrawLine(GPU_RenderSig *sig, Vec2 start, Vec2 end, f32 thickness, u32 color)
{ {
Quad quad = QuadFromLine(start, end, thickness); Quad quad = QuadFromLine(start, end, thickness);
D_DrawQuad(sig, quad, color); D_DrawQuad(sig, quad, color);
} }
void D_DrawRay(GPU_RenderSig *sig, Vec2 pos, Vec2 rel, f32 thickness, u32 color) void D_DrawRay(GPU_RenderSig *sig, Vec2 pos, Vec2 rel, f32 thickness, u32 color)
{ {
Quad quad = QuadFromRay(pos, rel, thickness); Quad quad = QuadFromRay(pos, rel, thickness);
D_DrawQuad(sig, quad, color); D_DrawQuad(sig, quad, color);
} }
void D_DrawPolyLine(GPU_RenderSig *sig, Vec2Array points, b32 loop, f32 thickness, u32 color) void D_DrawPolyLine(GPU_RenderSig *sig, Vec2Array points, b32 loop, f32 thickness, u32 color)
{ {
if (points.count >= 2) if (points.count >= 2)
{
for (u64 i = 1; i < points.count; ++i)
{ {
for (u64 i = 1; i < points.count; ++i) Vec2 p1 = points.points[i - 1];
{ Vec2 p2 = points.points[i];
Vec2 p1 = points.points[i - 1]; Quad q = QuadFromLine(p1, p2, thickness);
Vec2 p2 = points.points[i]; D_DrawQuad(sig, q, color);
Quad q = QuadFromLine(p1, p2, thickness);
D_DrawQuad(sig, q, color);
}
if (loop && points.count > 2)
{
Vec2 p1 = points.points[points.count - 1];
Vec2 p2 = points.points[0];
Quad q = QuadFromLine(p1, p2, thickness);
D_DrawQuad(sig, q, color);
}
} }
if (loop && points.count > 2)
{
Vec2 p1 = points.points[points.count - 1];
Vec2 p2 = points.points[0];
Quad q = QuadFromLine(p1, p2, thickness);
D_DrawQuad(sig, q, color);
}
}
} }
void D_DrawCircleLine(GPU_RenderSig *sig, Vec2 pos, f32 radius, f32 thickness, u32 color, u32 detail) void D_DrawCircleLine(GPU_RenderSig *sig, Vec2 pos, f32 radius, f32 thickness, u32 color, u32 detail)
{ {
TempArena scratch = BeginScratchNoConflict(); TempArena scratch = BeginScratchNoConflict();
Vec2 *points = PushStructsNoZero(scratch.arena, Vec2, detail); Vec2 *points = PushStructsNoZero(scratch.arena, Vec2, detail);
for (u32 i = 0; i < detail; ++i) for (u32 i = 0; i < detail; ++i)
{ {
f32 angle = ((f32)i / (f32)detail) * Tau; f32 angle = ((f32)i / (f32)detail) * Tau;
Vec2 p = VEC2( Vec2 p = VEC2(
radius * CosF32(angle), radius * CosF32(angle),
radius * SinF32(angle) radius * SinF32(angle)
); );
points[i] = AddVec2(pos, p); points[i] = AddVec2(pos, p);
} }
Vec2Array a = { Vec2Array a = {
.points = points, .points = points,
.count = detail .count = detail
}; };
D_DrawPolyLine(sig, a, 1, thickness, color); D_DrawPolyLine(sig, a, 1, thickness, color);
EndScratch(scratch); EndScratch(scratch);
} }
void D_DrawQuadLine(GPU_RenderSig *sig, Quad quad, f32 thickness, u32 color) void D_DrawQuadLine(GPU_RenderSig *sig, Quad quad, f32 thickness, u32 color)
{ {
Vec2 points[] = { quad.p0, quad.p1, quad.p2, quad.p3 }; Vec2 points[] = { quad.p0, quad.p1, quad.p2, quad.p3 };
Vec2Array a = { .points = points, .count = countof(points) }; Vec2Array a = { .points = points, .count = countof(points) };
D_DrawPolyLine(sig, a, 1, thickness, color); D_DrawPolyLine(sig, a, 1, thickness, color);
} }
void D_DrawArrowLine(GPU_RenderSig *sig, Vec2 start, Vec2 end, f32 thickness, f32 arrowhead_height, u32 color) void D_DrawArrowLine(GPU_RenderSig *sig, Vec2 start, Vec2 end, f32 thickness, f32 arrowhead_height, u32 color)
{ {
const f32 head_width_ratio = 0.5f; /* Width of arrowhead relative to its length */ const f32 head_width_ratio = 0.5f; /* Width of arrowhead relative to its length */
const f32 max_height_to_line_ratio = 0.9f; /* Maximum length of arrowhead relative to total line length */ const f32 max_height_to_line_ratio = 0.9f; /* Maximum length of arrowhead relative to total line length */
arrowhead_height = MinF32(arrowhead_height, Vec2Len(SubVec2(end, start)) * max_height_to_line_ratio); arrowhead_height = MinF32(arrowhead_height, Vec2Len(SubVec2(end, start)) * max_height_to_line_ratio);
Vec2 head_start_dir = SubVec2(start, end); Vec2 head_start_dir = SubVec2(start, end);
head_start_dir = NormVec2(head_start_dir); head_start_dir = NormVec2(head_start_dir);
head_start_dir = MulVec2(head_start_dir, arrowhead_height); head_start_dir = MulVec2(head_start_dir, arrowhead_height);
Vec2 head_start = AddVec2(end, head_start_dir); Vec2 head_start = AddVec2(end, head_start_dir);
Vec2 head_p1_dir = MulPerpVec2(head_start_dir, head_width_ratio); Vec2 head_p1_dir = MulPerpVec2(head_start_dir, head_width_ratio);
Vec2 head_p2_dir = NegVec2(head_p1_dir); Vec2 head_p2_dir = NegVec2(head_p1_dir);
Vec2 head_p1 = AddVec2(head_start, head_p1_dir); Vec2 head_p1 = AddVec2(head_start, head_p1_dir);
Vec2 head_p2 = AddVec2(head_start, head_p2_dir); Vec2 head_p2 = AddVec2(head_start, head_p2_dir);
Vec2 head_points[] = { end, head_p1, head_p2 }; Vec2 head_points[] = { end, head_p1, head_p2 };
Vec2Array head_points_v2_array = { Vec2Array head_points_v2_array = {
.points = head_points, .points = head_points,
.count = countof(head_points) .count = countof(head_points)
}; };
D_DrawPoly(sig, head_points_v2_array, color); D_DrawPoly(sig, head_points_v2_array, color);
Quad line_quad = QuadFromLine(start, head_start, thickness); Quad line_quad = QuadFromLine(start, head_start, thickness);
D_DrawQuad(sig, line_quad, color); D_DrawQuad(sig, line_quad, color);
} }
void D_DrawArrowRay(GPU_RenderSig *sig, Vec2 pos, Vec2 rel, f32 thickness, f32 arrowhead_height, u32 color) void D_DrawArrowRay(GPU_RenderSig *sig, Vec2 pos, Vec2 rel, f32 thickness, f32 arrowhead_height, u32 color)
{ {
Vec2 end = AddVec2(pos, rel); Vec2 end = AddVec2(pos, rel);
D_DrawArrowLine(sig, pos, end, thickness, arrowhead_height, color); D_DrawArrowLine(sig, pos, end, thickness, arrowhead_height, color);
} }
void D_DrawColliderLine(GPU_RenderSig *sig, CLD_Shape shape, Xform shape_xf, f32 thickness, u32 color, u32 detail) void D_DrawColliderLine(GPU_RenderSig *sig, CLD_Shape shape, Xform shape_xf, f32 thickness, u32 color, u32 detail)
{ {
TempArena scratch = BeginScratchNoConflict(); TempArena scratch = BeginScratchNoConflict();
Vec2Array poly = ZI; Vec2Array poly = ZI;
if (shape.radius == 0) if (shape.radius == 0)
{
poly.count = shape.count;
poly.points = PushStructsNoZero(scratch.arena, Vec2, shape.count);
for (u32 i = 0; i < shape.count; ++i)
{ {
poly.count = shape.count; Vec2 p = MulXformV2(shape_xf, shape.points[i]);
poly.points = PushStructsNoZero(scratch.arena, Vec2, shape.count); poly.points[i] = p;
for (u32 i = 0; i < shape.count; ++i)
{
Vec2 p = MulXformV2(shape_xf, shape.points[i]);
poly.points[i] = p;
}
} }
else }
else
{
poly.count = detail;
poly.points = PushStructsNoZero(scratch.arena, Vec2, detail);
for (u32 i = 0; i < detail; ++i)
{ {
poly.count = detail; f32 angle = ((f32)i / (f32)detail) * Tau;
poly.points = PushStructsNoZero(scratch.arena, Vec2, detail); Vec2 dir = VEC2(CosF32(angle), SinF32(angle));
for (u32 i = 0; i < detail; ++i) Vec2 p = CLD_SupportPointFromDir(&shape, shape_xf, dir).p;
{ poly.points[i] = p;
f32 angle = ((f32)i / (f32)detail) * Tau;
Vec2 dir = VEC2(CosF32(angle), SinF32(angle));
Vec2 p = CLD_SupportPointFromDir(&shape, shape_xf, dir).p;
poly.points[i] = p;
}
} }
D_DrawPolyLine(sig, poly, 1, thickness, color); }
EndScratch(scratch); D_DrawPolyLine(sig, poly, 1, thickness, color);
EndScratch(scratch);
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -253,27 +253,27 @@ void D_DrawColliderLine(GPU_RenderSig *sig, CLD_Shape shape, Xform shape_xf, f32
void D_DrawGrid(GPU_RenderSig *sig, Xform xf, u32 bg0_color, u32 bg1_color, u32 line_color, u32 x_color, u32 y_color, f32 thickness, f32 spacing, Vec2 offset) void D_DrawGrid(GPU_RenderSig *sig, Xform xf, u32 bg0_color, u32 bg1_color, u32 line_color, u32 x_color, u32 y_color, f32 thickness, f32 spacing, Vec2 offset)
{ {
i32 grid_id = 0; i32 grid_id = 0;
{ {
GPU_RenderCmdDesc cmd = ZI;
cmd.kind = GP_RENDER_CMD_KIND_PUSH_GRID;
cmd.grid.bg0_color = bg0_color;
cmd.grid.bg1_color = bg1_color;
cmd.grid.line_color = line_color;
cmd.grid.x_color = x_color;
cmd.grid.y_color = y_color;
cmd.grid.line_thickness = thickness;
cmd.grid.line_spacing = spacing;
cmd.grid.offset = offset;
grid_id = GPU_PushRenderCmd(sig, &cmd);
}
GPU_RenderCmdDesc cmd = ZI; GPU_RenderCmdDesc cmd = ZI;
cmd.kind = GP_RENDER_CMD_KIND_DRAW_MATERIAL; cmd.kind = GP_RENDER_CMD_KIND_PUSH_GRID;
cmd.material.xf = xf; cmd.grid.bg0_color = bg0_color;
cmd.material.tint = Color_White; cmd.grid.bg1_color = bg1_color;
cmd.material.grid_cmd_id = grid_id; cmd.grid.line_color = line_color;
GPU_PushRenderCmd(sig, &cmd); cmd.grid.x_color = x_color;
cmd.grid.y_color = y_color;
cmd.grid.line_thickness = thickness;
cmd.grid.line_spacing = spacing;
cmd.grid.offset = offset;
grid_id = GPU_PushRenderCmd(sig, &cmd);
}
GPU_RenderCmdDesc cmd = ZI;
cmd.kind = GP_RENDER_CMD_KIND_DRAW_MATERIAL;
cmd.material.xf = xf;
cmd.material.tint = Color_White;
cmd.material.grid_cmd_id = grid_id;
GPU_PushRenderCmd(sig, &cmd);
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -281,190 +281,190 @@ void D_DrawGrid(GPU_RenderSig *sig, Xform xf, u32 bg0_color, u32 bg1_color, u32
void D_DrawUiRect(GPU_RenderSig *sig, D_UiRectParams params) void D_DrawUiRect(GPU_RenderSig *sig, D_UiRectParams params)
{ {
GPU_RenderCmdDesc cmd = ZI; GPU_RenderCmdDesc cmd = ZI;
cmd.kind = GP_RENDER_CMD_KIND_DRAW_UI_RECT; cmd.kind = GP_RENDER_CMD_KIND_DRAW_UI_RECT;
cmd.ui_rect.xf = params.xf; cmd.ui_rect.xf = params.xf;
cmd.ui_rect.texture = params.texture; cmd.ui_rect.texture = params.texture;
cmd.ui_rect.clip = params.clip; cmd.ui_rect.clip = params.clip;
cmd.ui_rect.tint = params.tint; cmd.ui_rect.tint = params.tint;
GPU_PushRenderCmd(sig, &cmd); GPU_PushRenderCmd(sig, &cmd);
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Text //~ Text
/* Returns the rect of the text area */ /* Returns the rect of the text area */
Rect draw_text(GPU_RenderSig *sig, D_TextParams params) Rect draw_text(GPU_RenderSig *sig, D_TextParams params)
{ {
TempArena scratch = BeginScratchNoConflict(); TempArena scratch = BeginScratchNoConflict();
f32 inv_font_image_width = 1.0 / (f32)params.font->image_width; f32 inv_font_image_width = 1.0 / (f32)params.font->image_width;
f32 inv_font_image_height = 1.0 / (f32)params.font->image_height; f32 inv_font_image_height = 1.0 / (f32)params.font->image_height;
f32 line_spacing = params.font->point_size * 1.5f * params.scale; f32 line_spacing = params.font->point_size * 1.5f * params.scale;
//- Build line glyphs //- Build line glyphs
u64 num_lines = 0; u64 num_lines = 0;
f32 widest_line = 0; f32 widest_line = 0;
D_TextLine *first_line = 0; D_TextLine *first_line = 0;
D_TextLine *last_line = 0; D_TextLine *last_line = 0;
f32 first_line_top_offset = 0; f32 first_line_top_offset = 0;
f32 last_line_bottom_offset = 0; f32 last_line_bottom_offset = 0;
if (params.str.len > 0) if (params.str.len > 0)
{
b32 string_done = 0;
CodepointIter iter = BeginCodepointIter(params.str);
while (!string_done)
{ {
b32 string_done = 0; f32 line_width = 0;
CodepointIter iter = BeginCodepointIter(params.str); f32 top_offset = 0;
while (!string_done) f32 bottom_offset = 0;
u64 num_line_glyphs = 0;
D_TextGlyph *line_glyphs = PushDry(scratch.arena, D_TextGlyph);
b32 line_done = 0;
while (!line_done)
{
string_done = !AdvanceCodepointIter(&iter);
if (string_done)
{ {
f32 line_width = 0; line_done = 1;
f32 top_offset = 0;
f32 bottom_offset = 0;
u64 num_line_glyphs = 0;
D_TextGlyph *line_glyphs = PushDry(scratch.arena, D_TextGlyph);
b32 line_done = 0;
while (!line_done)
{
string_done = !AdvanceCodepointIter(&iter);
if (string_done)
{
line_done = 1;
}
else
{
u32 codepoint = iter.codepoint;
if (codepoint == '\n')
{
line_done = 1;
}
else
{
D_TextGlyph *tg = PushStruct(scratch.arena, D_TextGlyph);
++num_line_glyphs;
F_Glyph *glyph = F_GetGlyph(params.font, codepoint);
tg->off_x = glyph->off_x * params.scale;
tg->off_y = glyph->off_y * params.scale;
tg->width = glyph->width * params.scale;
tg->height = glyph->height * params.scale;
tg->advance = glyph->advance * params.scale;
Rect glyph_atlas_rect = glyph->atlas_rect;
tg->clip = (ClipRect) {
{
glyph_atlas_rect.x * inv_font_image_width,
glyph_atlas_rect.y * inv_font_image_height
},
{
(glyph_atlas_rect.x + glyph_atlas_rect.width) * inv_font_image_width,
(glyph_atlas_rect.y + glyph_atlas_rect.height) * inv_font_image_height
}
};
line_width += tg->advance;
top_offset = MinF32(top_offset, tg->off_y);
bottom_offset = MaxF32(bottom_offset, tg->off_y + tg->height);
}
}
}
/* Line ended */
/* TODO: Only create nodes for non-empty lines. Embed line number in the node. */
D_TextLine *node = PushStruct(scratch.arena, D_TextLine);
node->line_width = line_width;
node->num_glyphs = num_line_glyphs;
node->glyphs = line_glyphs;
if (last_line)
{
last_line->next = node;
}
else
{
first_line = node;
first_line_top_offset = top_offset;
}
last_line = node;
last_line_bottom_offset = bottom_offset;
widest_line = MaxF32(widest_line, line_width);
++num_lines;
} }
EndCodepointIter(&iter); else
}
//- Determine text bounds
Rect bounds = ZI;
bounds.x = params.pos.x;
bounds.y = params.pos.y;
bounds.width = widest_line;
bounds.height = num_lines * line_spacing + first_line_top_offset + last_line_bottom_offset;
/* Offset bounds X */
switch (params.offset_x)
{
case DRAW_TEXT_OFFSET_X_LEFT: break;
case DRAW_TEXT_OFFSET_X_CENTER:
{ {
bounds.x -= bounds.width / 2.f; u32 codepoint = iter.codepoint;
} break; if (codepoint == '\n')
case DRAW_TEXT_OFFSET_X_RIGHT: {
{ line_done = 1;
bounds.x -= bounds.width; }
} break; else
} {
D_TextGlyph *tg = PushStruct(scratch.arena, D_TextGlyph);
/* Offset bounds Y */ ++num_line_glyphs;
switch (params.offset_y) F_Glyph *glyph = F_GetGlyph(params.font, codepoint);
{ tg->off_x = glyph->off_x * params.scale;
case DRAW_TEXT_OFFSET_Y_TOP: break; tg->off_y = glyph->off_y * params.scale;
case DRAW_TEXT_OFFSET_Y_CENTER: tg->width = glyph->width * params.scale;
{ tg->height = glyph->height * params.scale;
bounds.y -= bounds.height / 2.f; tg->advance = glyph->advance * params.scale;
} break; Rect glyph_atlas_rect = glyph->atlas_rect;
case DRAW_TEXT_OFFSET_Y_BOTTOM: tg->clip = (ClipRect) {
{ {
if (last_line) glyph_atlas_rect.x * inv_font_image_width,
{ glyph_atlas_rect.y * inv_font_image_height
bounds.y -= bounds.height + last_line_bottom_offset; },
} {
} break; (glyph_atlas_rect.x + glyph_atlas_rect.width) * inv_font_image_width,
} (glyph_atlas_rect.y + glyph_atlas_rect.height) * inv_font_image_height
}
//- Draw lines };
line_width += tg->advance;
u64 line_number = 0; top_offset = MinF32(top_offset, tg->off_y);
for (D_TextLine *line = first_line; line; line = line->next) bottom_offset = MaxF32(bottom_offset, tg->off_y + tg->height);
{ }
Vec2 draw_pos = bounds.pos;
draw_pos.y += line_number * line_spacing - first_line_top_offset;
/* Alignment */
switch (params.alignment)
{
case DRAW_TEXT_ALIGNMENT_LEFT: break;
case DRAW_TEXT_ALIGNMENT_CENTER:
{
draw_pos.x += (bounds.width - line->line_width) / 2.f;
} break;
case DRAW_TEXT_ALIGNMENT_RIGHT:
{
draw_pos.x += bounds.width - line->line_width;
} break;
} }
}
/* Draw glyphs in line */ /* Line ended */
for (u64 i = 0; i < line->num_glyphs; ++i) /* TODO: Only create nodes for non-empty lines. Embed line number in the node. */
{ D_TextLine *node = PushStruct(scratch.arena, D_TextLine);
D_TextGlyph *tg = &line->glyphs[i]; node->line_width = line_width;
Vec2 pos = VEC2(draw_pos.x + tg->off_x, draw_pos.y + tg->off_y); node->num_glyphs = num_line_glyphs;
Vec2 size = VEC2(tg->width, tg->height); node->glyphs = line_glyphs;
Xform xf = XformFromRect(RectFromVec2(pos, size)); if (last_line)
D_DrawUiRect(sig, D_UIRECTPARAMS(.xf = xf, .texture = params.font->texture, .tint = params.color, .clip = tg->clip)); {
draw_pos.x += tg->advance; last_line->next = node;
}
else
{
first_line = node;
first_line_top_offset = top_offset;
}
last_line = node;
last_line_bottom_offset = bottom_offset;
widest_line = MaxF32(widest_line, line_width);
++num_lines;
}
EndCodepointIter(&iter);
}
} //- Determine text bounds
++line_number;
Rect bounds = ZI;
bounds.x = params.pos.x;
bounds.y = params.pos.y;
bounds.width = widest_line;
bounds.height = num_lines * line_spacing + first_line_top_offset + last_line_bottom_offset;
/* Offset bounds X */
switch (params.offset_x)
{
case DRAW_TEXT_OFFSET_X_LEFT: break;
case DRAW_TEXT_OFFSET_X_CENTER:
{
bounds.x -= bounds.width / 2.f;
} break;
case DRAW_TEXT_OFFSET_X_RIGHT:
{
bounds.x -= bounds.width;
} break;
}
/* Offset bounds Y */
switch (params.offset_y)
{
case DRAW_TEXT_OFFSET_Y_TOP: break;
case DRAW_TEXT_OFFSET_Y_CENTER:
{
bounds.y -= bounds.height / 2.f;
} break;
case DRAW_TEXT_OFFSET_Y_BOTTOM:
{
if (last_line)
{
bounds.y -= bounds.height + last_line_bottom_offset;
}
} break;
}
//- Draw lines
u64 line_number = 0;
for (D_TextLine *line = first_line; line; line = line->next)
{
Vec2 draw_pos = bounds.pos;
draw_pos.y += line_number * line_spacing - first_line_top_offset;
/* Alignment */
switch (params.alignment)
{
case DRAW_TEXT_ALIGNMENT_LEFT: break;
case DRAW_TEXT_ALIGNMENT_CENTER:
{
draw_pos.x += (bounds.width - line->line_width) / 2.f;
} break;
case DRAW_TEXT_ALIGNMENT_RIGHT:
{
draw_pos.x += bounds.width - line->line_width;
} break;
} }
EndScratch(scratch); /* Draw glyphs in line */
return bounds; for (u64 i = 0; i < line->num_glyphs; ++i)
{
D_TextGlyph *tg = &line->glyphs[i];
Vec2 pos = VEC2(draw_pos.x + tg->off_x, draw_pos.y + tg->off_y);
Vec2 size = VEC2(tg->width, tg->height);
Xform xf = XformFromRect(RectFromVec2(pos, size));
D_DrawUiRect(sig, D_UIRECTPARAMS(.xf = xf, .texture = params.font->texture, .tint = params.color, .clip = tg->clip));
draw_pos.x += tg->advance;
}
++line_number;
}
EndScratch(scratch);
return bounds;
} }

View File

@ -3,17 +3,17 @@
Struct(D_MaterialParams) Struct(D_MaterialParams)
{ {
Xform xf; Xform xf;
GPU_Resource *texture; GPU_Resource *texture;
ClipRect clip; ClipRect clip;
u32 tint; u32 tint;
b32 is_light; b32 is_light;
Vec3 light_emittance; Vec3 light_emittance;
}; };
#define D_MATERIALPARAMS(...) ((D_MaterialParams) { \ #define D_MATERIALPARAMS(...) ((D_MaterialParams) { \
.tint = Color_White, \ .tint = Color_White, \
.clip = AllClipped, \ .clip = AllClipped, \
__VA_ARGS__ \ __VA_ARGS__ \
}) })
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -21,15 +21,15 @@ Struct(D_MaterialParams)
Struct(D_UiRectParams) Struct(D_UiRectParams)
{ {
Xform xf; Xform xf;
GPU_Resource *texture; GPU_Resource *texture;
ClipRect clip; ClipRect clip;
u32 tint; u32 tint;
}; };
#define D_UIRECTPARAMS(...) ((D_UiRectParams) { \ #define D_UIRECTPARAMS(...) ((D_UiRectParams) { \
.tint = Color_White, \ .tint = Color_White, \
.clip = AllClipped, \ .clip = AllClipped, \
__VA_ARGS__ \ __VA_ARGS__ \
}) })
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -38,9 +38,9 @@ Struct(D_UiRectParams)
/* How is text aligned within its area */ /* How is text aligned within its area */
Enum(D_TextAlignment) Enum(D_TextAlignment)
{ {
DRAW_TEXT_ALIGNMENT_LEFT, /* Default */ DRAW_TEXT_ALIGNMENT_LEFT, /* Default */
DRAW_TEXT_ALIGNMENT_CENTER, DRAW_TEXT_ALIGNMENT_CENTER,
DRAW_TEXT_ALIGNMENT_RIGHT DRAW_TEXT_ALIGNMENT_RIGHT
}; };
/* How does the specified text position relate to the text area. /* How does the specified text position relate to the text area.
@ -48,54 +48,54 @@ Enum(D_TextAlignment)
* the specified position. */ * the specified position. */
Enum(D_TextOffsetX) Enum(D_TextOffsetX)
{ {
DRAW_TEXT_OFFSET_X_LEFT, /* Default */ DRAW_TEXT_OFFSET_X_LEFT, /* Default */
DRAW_TEXT_OFFSET_X_CENTER, DRAW_TEXT_OFFSET_X_CENTER,
DRAW_TEXT_OFFSET_X_RIGHT DRAW_TEXT_OFFSET_X_RIGHT
}; };
Enum(D_TextOffsetY) Enum(D_TextOffsetY)
{ {
DRAW_TEXT_OFFSET_Y_TOP, /* Default */ DRAW_TEXT_OFFSET_Y_TOP, /* Default */
DRAW_TEXT_OFFSET_Y_CENTER, DRAW_TEXT_OFFSET_Y_CENTER,
DRAW_TEXT_OFFSET_Y_BOTTOM DRAW_TEXT_OFFSET_Y_BOTTOM
}; };
Struct(D_TextGlyph) Struct(D_TextGlyph)
{ {
f32 off_x; f32 off_x;
f32 off_y; f32 off_y;
f32 width; f32 width;
f32 height; f32 height;
f32 advance; f32 advance;
ClipRect clip; ClipRect clip;
}; };
Struct(D_TextLine) Struct(D_TextLine)
{ {
f32 line_width; f32 line_width;
u32 num_glyphs; u32 num_glyphs;
D_TextGlyph *glyphs; D_TextGlyph *glyphs;
D_TextLine *next; D_TextLine *next;
}; };
Struct(D_TextParams) Struct(D_TextParams)
{ {
F_Font *font; F_Font *font;
Vec2 pos; Vec2 pos;
f32 scale; f32 scale;
u32 color; u32 color;
D_TextAlignment alignment; D_TextAlignment alignment;
D_TextOffsetX offset_x; D_TextOffsetX offset_x;
D_TextOffsetY offset_y; D_TextOffsetY offset_y;
String str; String str;
}; };
#define D_TEXTPARAMS(...) ((D_TextParams) { \ #define D_TEXTPARAMS(...) ((D_TextParams) { \
.scale = 1.0, \ .scale = 1.0, \
.alignment = DRAW_TEXT_ALIGNMENT_LEFT, \ .alignment = DRAW_TEXT_ALIGNMENT_LEFT, \
.offset_x = DRAW_TEXT_OFFSET_X_LEFT, \ .offset_x = DRAW_TEXT_OFFSET_X_LEFT, \
.offset_y = DRAW_TEXT_OFFSET_Y_TOP, \ .offset_y = DRAW_TEXT_OFFSET_Y_TOP, \
.color = Color_White, \ .color = Color_White, \
__VA_ARGS__ \ __VA_ARGS__ \
}) })
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -103,7 +103,7 @@ Struct(D_TextParams)
Struct(D_SharedState) Struct(D_SharedState)
{ {
GPU_Resource *solid_white_texture; GPU_Resource *solid_white_texture;
} extern D_shared_state; } extern D_shared_state;
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////

View File

@ -5,7 +5,7 @@ GC_Ctx GC = Zi;
void GC_Bootstrap(void) void GC_Bootstrap(void)
{ {
OnAsyncTick(GC_TickAsync); OnAsyncTick(GC_TickAsync);
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -13,15 +13,15 @@ void GC_Bootstrap(void)
GC_FontKey GC_FontKeyFromResource(ResourceKey resource) GC_FontKey GC_FontKeyFromResource(ResourceKey resource)
{ {
GC_FontKey result = Zi; GC_FontKey result = Zi;
result.r = resource; result.r = resource;
return result; return result;
} }
u64 GC_HashFromGlyphDesc(GC_GlyphDesc desc) u64 GC_HashFromGlyphDesc(GC_GlyphDesc desc)
{ {
/* TODO: Lower font-size precision to prevent unique hashes for slightly-different font sizes */ /* TODO: Lower font-size precision to prevent unique hashes for slightly-different font sizes */
return RandU64FromSeeds(desc.font.r.v, ((u64)desc.codepoint << 32) | *(u32 *)&desc.font_size); return RandU64FromSeeds(desc.font.r.v, ((u64)desc.codepoint << 32) | *(u32 *)&desc.font_size);
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -30,189 +30,189 @@ u64 GC_HashFromGlyphDesc(GC_GlyphDesc desc)
/* TODO: Thread-local cache */ /* TODO: Thread-local cache */
GC_Run GC_RunFromString(Arena *arena, String str, GC_FontKey font, f32 font_size) GC_Run GC_RunFromString(Arena *arena, String str, GC_FontKey font, f32 font_size)
{ {
GC_Run result = Zi; GC_Run result = Zi;
TempArena scratch = BeginScratch(arena); TempArena scratch = BeginScratch(arena);
Arena *perm = PermArena(); Arena *perm = PermArena();
u64 codepoints_count = 0; u64 codepoints_count = 0;
u32 *codepoints = 0; u32 *codepoints = 0;
{
String32 str32 = String32FromString(scratch.arena, str);
codepoints_count = str32.len;
codepoints = str32.text;
}
//////////////////////////////
//- Grab glyphs from cache
u64 ready_glyphs_count = 0;
GC_Glyph **ready_glyphs = PushStructsNoZero(scratch.arena, GC_Glyph *, codepoints_count);
u32 *uncached_codepoints = PushStructsNoZero(scratch.arena, u32, codepoints_count);
u64 uncached_codepoints_count = 0;
/* TODO: Include advances for glyphs in run that have rasterized but not finished uploading to atlas */
u64 pending_glyphs_count = 0;
{
if (codepoints_count > 0)
{ {
String32 str32 = String32FromString(scratch.arena, str); Lock lock = LockS(&GC.glyphs_mutex);
codepoints_count = str32.len; {
codepoints = str32.text; i64 completion = G_CompletionValueFromQueue(G_QueueKind_AsyncCopy);
} for (u64 codepoint_idx = 0; codepoint_idx < codepoints_count; ++codepoint_idx)
//////////////////////////////
//- Grab glyphs from cache
u64 ready_glyphs_count = 0;
GC_Glyph **ready_glyphs = PushStructsNoZero(scratch.arena, GC_Glyph *, codepoints_count);
u32 *uncached_codepoints = PushStructsNoZero(scratch.arena, u32, codepoints_count);
u64 uncached_codepoints_count = 0;
/* TODO: Include advances for glyphs in run that have rasterized but not finished uploading to atlas */
u64 pending_glyphs_count = 0;
{
if (codepoints_count > 0)
{ {
Lock lock = LockS(&GC.glyphs_mutex); u32 codepoint = codepoints[codepoint_idx];
{
i64 completion = G_CompletionValueFromQueue(G_QueueKind_AsyncCopy);
for (u64 codepoint_idx = 0; codepoint_idx < codepoints_count; ++codepoint_idx)
{
u32 codepoint = codepoints[codepoint_idx];
GC_GlyphDesc desc = Zi; GC_GlyphDesc desc = Zi;
desc.font = font; desc.font = font;
desc.font_size = font_size; desc.font_size = font_size;
desc.codepoint = codepoint; desc.codepoint = codepoint;
u64 hash = GC_HashFromGlyphDesc(desc); u64 hash = GC_HashFromGlyphDesc(desc);
GC_GlyphBin *bin = &GC.glyph_bins[hash % countof(GC.glyph_bins)]; GC_GlyphBin *bin = &GC.glyph_bins[hash % countof(GC.glyph_bins)];
GC_Glyph *glyph = bin->first; GC_Glyph *glyph = bin->first;
for (; glyph; glyph = glyph->next) for (; glyph; glyph = glyph->next)
{ {
if (glyph->hash == hash) break; if (glyph->hash == hash) break;
} }
if (glyph == 0) if (glyph == 0)
{ {
uncached_codepoints[uncached_codepoints_count] = codepoint; uncached_codepoints[uncached_codepoints_count] = codepoint;
uncached_codepoints_count += 1; uncached_codepoints_count += 1;
} }
else if (completion < Atomic64Fetch(&glyph->async_copy_completion_target)) else if (completion < Atomic64Fetch(&glyph->async_copy_completion_target))
{ {
pending_glyphs_count += 1; pending_glyphs_count += 1;
} }
else else
{ {
ready_glyphs[ready_glyphs_count] = glyph; ready_glyphs[ready_glyphs_count] = glyph;
ready_glyphs_count += 1; ready_glyphs_count += 1;
} }
}
}
Unlock(&lock);
} }
}
Unlock(&lock);
} }
}
////////////////////////////// //////////////////////////////
//- Create cache entries //- Create cache entries
u64 submit_cmds_count = 0; u64 submit_cmds_count = 0;
GC_Cmd *submit_cmds = PushStructsNoZero(scratch.arena, GC_Cmd, uncached_codepoints_count); GC_Cmd *submit_cmds = PushStructsNoZero(scratch.arena, GC_Cmd, uncached_codepoints_count);
if (uncached_codepoints_count > 0) if (uncached_codepoints_count > 0)
{
Lock lock = LockE(&GC.glyphs_mutex);
{ {
Lock lock = LockE(&GC.glyphs_mutex); for (u64 uncached_codepoint_idx = 0; uncached_codepoint_idx < uncached_codepoints_count; ++uncached_codepoint_idx)
{
GC_GlyphDesc desc = Zi;
desc.font = font;
desc.font_size = font_size;
desc.codepoint = uncached_codepoints[uncached_codepoint_idx];
u64 hash = GC_HashFromGlyphDesc(desc);
GC_GlyphBin *bin = &GC.glyph_bins[hash % countof(GC.glyph_bins)];
GC_Glyph *glyph = bin->first;
for (; glyph; glyph = glyph->next)
{ {
for (u64 uncached_codepoint_idx = 0; uncached_codepoint_idx < uncached_codepoints_count; ++uncached_codepoint_idx) if (glyph->hash == hash) break;
{
GC_GlyphDesc desc = Zi;
desc.font = font;
desc.font_size = font_size;
desc.codepoint = uncached_codepoints[uncached_codepoint_idx];
u64 hash = GC_HashFromGlyphDesc(desc);
GC_GlyphBin *bin = &GC.glyph_bins[hash % countof(GC.glyph_bins)];
GC_Glyph *glyph = bin->first;
for (; glyph; glyph = glyph->next)
{
if (glyph->hash == hash) break;
}
if (glyph == 0)
{
glyph = PushStruct(perm, GC_Glyph);
glyph->desc = desc;
glyph->hash = hash;
Atomic64FetchSet(&glyph->async_copy_completion_target, I64Max);
SllStackPush(bin->first, glyph);
/* Create cmd */
{
GC_Cmd *cmd = &submit_cmds[submit_cmds_count];
cmd->glyph = glyph;
++submit_cmds_count;
}
}
}
}
Unlock(&lock);
}
//////////////////////////////
//- Submit cmds
if (submit_cmds_count > 0)
{
Lock lock = LockE(&GC.submit.mutex);
for (u64 cmd_idx = 0; cmd_idx < submit_cmds_count; ++cmd_idx)
{
GC_Cmd *src = &submit_cmds[cmd_idx];
GC_CmdNode *n = GC.submit.first_free;
if (n)
{
SllStackPop(GC.submit.first_free);
ZeroStruct(n);
}
else
{
n = PushStruct(perm, GC_CmdNode);
}
n->cmd = *src;
GC.submit.count += 1;
SllQueuePush(GC.submit.first, GC.submit.last, n);
}
Unlock(&lock);
SignalAsyncTick();
}
//////////////////////////////
//- Create run from glyphs
f32 baseline_pos = 0;
result.rects = PushStructs(arena, GC_RunRect, ready_glyphs_count);
result.rects_count = ready_glyphs_count;
for (u64 glyph_idx = 0; glyph_idx < ready_glyphs_count; ++glyph_idx)
{
GC_Glyph *glyph = ready_glyphs[glyph_idx];
GC_RunRect *rect = &result.rects[glyph_idx];
rect->tex = glyph->atlas->tex_ref;
rect->tex_slice = glyph->tex_slice;
rect->tex_slice_uv = glyph->tex_slice_uv;
rect->baseline_pos = baseline_pos;
rect->advance = glyph->advance;
rect->bounds = glyph->bounds;
if (glyph_idx == 0)
{
result.bounds = rect->bounds;
}
else
{
result.bounds = UnionRng2(result.bounds, rect->bounds);
} }
baseline_pos += rect->advance; if (glyph == 0)
result.baseline_length = MaxF32(result.baseline_length, baseline_pos); {
glyph = PushStruct(perm, GC_Glyph);
glyph->desc = desc;
glyph->hash = hash;
Atomic64FetchSet(&glyph->async_copy_completion_target, I64Max);
SllStackPush(bin->first, glyph);
/* Create cmd */
{
GC_Cmd *cmd = &submit_cmds[submit_cmds_count];
cmd->glyph = glyph;
++submit_cmds_count;
}
}
}
} }
Unlock(&lock);
}
if (ready_glyphs_count > 0) //////////////////////////////
//- Submit cmds
if (submit_cmds_count > 0)
{
Lock lock = LockE(&GC.submit.mutex);
for (u64 cmd_idx = 0; cmd_idx < submit_cmds_count; ++cmd_idx)
{ {
GC_Glyph *glyph = ready_glyphs[0]; GC_Cmd *src = &submit_cmds[cmd_idx];
result.font_size = glyph->font_size; GC_CmdNode *n = GC.submit.first_free;
result.font_ascent = glyph->font_ascent; if (n)
result.font_descent = glyph->font_descent; {
result.font_cap = glyph->font_cap; SllStackPop(GC.submit.first_free);
ZeroStruct(n);
}
else
{
n = PushStruct(perm, GC_CmdNode);
}
n->cmd = *src;
GC.submit.count += 1;
SllQueuePush(GC.submit.first, GC.submit.last, n);
}
Unlock(&lock);
SignalAsyncTick();
}
//////////////////////////////
//- Create run from glyphs
f32 baseline_pos = 0;
result.rects = PushStructs(arena, GC_RunRect, ready_glyphs_count);
result.rects_count = ready_glyphs_count;
for (u64 glyph_idx = 0; glyph_idx < ready_glyphs_count; ++glyph_idx)
{
GC_Glyph *glyph = ready_glyphs[glyph_idx];
GC_RunRect *rect = &result.rects[glyph_idx];
rect->tex = glyph->atlas->tex_ref;
rect->tex_slice = glyph->tex_slice;
rect->tex_slice_uv = glyph->tex_slice_uv;
rect->baseline_pos = baseline_pos;
rect->advance = glyph->advance;
rect->bounds = glyph->bounds;
if (glyph_idx == 0)
{
result.bounds = rect->bounds;
}
else
{
result.bounds = UnionRng2(result.bounds, rect->bounds);
} }
// result.ready = uncached_codepoints_count == 0 && pending_glyphs_count == 0; baseline_pos += rect->advance;
result.ready = 1; result.baseline_length = MaxF32(result.baseline_length, baseline_pos);
}
EndScratch(scratch); if (ready_glyphs_count > 0)
return result; {
GC_Glyph *glyph = ready_glyphs[0];
result.font_size = glyph->font_size;
result.font_ascent = glyph->font_ascent;
result.font_descent = glyph->font_descent;
result.font_cap = glyph->font_cap;
}
// result.ready = uncached_codepoints_count == 0 && pending_glyphs_count == 0;
result.ready = 1;
EndScratch(scratch);
return result;
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -220,162 +220,162 @@ GC_Run GC_RunFromString(Arena *arena, String str, GC_FontKey font, f32 font_size
void GC_TickAsync(WaveLaneCtx *lane, AsyncTickCtx *tick) void GC_TickAsync(WaveLaneCtx *lane, AsyncTickCtx *tick)
{ {
GC_AsyncCtx *async = &GC.async_ctx; GC_AsyncCtx *async = &GC.async_ctx;
////////////////////////////// //////////////////////////////
//- Begin tick //- Begin tick
/* TODO: Limit cmds processed per-tick */ /* TODO: Limit cmds processed per-tick */
if (lane->idx == 0) if (lane->idx == 0)
{
ZeroStruct(&async->cmds);
Lock lock = LockE(&GC.submit.mutex);
{ {
ZeroStruct(&async->cmds); /* Pop cmds from submission queue */
async->cmds.count = GC.submit.count;
Lock lock = LockE(&GC.submit.mutex); async->cmds.v = PushStructsNoZero(tick->arena, GC_Cmd, GC.submit.count);
{ u64 cmd_idx = 0;
/* Pop cmds from submission queue */ for (GC_CmdNode *n = GC.submit.first; n; n = n->next)
async->cmds.count = GC.submit.count; {
async->cmds.v = PushStructsNoZero(tick->arena, GC_Cmd, GC.submit.count); async->cmds.v[cmd_idx] = n->cmd;
u64 cmd_idx = 0; ++cmd_idx;
for (GC_CmdNode *n = GC.submit.first; n; n = n->next) }
{ /* Reset submission queue */
async->cmds.v[cmd_idx] = n->cmd; GC.submit.first_free = GC.submit.first;
++cmd_idx; GC.submit.count = 0;
} GC.submit.first = 0;
/* Reset submission queue */ GC.submit.last = 0;
GC.submit.first_free = GC.submit.first;
GC.submit.count = 0;
GC.submit.first = 0;
GC.submit.last = 0;
}
Unlock(&lock);
} }
Unlock(&lock);
}
WaveSync(lane);
if (async->cmds.count > 0)
{
//////////////////////////////
//- Rasterize glyphs
/* TODO: Process cmds unevenly to account for varying work size */
{
RngU64 cmd_idxs = WaveIdxRangeFromCount(lane, async->cmds.count);
for (u64 cmd_idx = cmd_idxs.min; cmd_idx < cmd_idxs.max; ++cmd_idx)
{
GC_Cmd *cmd = &async->cmds.v[cmd_idx];
GC_Glyph *glyph = cmd->glyph;
ResourceKey resource = glyph->desc.font.r;
GC_GlyphDesc desc = glyph->desc;
TTF_GlyphResult ttf_result = TTF_RasterizeGlyphFromCodepoint(tick->arena, desc.codepoint, resource, desc.font_size);;
glyph->font_size = desc.font_size;
glyph->font_ascent = ttf_result.font_ascent;
glyph->font_descent = ttf_result.font_descent;
glyph->font_cap = ttf_result.font_cap;
glyph->advance = ttf_result.advance;
glyph->bounds = ttf_result.bounds;
cmd->rasterized = ttf_result;
}
}
/* TODO: Only sync first lane? */
WaveSync(lane); WaveSync(lane);
if (async->cmds.count > 0) ////////////////////////////
//- Allocate atlas slices
if (lane->idx == 0)
{ {
////////////////////////////// G_CommandListHandle cl = G_PrepareCommandList(G_QueueKind_AsyncCopy);
//- Rasterize glyphs for (u64 cmd_idx = 0; cmd_idx < async->cmds.count; ++cmd_idx)
{
GC_Cmd *cmd = &async->cmds.v[cmd_idx];
GC_Glyph *glyph = cmd->glyph;
GC_GlyphDesc desc = glyph->desc;
TTF_GlyphResult ttf_result = cmd->rasterized;
/* TODO: Process cmds unevenly to account for varying work size */ Vec2I32 image_dims = ttf_result.image_dims;
/* TODO: Use a more efficient atlas packing algorithm for less wasted space `*/
GC_Atlas *atlas = GC.first_atlas;
b32 can_use_atlas = 0;
Vec2I32 pos_in_atlas = Zi;
while (can_use_atlas == 0)
{ {
RngU64 cmd_idxs = WaveIdxRangeFromCount(lane, async->cmds.count); /* Create atlas */
for (u64 cmd_idx = cmd_idxs.min; cmd_idx < cmd_idxs.max; ++cmd_idx) if (!atlas)
{
Arena *perm = PermArena();
atlas = PushStruct(perm, GC_Atlas);
atlas->dims = VEC2I32(1024, 1024);
{ {
GC_Cmd *cmd = &async->cmds.v[cmd_idx]; G_ArenaHandle gpu_perm = G_PermArena();
GC_Glyph *glyph = cmd->glyph; atlas->tex = G_PushTexture2D(
ResourceKey resource = glyph->desc.font.r; gpu_perm, cl,
GC_GlyphDesc desc = glyph->desc; G_Format_R8G8B8A8_Unorm_Srgb,
TTF_GlyphResult ttf_result = TTF_RasterizeGlyphFromCodepoint(tick->arena, desc.codepoint, resource, desc.font_size);; atlas->dims,
glyph->font_size = desc.font_size; G_Layout_AnyQueue_ShaderRead_CopyRead_CopyWrite_Present,
glyph->font_ascent = ttf_result.font_ascent; );
glyph->font_descent = ttf_result.font_descent; atlas->tex_ref = G_PushTexture2DRef(gpu_perm, atlas->tex);
glyph->font_cap = ttf_result.font_cap;
glyph->advance = ttf_result.advance;
glyph->bounds = ttf_result.bounds;
cmd->rasterized = ttf_result;
} }
SllStackPush(GC.first_atlas, atlas);
++GC.atlases_count;
}
/* Determine pos in atlas */
pos_in_atlas = atlas->cur_pos;
atlas->cur_row_height = MaxI32(atlas->cur_row_height, image_dims.y);
if (pos_in_atlas.x + image_dims.x > atlas->dims.x);
{
atlas->cur_pos.x = 0;
atlas->cur_pos.y += atlas->cur_row_height;
atlas->cur_row_height = image_dims.y;
}
atlas->cur_pos.x += image_dims.x;
if (atlas->cur_pos.x < atlas->dims.x && atlas->cur_pos.y < atlas->dims.y)
{
can_use_atlas = 1;
}
else
{
atlas = 0;
}
} }
/* TODO: Only sync first lane? */ /* Atlas info */
glyph->atlas = atlas;
glyph->tex_slice = RNG2I32(pos_in_atlas, AddVec2I32(pos_in_atlas, image_dims));
glyph->tex_slice_uv.p0.x = (f32)glyph->tex_slice.p0.x / (f32)atlas->dims.x;
glyph->tex_slice_uv.p0.y = (f32)glyph->tex_slice.p0.y / (f32)atlas->dims.x;
glyph->tex_slice_uv.p1.x = (f32)glyph->tex_slice.p1.x / (f32)atlas->dims.x;
glyph->tex_slice_uv.p1.y = (f32)glyph->tex_slice.p1.y / (f32)atlas->dims.x;
WaveSync(lane); /* Copy to atlas */
u32 *image_pixels = ttf_result.image_pixels;
//////////////////////////// if (image_dims.x > 0 && image_dims.y > 0)
//- Allocate atlas slices
if (lane->idx == 0)
{ {
G_CommandListHandle cl = G_PrepareCommandList(G_QueueKind_AsyncCopy); G_CopyCpuToTexture(
for (u64 cmd_idx = 0; cmd_idx < async->cmds.count; ++cmd_idx) cl,
{ glyph->atlas->tex, VEC3I32(glyph->tex_slice.p0.x, glyph->tex_slice.p0.y, 0),
GC_Cmd *cmd = &async->cmds.v[cmd_idx]; image_pixels, VEC3I32(image_dims.x, image_dims.y, 1),
GC_Glyph *glyph = cmd->glyph; RNG3I32(
GC_GlyphDesc desc = glyph->desc; VEC3I32(0, 0, 0),
TTF_GlyphResult ttf_result = cmd->rasterized; VEC3I32(image_dims.x, image_dims.y, 1)
)
Vec2I32 image_dims = ttf_result.image_dims; );
/* TODO: Use a more efficient atlas packing algorithm for less wasted space `*/
GC_Atlas *atlas = GC.first_atlas;
b32 can_use_atlas = 0;
Vec2I32 pos_in_atlas = Zi;
while (can_use_atlas == 0)
{
/* Create atlas */
if (!atlas)
{
Arena *perm = PermArena();
atlas = PushStruct(perm, GC_Atlas);
atlas->dims = VEC2I32(1024, 1024);
{
G_ArenaHandle gpu_perm = G_PermArena();
atlas->tex = G_PushTexture2D(
gpu_perm, cl,
G_Format_R8G8B8A8_Unorm_Srgb,
atlas->dims,
G_Layout_AnyQueue_ShaderRead_CopyRead_CopyWrite_Present,
);
atlas->tex_ref = G_PushTexture2DRef(gpu_perm, atlas->tex);
}
SllStackPush(GC.first_atlas, atlas);
++GC.atlases_count;
}
/* Determine pos in atlas */
pos_in_atlas = atlas->cur_pos;
atlas->cur_row_height = MaxI32(atlas->cur_row_height, image_dims.y);
if (pos_in_atlas.x + image_dims.x > atlas->dims.x);
{
atlas->cur_pos.x = 0;
atlas->cur_pos.y += atlas->cur_row_height;
atlas->cur_row_height = image_dims.y;
}
atlas->cur_pos.x += image_dims.x;
if (atlas->cur_pos.x < atlas->dims.x && atlas->cur_pos.y < atlas->dims.y)
{
can_use_atlas = 1;
}
else
{
atlas = 0;
}
}
/* Atlas info */
glyph->atlas = atlas;
glyph->tex_slice = RNG2I32(pos_in_atlas, AddVec2I32(pos_in_atlas, image_dims));
glyph->tex_slice_uv.p0.x = (f32)glyph->tex_slice.p0.x / (f32)atlas->dims.x;
glyph->tex_slice_uv.p0.y = (f32)glyph->tex_slice.p0.y / (f32)atlas->dims.x;
glyph->tex_slice_uv.p1.x = (f32)glyph->tex_slice.p1.x / (f32)atlas->dims.x;
glyph->tex_slice_uv.p1.y = (f32)glyph->tex_slice.p1.y / (f32)atlas->dims.x;
/* Copy to atlas */
u32 *image_pixels = ttf_result.image_pixels;
if (image_dims.x > 0 && image_dims.y > 0)
{
G_CopyCpuToTexture(
cl,
glyph->atlas->tex, VEC3I32(glyph->tex_slice.p0.x, glyph->tex_slice.p0.y, 0),
image_pixels, VEC3I32(image_dims.x, image_dims.y, 1),
RNG3I32(
VEC3I32(0, 0, 0),
VEC3I32(image_dims.x, image_dims.y, 1)
)
);
}
}
i64 completion_target = G_CommitCommandList(cl);
/* Update completion targets */
for (u64 cmd_idx = 0; cmd_idx < async->cmds.count; ++cmd_idx)
{
GC_Cmd *cmd = &async->cmds.v[cmd_idx];
GC_Glyph *glyph = cmd->glyph;
Atomic64Set(&glyph->async_copy_completion_target, completion_target);
}
} }
}
i64 completion_target = G_CommitCommandList(cl);
/* Update completion targets */
for (u64 cmd_idx = 0; cmd_idx < async->cmds.count; ++cmd_idx)
{
GC_Cmd *cmd = &async->cmds.v[cmd_idx];
GC_Glyph *glyph = cmd->glyph;
Atomic64Set(&glyph->async_copy_completion_target, completion_target);
}
} }
}
} }

View File

@ -3,7 +3,7 @@
Struct(GC_FontKey) Struct(GC_FontKey)
{ {
ResourceKey r; ResourceKey r;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -11,13 +11,13 @@ Struct(GC_FontKey)
Struct(GC_Atlas) Struct(GC_Atlas)
{ {
GC_Atlas *next; GC_Atlas *next;
Vec2I32 dims; Vec2I32 dims;
G_ResourceHandle tex; G_ResourceHandle tex;
G_Texture2DRef tex_ref; G_Texture2DRef tex_ref;
Vec2I32 cur_pos; Vec2I32 cur_pos;
i32 cur_row_height; i32 cur_row_height;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -25,38 +25,38 @@ Struct(GC_Atlas)
Struct(GC_GlyphDesc) Struct(GC_GlyphDesc)
{ {
GC_FontKey font; GC_FontKey font;
f32 font_size; f32 font_size;
u32 codepoint; u32 codepoint;
}; };
Struct(GC_Glyph) Struct(GC_Glyph)
{ {
GC_Glyph *next; GC_Glyph *next;
GC_GlyphDesc desc; GC_GlyphDesc desc;
u64 hash; u64 hash;
Atomic64 async_copy_completion_target; Atomic64 async_copy_completion_target;
/* Font info */ /* Font info */
f32 font_size; f32 font_size;
f32 font_ascent; f32 font_ascent;
f32 font_descent; f32 font_descent;
f32 font_cap; f32 font_cap;
/* Layout info */ /* Layout info */
f32 advance; f32 advance;
Rng2 bounds; Rng2 bounds;
/* Atlas info */ /* Atlas info */
GC_Atlas *atlas; GC_Atlas *atlas;
Rng2I32 tex_slice; Rng2I32 tex_slice;
Rng2 tex_slice_uv; Rng2 tex_slice_uv;
}; };
Struct(GC_GlyphBin) Struct(GC_GlyphBin)
{ {
GC_Glyph *first; GC_Glyph *first;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -64,30 +64,30 @@ Struct(GC_GlyphBin)
Struct(GC_RunRect) Struct(GC_RunRect)
{ {
Rng2 bounds; /* Visual bounds in relation to the baseline */ Rng2 bounds; /* Visual bounds in relation to the baseline */
f32 baseline_pos; /* Horizontal distance from start of baseline */ f32 baseline_pos; /* Horizontal distance from start of baseline */
f32 advance; f32 advance;
G_Texture2DRef tex; G_Texture2DRef tex;
Rng2I32 tex_slice; Rng2I32 tex_slice;
Rng2 tex_slice_uv; Rng2 tex_slice_uv;
}; };
Struct(GC_Run) Struct(GC_Run)
{ {
/* Run data */ /* Run data */
Rng2 bounds; /* Visual bounds of the run in relation to the baseline */ Rng2 bounds; /* Visual bounds of the run in relation to the baseline */
f32 baseline_length; f32 baseline_length;
u64 rects_count; u64 rects_count;
GC_RunRect *rects; GC_RunRect *rects;
/* Font info */ /* Font info */
f32 font_size; f32 font_size;
f32 font_ascent; f32 font_ascent;
f32 font_descent; f32 font_descent;
f32 font_cap; f32 font_cap;
b32 ready; b32 ready;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -95,16 +95,16 @@ Struct(GC_Run)
Struct(GC_Cmd) Struct(GC_Cmd)
{ {
GC_Glyph *glyph; GC_Glyph *glyph;
/* Async temporary data */ /* Async temporary data */
TTF_GlyphResult rasterized; TTF_GlyphResult rasterized;
}; };
Struct(GC_CmdNode) Struct(GC_CmdNode)
{ {
GC_CmdNode *next; GC_CmdNode *next;
GC_Cmd cmd; GC_Cmd cmd;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -112,31 +112,31 @@ Struct(GC_CmdNode)
Struct(GC_AsyncCtx) Struct(GC_AsyncCtx)
{ {
struct struct
{ {
u64 count; u64 count;
GC_Cmd *v; GC_Cmd *v;
} cmds; } cmds;
}; };
Struct(GC_Ctx) Struct(GC_Ctx)
{ {
Mutex glyphs_mutex; Mutex glyphs_mutex;
GC_GlyphBin glyph_bins[16384]; GC_GlyphBin glyph_bins[16384];
u64 atlases_count; u64 atlases_count;
GC_Atlas *first_atlas; GC_Atlas *first_atlas;
struct struct
{ {
Mutex mutex; Mutex mutex;
u64 count; u64 count;
GC_CmdNode *first; GC_CmdNode *first;
GC_CmdNode *last; GC_CmdNode *last;
GC_CmdNode *first_free; GC_CmdNode *first_free;
} submit; } submit;
GC_AsyncCtx async_ctx; GC_AsyncCtx async_ctx;
}; };
extern GC_Ctx GC; extern GC_Ctx GC;

View File

@ -6,57 +6,57 @@ ThreadLocal G_ArenaHandle G_t_perm_arena = Zi;
void G_BootstrapCommon(void) void G_BootstrapCommon(void)
{ {
G_SharedUtilState *g = &G_shared_util_state; G_SharedUtilState *g = &G_shared_util_state;
G_ArenaHandle gpu_perm = G_PermArena(); G_ArenaHandle gpu_perm = G_PermArena();
G_CommandListHandle cl = G_PrepareCommandList(G_QueueKind_Direct); G_CommandListHandle cl = G_PrepareCommandList(G_QueueKind_Direct);
{
/* Init quad index buffer */
{ {
/* Init quad index buffer */ G_ResourceHandle quad_indices = Zi;
{ u16 quad_data[6] = { 0, 1, 2, 0, 2, 3 };
G_ResourceHandle quad_indices = Zi; quad_indices = G_PushBuffer(gpu_perm, cl, u16, countof(quad_data));
u16 quad_data[6] = { 0, 1, 2, 0, 2, 3 }; G_CopyCpuToBuffer(cl, quad_indices, 0, quad_data, RNGU64(0, sizeof(quad_data)));
quad_indices = G_PushBuffer(gpu_perm, cl, u16, countof(quad_data)); g->quad_indices = G_IdxBuff16(quad_indices);
G_CopyCpuToBuffer(cl, quad_indices, 0, quad_data, RNGU64(0, sizeof(quad_data)));
g->quad_indices = G_IdxBuff16(quad_indices);
}
/* Init point sampler */
{
G_ResourceHandle pt_sampler = G_PushSampler(gpu_perm, cl, .filter = G_Filter_MinMagMipPoint);
g->basic_sampler = G_PushSamplerStateRef(gpu_perm, pt_sampler);
}
/* Init noise texture */
{
G_ResourceHandle noise_tex = Zi;
String noise_data = DataFromResource(ResourceKeyFromStore(&G_Resources, Lit("noise_128x128x64_16.dat")));
Vec3I32 noise_dims = VEC3I32(128, 128, 64);
if (noise_data.len != noise_dims.x * noise_dims.y * noise_dims.z * 2)
{
Panic(Lit("Unexpected noise texture size"));
}
noise_tex = G_PushTexture3D(
gpu_perm, cl,
G_Format_R16_Uint,
noise_dims,
G_Layout_AnyQueue_ShaderRead_CopyRead_CopyWrite_Present
);
G_CopyCpuToTexture(
cl,
noise_tex, VEC3I32(0, 0, 0),
noise_data.text, noise_dims,
RNG3I32(VEC3I32(0, 0, 0), noise_dims)
);
g->basic_noise = G_PushTexture3DRef(gpu_perm, noise_tex);
}
} }
G_CommitCommandList(cl);
/* Barrier all queues until direct queue finishes initializing resources */ /* Init point sampler */
G_Sync(G_QueueMask_Direct, G_QueueMask_All); {
G_ResourceHandle pt_sampler = G_PushSampler(gpu_perm, cl, .filter = G_Filter_MinMagMipPoint);
g->basic_sampler = G_PushSamplerStateRef(gpu_perm, pt_sampler);
}
/* Init noise texture */
{
G_ResourceHandle noise_tex = Zi;
String noise_data = DataFromResource(ResourceKeyFromStore(&G_Resources, Lit("noise_128x128x64_16.dat")));
Vec3I32 noise_dims = VEC3I32(128, 128, 64);
if (noise_data.len != noise_dims.x * noise_dims.y * noise_dims.z * 2)
{
Panic(Lit("Unexpected noise texture size"));
}
noise_tex = G_PushTexture3D(
gpu_perm, cl,
G_Format_R16_Uint,
noise_dims,
G_Layout_AnyQueue_ShaderRead_CopyRead_CopyWrite_Present
);
G_CopyCpuToTexture(
cl,
noise_tex, VEC3I32(0, 0, 0),
noise_data.text, noise_dims,
RNG3I32(VEC3I32(0, 0, 0), noise_dims)
);
g->basic_noise = G_PushTexture3DRef(gpu_perm, noise_tex);
}
}
G_CommitCommandList(cl);
/* Barrier all queues until direct queue finishes initializing resources */
G_Sync(G_QueueMask_Direct, G_QueueMask_All);
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -66,56 +66,56 @@ void G_BootstrapCommon(void)
G_ArenaHandle G_PermArena(void) G_ArenaHandle G_PermArena(void)
{ {
G_ArenaHandle perm = G_t_perm_arena; G_ArenaHandle perm = G_t_perm_arena;
if (G_IsArenaNil(perm)) if (G_IsArenaNil(perm))
{ {
G_t_perm_arena = G_AcquireArena(); G_t_perm_arena = G_AcquireArena();
perm = G_t_perm_arena; perm = G_t_perm_arena;
} }
return perm; return perm;
} }
//- Cpu -> Gpu upload //- Cpu -> Gpu upload
G_ResourceHandle G_PushBufferFromString_(G_ArenaHandle gpu_arena, G_CommandListHandle cl, String src, G_BufferDesc desc) G_ResourceHandle G_PushBufferFromString_(G_ArenaHandle gpu_arena, G_CommandListHandle cl, String src, G_BufferDesc desc)
{ {
G_ResourceHandle buffer = G_PushResource(gpu_arena, cl, (G_ResourceDesc) { .kind = G_ResourceKind_Buffer, .buffer = desc }); G_ResourceHandle buffer = G_PushResource(gpu_arena, cl, (G_ResourceDesc) { .kind = G_ResourceKind_Buffer, .buffer = desc });
G_CopyCpuToBuffer(cl, buffer, 0, src.text, RNGU64(0, src.len)); G_CopyCpuToBuffer(cl, buffer, 0, src.text, RNGU64(0, src.len));
G_MemorySync( G_MemorySync(
cl, buffer, cl, buffer,
G_Stage_Copy, G_Access_CopyWrite, G_Stage_Copy, G_Access_CopyWrite,
G_Stage_All, G_Access_All G_Stage_All, G_Access_All
); );
return buffer; return buffer;
} }
//- Viewport / scissor //- Viewport / scissor
Rng3 G_ViewportFromTexture(G_ResourceHandle texture) Rng3 G_ViewportFromTexture(G_ResourceHandle texture)
{ {
Vec2I32 dims = G_Count2D(texture); Vec2I32 dims = G_Count2D(texture);
return RNG3(VEC3(0, 0, 0), VEC3(dims.x, dims.y, 1)); return RNG3(VEC3(0, 0, 0), VEC3(dims.x, dims.y, 1));
} }
Rng2 G_ScissorFromTexture(G_ResourceHandle texture) Rng2 G_ScissorFromTexture(G_ResourceHandle texture)
{ {
Vec2I32 dims = G_Count2D(texture); Vec2I32 dims = G_Count2D(texture);
return RNG2(VEC2(0, 0), VEC2(dims.x, dims.y)); return RNG2(VEC2(0, 0), VEC2(dims.x, dims.y));
} }
//- Shared resources //- Shared resources
G_IndexBufferDesc G_QuadIndices(void) G_IndexBufferDesc G_QuadIndices(void)
{ {
return G_shared_util_state.quad_indices; return G_shared_util_state.quad_indices;
} }
G_SamplerStateRef G_BasicSampler(void) G_SamplerStateRef G_BasicSampler(void)
{ {
return G_shared_util_state.basic_sampler; return G_shared_util_state.basic_sampler;
} }
G_Texture3DRef G_BasicNoiseTexture(void) G_Texture3DRef G_BasicNoiseTexture(void)
{ {
return G_shared_util_state.basic_noise; return G_shared_util_state.basic_noise;
} }

View File

@ -3,10 +3,10 @@
Struct(G_SharedUtilState) Struct(G_SharedUtilState)
{ {
/* Common shared resources */ /* Common shared resources */
G_IndexBufferDesc quad_indices; G_IndexBufferDesc quad_indices;
G_SamplerStateRef basic_sampler; G_SamplerStateRef basic_sampler;
G_Texture3DRef basic_noise; G_Texture3DRef basic_noise;
} extern G_shared_util_state; } extern G_shared_util_state;
extern ThreadLocal G_ArenaHandle G_t_perm_arena; extern ThreadLocal G_ArenaHandle G_t_perm_arena;
@ -27,7 +27,7 @@ G_ArenaHandle G_PermArena(void);
G_ResourceHandle G_PushBufferFromString_(G_ArenaHandle gpu_arena, G_CommandListHandle cl, String src, G_BufferDesc desc); G_ResourceHandle G_PushBufferFromString_(G_ArenaHandle gpu_arena, G_CommandListHandle cl, String src, G_BufferDesc desc);
#define G_PushBufferFromString(_arena, _cl, _src, ...) \ #define G_PushBufferFromString(_arena, _cl, _src, ...) \
G_PushBufferFromString_((_arena), (_cl), (_src), (G_BufferDesc) { .size = (_src).len, __VA_ARGS__ }) G_PushBufferFromString_((_arena), (_cl), (_src), (G_BufferDesc) { .size = (_src).len, __VA_ARGS__ })
//- Viewport / scissor //- Viewport / scissor

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -2,9 +2,9 @@
//~ DirectX12 libs //~ DirectX12 libs
#pragma warning(push, 0) #pragma warning(push, 0)
# include <d3d12.h> #include <d3d12.h>
# include <dxgidebug.h> #include <dxgidebug.h>
# include <dxgi1_6.h> #include <dxgi1_6.h>
#pragma warning(pop) #pragma warning(pop)
#pragma comment(lib, "d3d12") #pragma comment(lib, "d3d12")
@ -16,9 +16,10 @@
#define G_D12_TearingIsAllowed 1 #define G_D12_TearingIsAllowed 1
#define G_D12_FrameLatency 1 #define G_D12_FrameLatency 1
#define G_D12_SwapchainBufferCount 3 #define G_D12_SwapchainBufferCount 3
#define G_D12_SwapchainFlags (((G_D12_TearingIsAllowed != 0) * DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING) \ #define G_D12_SwapchainFlags (0 \
| ((G_D12_FrameLatency != 0) * DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT)) | ((G_D12_TearingIsAllowed != 0) * DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING) \
| ((G_D12_FrameLatency != 0) * DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT) \
)
#define G_D12_MaxCbvSrvUavDescriptors (1024 * 128) #define G_D12_MaxCbvSrvUavDescriptors (1024 * 128)
#define G_D12_MaxSamplerDescriptors (1024 * 1) #define G_D12_MaxSamplerDescriptors (1024 * 1)
@ -29,30 +30,30 @@
Struct(G_D12_PipelineDesc) Struct(G_D12_PipelineDesc)
{ {
VertexShader vs; VertexShader vs;
PixelShader ps; PixelShader ps;
ComputeShader cs; ComputeShader cs;
b32 is_wireframe; b32 is_wireframe;
D3D12_PRIMITIVE_TOPOLOGY_TYPE topology_type; D3D12_PRIMITIVE_TOPOLOGY_TYPE topology_type;
G_Format render_target_formats[G_MaxRenderTargets]; G_Format render_target_formats[G_MaxRenderTargets];
}; };
Struct(G_D12_Pipeline) Struct(G_D12_Pipeline)
{ {
G_D12_Pipeline *next_in_bin; G_D12_Pipeline *next_in_bin;
u64 hash; u64 hash;
G_D12_PipelineDesc desc; G_D12_PipelineDesc desc;
ID3D12PipelineState *pso; ID3D12PipelineState *pso;
b32 ok; b32 ok;
String error; String error;
}; };
Struct(G_D12_PipelineBin) Struct(G_D12_PipelineBin)
{ {
Mutex mutex; Mutex mutex;
G_D12_Pipeline *first; G_D12_Pipeline *first;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -60,40 +61,40 @@ Struct(G_D12_PipelineBin)
Struct(G_D12_Resource) Struct(G_D12_Resource)
{ {
G_D12_Resource *next; G_D12_Resource *next;
struct G_D12_ResourceHeap *heap; struct G_D12_ResourceHeap *heap;
u64 pos_in_heap; u64 pos_in_heap;
u64 size_in_heap; u64 size_in_heap;
ID3D12Resource *d3d_resource; ID3D12Resource *d3d_resource;
u64 uid; u64 uid;
G_ResourceFlag flags; G_ResourceFlag flags;
/* Buffer info */ /* Buffer info */
u64 buffer_size; u64 buffer_size;
u64 buffer_size_actual; u64 buffer_size_actual;
D3D12_GPU_VIRTUAL_ADDRESS buffer_gpu_address; D3D12_GPU_VIRTUAL_ADDRESS buffer_gpu_address;
/* Texture info */ /* Texture info */
b32 is_texture; b32 is_texture;
G_Format texture_format; G_Format texture_format;
Vec3I32 texture_dims; Vec3I32 texture_dims;
i32 texture_mip_levels; i32 texture_mip_levels;
D3D12_BARRIER_LAYOUT texture_layout; D3D12_BARRIER_LAYOUT texture_layout;
/* Sampler info */ /* Sampler info */
G_SamplerDesc sampler_desc; G_SamplerDesc sampler_desc;
/* Backbuffer info */ /* Backbuffer info */
struct G_D12_Swapchain *swapchain; struct G_D12_Swapchain *swapchain;
}; };
Struct(G_D12_ResourceList) Struct(G_D12_ResourceList)
{ {
u64 count; u64 count;
G_D12_Resource *first; G_D12_Resource *first;
G_D12_Resource *last; G_D12_Resource *last;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -101,46 +102,46 @@ Struct(G_D12_ResourceList)
Enum(G_D12_DescriptorHeapKind) Enum(G_D12_DescriptorHeapKind)
{ {
G_D12_DescriptorHeapKind_CbvSrvUav, G_D12_DescriptorHeapKind_CbvSrvUav,
G_D12_DescriptorHeapKind_Rtv, G_D12_DescriptorHeapKind_Rtv,
G_D12_DescriptorHeapKind_Sampler, G_D12_DescriptorHeapKind_Sampler,
G_D12_DescriptorHeapKind_Count G_D12_DescriptorHeapKind_Count
}; };
Struct(G_D12_DescriptorHeap) Struct(G_D12_DescriptorHeap)
{ {
Arena *descriptors_arena; Arena *descriptors_arena;
G_D12_DescriptorHeapKind kind; G_D12_DescriptorHeapKind kind;
D3D12_DESCRIPTOR_HEAP_TYPE type; D3D12_DESCRIPTOR_HEAP_TYPE type;
u32 descriptor_size; u32 descriptor_size;
ID3D12DescriptorHeap *d3d_heap; ID3D12DescriptorHeap *d3d_heap;
D3D12_CPU_DESCRIPTOR_HANDLE start_handle; D3D12_CPU_DESCRIPTOR_HANDLE start_handle;
Mutex mutex; Mutex mutex;
struct G_D12_Descriptor *first_free; struct G_D12_Descriptor *first_free;
u32 max_count; u32 max_count;
}; };
Struct(G_D12_Descriptor) Struct(G_D12_Descriptor)
{ {
G_D12_Descriptor *next; G_D12_Descriptor *next;
struct G_D12_Arena *gpu_arena; struct G_D12_Arena *gpu_arena;
G_QueueKind completion_queue_kind; G_QueueKind completion_queue_kind;
i64 completion_queue_target; i64 completion_queue_target;
G_D12_DescriptorHeap *heap; G_D12_DescriptorHeap *heap;
D3D12_CPU_DESCRIPTOR_HANDLE handle; D3D12_CPU_DESCRIPTOR_HANDLE handle;
u32 index; u32 index;
}; };
Struct(G_D12_DescriptorList) Struct(G_D12_DescriptorList)
{ {
u64 count; u64 count;
G_D12_Descriptor *first; G_D12_Descriptor *first;
G_D12_Descriptor *last; G_D12_Descriptor *last;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -154,40 +155,40 @@ Struct(G_D12_DescriptorList)
*/ */
Enum(G_D12_ResourceHeapKind) Enum(G_D12_ResourceHeapKind)
{ {
G_D12_ResourceHeapKind_Gpu, G_D12_ResourceHeapKind_Gpu,
G_D12_ResourceHeapKind_Cpu, G_D12_ResourceHeapKind_Cpu,
G_D12_ResourceHeapKind_CpuWriteCombined, G_D12_ResourceHeapKind_CpuWriteCombined,
G_D12_ResourceHeapKind_Count, G_D12_ResourceHeapKind_Count,
}; };
Struct(G_D12_ResourceHeap) Struct(G_D12_ResourceHeap)
{ {
G_D12_ResourceHeapKind kind; G_D12_ResourceHeapKind kind;
struct GPU_D12_Arena *gpu_arena; struct GPU_D12_Arena *gpu_arena;
ID3D12Heap *d3d_heap; ID3D12Heap *d3d_heap;
ID3D12Resource *d3d_mapped_resource; ID3D12Resource *d3d_mapped_resource;
void *mapped; void *mapped;
G_D12_ResourceList resources; G_D12_ResourceList resources;
G_D12_ResourceList reset_resources; G_D12_ResourceList reset_resources;
u64 pos; u64 pos;
u64 size; u64 size;
}; };
Struct(G_D12_Arena) Struct(G_D12_Arena)
{ {
Arena *arena; Arena *arena;
G_D12_DescriptorList descriptors; G_D12_DescriptorList descriptors;
G_D12_DescriptorList reset_descriptors_by_heap[G_D12_DescriptorHeapKind_Count]; G_D12_DescriptorList reset_descriptors_by_heap[G_D12_DescriptorHeapKind_Count];
G_D12_ResourceList free_resources; G_D12_ResourceList free_resources;
G_D12_ResourceHeap resource_heaps[G_D12_ResourceHeapKind_Count]; G_D12_ResourceHeap resource_heaps[G_D12_ResourceHeapKind_Count];
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -195,32 +196,32 @@ Struct(G_D12_Arena)
Struct(G_D12_StagingRing) Struct(G_D12_StagingRing)
{ {
Arena *arena; Arena *arena;
G_D12_Arena *gpu_arena; G_D12_Arena *gpu_arena;
u64 size; u64 size;
G_D12_Resource *resource; G_D12_Resource *resource;
u8 *base; u8 *base;
struct G_D12_StagingRegionNode *head_region_node; struct G_D12_StagingRegionNode *head_region_node;
struct G_D12_StagingRegionNode *first_free_region_node; struct G_D12_StagingRegionNode *first_free_region_node;
}; };
Struct(G_D12_StagingRegionNode) Struct(G_D12_StagingRegionNode)
{ {
G_D12_StagingRing *ring; G_D12_StagingRing *ring;
/* Ring links (requires ring lock to read) */ /* Ring links (requires ring lock to read) */
G_D12_StagingRegionNode *prev; G_D12_StagingRegionNode *prev;
G_D12_StagingRegionNode *next; G_D12_StagingRegionNode *next;
/* Command list links */ /* Command list links */
G_D12_StagingRegionNode *next_in_command_list; G_D12_StagingRegionNode *next_in_command_list;
/* Region info */ /* Region info */
Atomic64 completion_target; Atomic64 completion_target;
u64 pos; u64 pos;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -228,34 +229,34 @@ Struct(G_D12_StagingRegionNode)
Struct(G_D12_CommandQueueDesc) Struct(G_D12_CommandQueueDesc)
{ {
D3D12_COMMAND_LIST_TYPE type; D3D12_COMMAND_LIST_TYPE type;
D3D12_COMMAND_QUEUE_PRIORITY priority; D3D12_COMMAND_QUEUE_PRIORITY priority;
}; };
Struct(G_D12_Queue) Struct(G_D12_Queue)
{ {
ID3D12CommandQueue *d3d_queue; ID3D12CommandQueue *d3d_queue;
G_D12_CommandQueueDesc desc; G_D12_CommandQueueDesc desc;
Mutex commit_mutex; Mutex commit_mutex;
ID3D12Fence *commit_fence; ID3D12Fence *commit_fence;
u64 commit_fence_target; u64 commit_fence_target;
/* Global resources */ /* Global resources */
u64 print_buffer_size; u64 print_buffer_size;
G_ResourceHandle print_buffer; G_ResourceHandle print_buffer;
G_ResourceHandle print_readback_buffer; G_ResourceHandle print_readback_buffer;
G_RWByteAddressBufferRef print_buffer_ref; G_RWByteAddressBufferRef print_buffer_ref;
/* Raw command lists */ /* Raw command lists */
struct G_D12_RawCommandList *first_committed_cl; struct G_D12_RawCommandList *first_committed_cl;
struct G_D12_RawCommandList *last_committed_cl; struct G_D12_RawCommandList *last_committed_cl;
/* Staging heap */ /* Staging heap */
Mutex staging_mutex; Mutex staging_mutex;
G_D12_StagingRing *staging_ring; G_D12_StagingRing *staging_ring;
Fence sync_fence; Fence sync_fence;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -263,17 +264,17 @@ Struct(G_D12_Queue)
Struct(G_D12_RawCommandList) Struct(G_D12_RawCommandList)
{ {
G_D12_Queue *queue; G_D12_Queue *queue;
G_D12_RawCommandList *next; G_D12_RawCommandList *next;
u64 commit_fence_target; u64 commit_fence_target;
ID3D12CommandAllocator *d3d_ca; ID3D12CommandAllocator *d3d_ca;
ID3D12GraphicsCommandList7 *d3d_cl; ID3D12GraphicsCommandList7 *d3d_cl;
/* Direct queue command lists keep a constant list of CPU-only descriptors */ /* Direct queue command lists keep a constant list of CPU-only descriptors */
G_D12_Descriptor *rtv_descriptors[G_MaxRenderTargets]; G_D12_Descriptor *rtv_descriptors[G_MaxRenderTargets];
G_D12_Descriptor *rtv_clear_descriptor; G_D12_Descriptor *rtv_clear_descriptor;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -283,108 +284,108 @@ Struct(G_D12_RawCommandList)
Enum(G_D12_CmdKind) Enum(G_D12_CmdKind)
{ {
G_D12_CmdKind_None, G_D12_CmdKind_None,
G_D12_CmdKind_Barrier, G_D12_CmdKind_Barrier,
G_D12_CmdKind_Constant, G_D12_CmdKind_Constant,
G_D12_CmdKind_CopyBytes, G_D12_CmdKind_CopyBytes,
G_D12_CmdKind_CopyTexels, G_D12_CmdKind_CopyTexels,
G_D12_CmdKind_Compute, G_D12_CmdKind_Compute,
G_D12_CmdKind_Rasterize, G_D12_CmdKind_Rasterize,
G_D12_CmdKind_ClearRtv, G_D12_CmdKind_ClearRtv,
G_D12_CmdKind_DiscardRtv, G_D12_CmdKind_DiscardRtv,
}; };
Struct(G_D12_Cmd) Struct(G_D12_Cmd)
{ {
G_D12_CmdKind kind; G_D12_CmdKind kind;
b32 skip; b32 skip;
union union
{
struct
{ {
struct i32 slot;
{ u32 value;
i32 slot; } constant;
u32 value;
} constant;
struct struct
{ {
G_MemoryBarrierDesc desc; G_MemoryBarrierDesc desc;
/* Post-batch data */ /* Post-batch data */
b32 is_end_of_batch; b32 is_end_of_batch;
u64 batch_gen; u64 batch_gen;
} barrier; } barrier;
struct struct
{ {
G_D12_Resource *dst; G_D12_Resource *dst;
G_D12_Resource *src; G_D12_Resource *src;
u64 dst_offset; u64 dst_offset;
RngU64 src_range; RngU64 src_range;
} copy_bytes; } copy_bytes;
struct struct
{ {
G_D12_Resource *dst; G_D12_Resource *dst;
G_D12_Resource *src; G_D12_Resource *src;
D3D12_TEXTURE_COPY_LOCATION dst_loc; D3D12_TEXTURE_COPY_LOCATION dst_loc;
D3D12_TEXTURE_COPY_LOCATION src_loc; D3D12_TEXTURE_COPY_LOCATION src_loc;
Vec3I32 dst_texture_offset; Vec3I32 dst_texture_offset;
Rng3I32 src_texture_range; Rng3I32 src_texture_range;
} copy_texels; } copy_texels;
struct struct
{ {
ComputeShader cs; ComputeShader cs;
Vec3I32 groups; Vec3I32 groups;
} compute; } compute;
struct struct
{ {
VertexShader vs; VertexShader vs;
PixelShader ps; PixelShader ps;
u32 instances_count; u32 instances_count;
G_IndexBufferDesc index_buffer_desc; G_IndexBufferDesc index_buffer_desc;
G_D12_Resource *render_targets[G_MaxRenderTargets]; G_D12_Resource *render_targets[G_MaxRenderTargets];
Rng3 viewport; Rng3 viewport;
Rng2 scissor; Rng2 scissor;
G_RasterMode mode; G_RasterMode mode;
} rasterize; } rasterize;
struct struct
{ {
G_D12_Resource *render_target; G_D12_Resource *render_target;
Vec4 color; Vec4 color;
} clear_rtv; } clear_rtv;
struct struct
{ {
G_D12_Resource *render_target; G_D12_Resource *render_target;
} discard_rtv; } discard_rtv;
}; };
}; };
Struct(G_D12_CmdChunk) Struct(G_D12_CmdChunk)
{ {
G_D12_CmdChunk *next; G_D12_CmdChunk *next;
struct G_D12_CmdList *cl; struct G_D12_CmdList *cl;
G_D12_Cmd *cmds; G_D12_Cmd *cmds;
u64 cmds_count; u64 cmds_count;
}; };
Struct(G_D12_CmdList) Struct(G_D12_CmdList)
{ {
G_D12_CmdList *next; G_D12_CmdList *next;
G_QueueKind queue_kind; G_QueueKind queue_kind;
G_D12_DescriptorList reset_descriptors; G_D12_DescriptorList reset_descriptors;
G_D12_StagingRegionNode *first_staging_region; G_D12_StagingRegionNode *first_staging_region;
G_D12_StagingRegionNode *last_staging_region; G_D12_StagingRegionNode *last_staging_region;
G_D12_CmdChunk *first_cmd_chunk; G_D12_CmdChunk *first_cmd_chunk;
G_D12_CmdChunk *last_cmd_chunk; G_D12_CmdChunk *last_cmd_chunk;
u64 chunks_count; u64 chunks_count;
u64 cmds_count; u64 cmds_count;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -393,17 +394,17 @@ Struct(G_D12_CmdList)
Struct(G_D12_Swapchain) Struct(G_D12_Swapchain)
{ {
IDXGISwapChain3 *d3d_swapchain; IDXGISwapChain3 *d3d_swapchain;
HWND window_hwnd; HWND window_hwnd;
HANDLE waitable; HANDLE waitable;
HANDLE present_event; HANDLE present_event;
ID3D12Fence *present_fence; ID3D12Fence *present_fence;
u64 present_fence_target; u64 present_fence_target;
G_Format backbuffers_format; G_Format backbuffers_format;
Vec2I32 backbuffers_resolution; Vec2I32 backbuffers_resolution;
G_D12_Resource backbuffers[G_D12_SwapchainBufferCount]; G_D12_Resource backbuffers[G_D12_SwapchainBufferCount];
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -411,45 +412,45 @@ Struct(G_D12_Swapchain)
Struct(G_D12_SharedState) Struct(G_D12_SharedState)
{ {
Atomic64Padded resource_creation_gen; Atomic64Padded resource_creation_gen;
/* Stats */ /* Stats */
Atomic64 driver_resources_allocated; Atomic64 driver_resources_allocated;
Atomic64 driver_descriptors_allocated; Atomic64 driver_descriptors_allocated;
/* Queues */ /* Queues */
G_D12_Queue queues[G_NumQueues]; G_D12_Queue queues[G_NumQueues];
/* Descriptor heaps */ /* Descriptor heaps */
G_D12_DescriptorHeap descriptor_heaps[G_D12_DescriptorHeapKind_Count]; G_D12_DescriptorHeap descriptor_heaps[G_D12_DescriptorHeapKind_Count];
/* Rootsig */ /* Rootsig */
ID3D12RootSignature *bindless_rootsig; ID3D12RootSignature *bindless_rootsig;
/* Pipelines */ /* Pipelines */
G_D12_PipelineBin pipeline_bins[1024]; G_D12_PipelineBin pipeline_bins[1024];
/* Command lists */ /* Command lists */
Mutex free_cmd_lists_mutex; Mutex free_cmd_lists_mutex;
G_D12_CmdList *first_free_cmd_list; G_D12_CmdList *first_free_cmd_list;
/* Command chunks */ /* Command chunks */
Mutex free_cmd_chunks_mutex; Mutex free_cmd_chunks_mutex;
G_D12_CmdChunk *first_free_cmd_chunk; G_D12_CmdChunk *first_free_cmd_chunk;
/* Swapchains */ /* Swapchains */
Mutex free_swapchains_mutex; Mutex free_swapchains_mutex;
G_D12_Swapchain *first_free_swapchain; G_D12_Swapchain *first_free_swapchain;
/* Device */ /* Device */
IDXGIFactory6 *factory; IDXGIFactory6 *factory;
IDXGIAdapter3 *adapter; IDXGIAdapter3 *adapter;
ID3D12Device10 *device; ID3D12Device10 *device;
} extern G_D12_shared_state; } extern G_D12_shared_state;
Struct(G_D12_ThreadLocalState) Struct(G_D12_ThreadLocalState)
{ {
HANDLE sync_event; HANDLE sync_event;
} extern ThreadLocal G_D12_tl; } extern ThreadLocal G_D12_tl;
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////

View File

@ -3,17 +3,17 @@
Enum(G_RefKind) Enum(G_RefKind)
{ {
G_RefKind_StructuredBuffer, G_RefKind_StructuredBuffer,
G_RefKind_RWStructuredBuffer, G_RefKind_RWStructuredBuffer,
G_RefKind_ByteAddressBuffer, G_RefKind_ByteAddressBuffer,
G_RefKind_RWByteAddressBuffer, G_RefKind_RWByteAddressBuffer,
G_RefKind_Texture1D, G_RefKind_Texture1D,
G_RefKind_RWTexture1D, G_RefKind_RWTexture1D,
G_RefKind_Texture2D, G_RefKind_Texture2D,
G_RefKind_RWTexture2D, G_RefKind_RWTexture2D,
G_RefKind_Texture3D, G_RefKind_Texture3D,
G_RefKind_RWTexture3D, G_RefKind_RWTexture3D,
G_RefKind_SamplerState, G_RefKind_SamplerState,
}; };
Struct(G_StructuredBufferRef) { u32 v; }; Struct(G_StructuredBufferRef) { u32 v; };
@ -43,56 +43,56 @@ Struct(G_SamplerStateRef) { u32 v; };
#define G_NumConstants (G_NumGeneralPurposeConstants + G_NumReservedConstants) #define G_NumConstants (G_NumGeneralPurposeConstants + G_NumReservedConstants)
#if IsLanguageC #if IsLanguageC
#define G_ForceDeclConstant(type, name, slot) \ #define G_ForceDeclConstant(type, name, slot) \
Enum(name##__shaderconstantenum) { name = slot }; \ Enum(name##__shaderconstantenum) { name = slot }; \
Struct(name##__shaderconstanttype) { type v; } Struct(name##__shaderconstanttype) { type v; }
#define G_DeclConstant(type, name, slot) \ #define G_DeclConstant(type, name, slot) \
StaticAssert(sizeof(type) <= 4); \ StaticAssert(sizeof(type) <= 4); \
StaticAssert(slot < G_NumGeneralPurposeConstants); \ StaticAssert(slot < G_NumGeneralPurposeConstants); \
G_ForceDeclConstant(type, name, slot) G_ForceDeclConstant(type, name, slot)
#elif IsLanguageG #elif IsLanguageG
#define G_ForceDeclConstant(type, name, slot) cbuffer name : register(b##slot) { type name; } #define G_ForceDeclConstant(type, name, slot) cbuffer name : register(b##slot) { type name; }
#define G_DeclConstant(type, name, slot) G_ForceDeclConstant(type, name, slot) #define G_DeclConstant(type, name, slot) G_ForceDeclConstant(type, name, slot)
#endif #endif
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Resource dereference //~ Resource dereference
#if IsLanguageG #if IsLanguageG
/* TODO: Non-uniform resource access currently is assumed as the default /* TODO: Non-uniform resource access currently is assumed as the default
* behavior. We may want to add explicit "uniform" variants for * behavior. We may want to add explicit "uniform" variants for
* optimization on amd in the future. */ * optimization on amd in the future. */
template<typename T> StructuredBuffer<T> G_Dereference(G_StructuredBufferRef r) { return ResourceDescriptorHeap[NonUniformResourceIndex(r.v)]; } template<typename T> StructuredBuffer<T> G_Dereference(G_StructuredBufferRef r) { return ResourceDescriptorHeap[NonUniformResourceIndex(r.v)]; }
template<typename T> RWStructuredBuffer<T> G_Dereference(G_RWStructuredBufferRef r) { return ResourceDescriptorHeap[NonUniformResourceIndex(r.v)]; } template<typename T> RWStructuredBuffer<T> G_Dereference(G_RWStructuredBufferRef r) { return ResourceDescriptorHeap[NonUniformResourceIndex(r.v)]; }
ByteAddressBuffer G_Dereference(G_ByteAddressBufferRef r) { return ResourceDescriptorHeap[NonUniformResourceIndex(r.v)]; } ByteAddressBuffer G_Dereference(G_ByteAddressBufferRef r) { return ResourceDescriptorHeap[NonUniformResourceIndex(r.v)]; }
RWByteAddressBuffer G_Dereference(G_RWByteAddressBufferRef r) { return ResourceDescriptorHeap[NonUniformResourceIndex(r.v)]; } RWByteAddressBuffer G_Dereference(G_RWByteAddressBufferRef r) { return ResourceDescriptorHeap[NonUniformResourceIndex(r.v)]; }
template<typename T> Texture1D<T> G_Dereference(G_Texture1DRef r) { return ResourceDescriptorHeap[NonUniformResourceIndex(r.v)]; } template<typename T> Texture1D<T> G_Dereference(G_Texture1DRef r) { return ResourceDescriptorHeap[NonUniformResourceIndex(r.v)]; }
template<typename T> Texture2D<T> G_Dereference(G_Texture2DRef r) { return ResourceDescriptorHeap[NonUniformResourceIndex(r.v)]; } template<typename T> Texture2D<T> G_Dereference(G_Texture2DRef r) { return ResourceDescriptorHeap[NonUniformResourceIndex(r.v)]; }
template<typename T> Texture3D<T> G_Dereference(G_Texture3DRef r) { return ResourceDescriptorHeap[NonUniformResourceIndex(r.v)]; } template<typename T> Texture3D<T> G_Dereference(G_Texture3DRef r) { return ResourceDescriptorHeap[NonUniformResourceIndex(r.v)]; }
template<typename T> RWTexture1D<T> G_Dereference(G_RWTexture1DRef r) { return ResourceDescriptorHeap[NonUniformResourceIndex(r.v)]; } template<typename T> RWTexture1D<T> G_Dereference(G_RWTexture1DRef r) { return ResourceDescriptorHeap[NonUniformResourceIndex(r.v)]; }
template<typename T> RWTexture2D<T> G_Dereference(G_RWTexture2DRef r) { return ResourceDescriptorHeap[NonUniformResourceIndex(r.v)]; } template<typename T> RWTexture2D<T> G_Dereference(G_RWTexture2DRef r) { return ResourceDescriptorHeap[NonUniformResourceIndex(r.v)]; }
template<typename T> RWTexture3D<T> G_Dereference(G_RWTexture3DRef r) { return ResourceDescriptorHeap[NonUniformResourceIndex(r.v)]; } template<typename T> RWTexture3D<T> G_Dereference(G_RWTexture3DRef r) { return ResourceDescriptorHeap[NonUniformResourceIndex(r.v)]; }
SamplerState G_Dereference(G_SamplerStateRef r) { return SamplerDescriptorHeap[NonUniformResourceIndex(r.v)]; } SamplerState G_Dereference(G_SamplerStateRef r) { return SamplerDescriptorHeap[NonUniformResourceIndex(r.v)]; }
#endif #endif
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Size helpers //~ Size helpers
#if IsLanguageG #if IsLanguageG
template<typename T> u32 countof(StructuredBuffer<T> buff) { u32 result; buff.GetDimensions(result); return result; } template<typename T> u32 countof(StructuredBuffer<T> buff) { u32 result; buff.GetDimensions(result); return result; }
template<typename T> u32 countof(RWStructuredBuffer<T> buff) { u32 result; buff.GetDimensions(result); return result; } template<typename T> u32 countof(RWStructuredBuffer<T> buff) { u32 result; buff.GetDimensions(result); return result; }
u32 countof(ByteAddressBuffer buff) { u32 result; buff.GetDimensions(result); return result; } u32 countof(ByteAddressBuffer buff) { u32 result; buff.GetDimensions(result); return result; }
u32 countof(RWByteAddressBuffer buff) { u32 result; buff.GetDimensions(result); return result; } u32 countof(RWByteAddressBuffer buff) { u32 result; buff.GetDimensions(result); return result; }
u32 countof(Texture1D tex) { u32 result; tex.GetDimensions(result); return result; } u32 countof(Texture1D tex) { u32 result; tex.GetDimensions(result); return result; }
template<typename T> u32 countof(RWTexture1D<T> tex) { u32 result; tex.GetDimensions(result); return result; } template<typename T> u32 countof(RWTexture1D<T> tex) { u32 result; tex.GetDimensions(result); return result; }
Vec2U32 countof(Texture2D tex) { Vec2U32 result; tex.GetDimensions(result.x, result.y); return result; } Vec2U32 countof(Texture2D tex) { Vec2U32 result; tex.GetDimensions(result.x, result.y); return result; }
template<typename T> Vec2U32 countof(RWTexture2D<T> tex) { Vec2U32 result; tex.GetDimensions(result.x, result.y); return result; } template<typename T> Vec2U32 countof(RWTexture2D<T> tex) { Vec2U32 result; tex.GetDimensions(result.x, result.y); return result; }
Vec3U32 countof(Texture3D tex) { Vec3U32 result; tex.GetDimensions(result.x, result.y, result.z); return result; } Vec3U32 countof(Texture3D tex) { Vec3U32 result; tex.GetDimensions(result.x, result.y, result.z); return result; }
template<typename T> Vec3U32 countof(RWTexture3D<T> tex) { Vec3U32 result; tex.GetDimensions(result.x, result.y, result.z); return result; } template<typename T> Vec3U32 countof(RWTexture3D<T> tex) { Vec3U32 result; tex.GetDimensions(result.x, result.y, result.z); return result; }
#endif #endif
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -111,196 +111,196 @@ G_ForceDeclConstant(G_RWByteAddressBufferRef, G_ShaderConst_PrintBufferRef, 8)
Enum(G_FmtArgKind) Enum(G_FmtArgKind)
{ {
G_FmtArgKind_None, G_FmtArgKind_None,
G_FmtArgKind_End, G_FmtArgKind_End,
G_FmtArgKind_BEGINSIZE1, G_FmtArgKind_BEGINSIZE1,
G_FmtArgKind_Uint, G_FmtArgKind_Uint,
G_FmtArgKind_Sint, G_FmtArgKind_Sint,
G_FmtArgKind_Float, G_FmtArgKind_Float,
G_FmtArgKind_BEGINSIZE2, G_FmtArgKind_BEGINSIZE2,
G_FmtArgKind_Uint2, G_FmtArgKind_Uint2,
G_FmtArgKind_Sint2, G_FmtArgKind_Sint2,
G_FmtArgKind_Float2, G_FmtArgKind_Float2,
G_FmtArgKind_BEGINSIZE3, G_FmtArgKind_BEGINSIZE3,
G_FmtArgKind_Uint3, G_FmtArgKind_Uint3,
G_FmtArgKind_Sint3, G_FmtArgKind_Sint3,
G_FmtArgKind_Float3, G_FmtArgKind_Float3,
G_FmtArgKind_BEGINSIZE4, G_FmtArgKind_BEGINSIZE4,
G_FmtArgKind_Uint4, G_FmtArgKind_Uint4,
G_FmtArgKind_Sint4, G_FmtArgKind_Sint4,
G_FmtArgKind_Float4, G_FmtArgKind_Float4,
}; };
Struct(G_FmtArg) Struct(G_FmtArg)
{ {
G_FmtArgKind kind; G_FmtArgKind kind;
Vec4U32 v; Vec4U32 v;
}; };
#if IsLanguageG && GPU_SHADER_PRINT #if IsLanguageG && GPU_SHADER_PRINT
G_FmtArg G_Fmt(u32 v) { G_FmtArg result; result.kind = G_FmtArgKind_Uint; result.v.x = v; return result; } G_FmtArg G_Fmt(u32 v) { G_FmtArg result; result.kind = G_FmtArgKind_Uint; result.v.x = v; return result; }
G_FmtArg G_Fmt(Vec2U32 v) { G_FmtArg result; result.kind = G_FmtArgKind_Uint2; result.v.xy = v.xy; return result; } G_FmtArg G_Fmt(Vec2U32 v) { G_FmtArg result; result.kind = G_FmtArgKind_Uint2; result.v.xy = v.xy; return result; }
G_FmtArg G_Fmt(Vec3U32 v) { G_FmtArg result; result.kind = G_FmtArgKind_Uint3; result.v.xyz = v.xyz; return result; } G_FmtArg G_Fmt(Vec3U32 v) { G_FmtArg result; result.kind = G_FmtArgKind_Uint3; result.v.xyz = v.xyz; return result; }
G_FmtArg G_Fmt(Vec4U32 v) { G_FmtArg result; result.kind = G_FmtArgKind_Uint4; result.v.xyzw = v.xyzw; return result; } G_FmtArg G_Fmt(Vec4U32 v) { G_FmtArg result; result.kind = G_FmtArgKind_Uint4; result.v.xyzw = v.xyzw; return result; }
G_FmtArg G_Fmt(i32 v) { G_FmtArg result; result.kind = G_FmtArgKind_Sint; result.v.x = v; return result; } G_FmtArg G_Fmt(i32 v) { G_FmtArg result; result.kind = G_FmtArgKind_Sint; result.v.x = v; return result; }
G_FmtArg G_Fmt(Vec2I32 v) { G_FmtArg result; result.kind = G_FmtArgKind_Sint2; result.v.xy = v.xy; return result; } G_FmtArg G_Fmt(Vec2I32 v) { G_FmtArg result; result.kind = G_FmtArgKind_Sint2; result.v.xy = v.xy; return result; }
G_FmtArg G_Fmt(Vec3I32 v) { G_FmtArg result; result.kind = G_FmtArgKind_Sint3; result.v.xyz = v.xyz; return result; } G_FmtArg G_Fmt(Vec3I32 v) { G_FmtArg result; result.kind = G_FmtArgKind_Sint3; result.v.xyz = v.xyz; return result; }
G_FmtArg G_Fmt(Vec4I32 v) { G_FmtArg result; result.kind = G_FmtArgKind_Sint4; result.v.xyzw = v.xyzw; return result; } G_FmtArg G_Fmt(Vec4I32 v) { G_FmtArg result; result.kind = G_FmtArgKind_Sint4; result.v.xyzw = v.xyzw; return result; }
G_FmtArg G_Fmt(f32 v) { G_FmtArg result; result.kind = G_FmtArgKind_Float; result.v.x = asuint(v); return result; } G_FmtArg G_Fmt(f32 v) { G_FmtArg result; result.kind = G_FmtArgKind_Float; result.v.x = asuint(v); return result; }
G_FmtArg G_Fmt(Vec2 v) { G_FmtArg result; result.kind = G_FmtArgKind_Float2; result.v.xy = asuint(v.xy); return result; } G_FmtArg G_Fmt(Vec2 v) { G_FmtArg result; result.kind = G_FmtArgKind_Float2; result.v.xy = asuint(v.xy); return result; }
G_FmtArg G_Fmt(Vec3 v) { G_FmtArg result; result.kind = G_FmtArgKind_Float3; result.v.xyz = asuint(v.xyz); return result; } G_FmtArg G_Fmt(Vec3 v) { G_FmtArg result; result.kind = G_FmtArgKind_Float3; result.v.xyz = asuint(v.xyz); return result; }
G_FmtArg G_Fmt(Vec4 v) { G_FmtArg result; result.kind = G_FmtArgKind_Float4; result.v.xyzw = asuint(v.xyzw); return result; } G_FmtArg G_Fmt(Vec4 v) { G_FmtArg result; result.kind = G_FmtArgKind_Float4; result.v.xyzw = asuint(v.xyzw); return result; }
G_FmtArg G_FmtEnd(void) { G_FmtArg result; result.kind = G_FmtArgKind_End; return result; } G_FmtArg G_FmtEnd(void) { G_FmtArg result; result.kind = G_FmtArgKind_End; return result; }
Struct(G_TempPrintBuffer) Struct(G_TempPrintBuffer)
{
/* NOTE: The larger the array size, the longer the compilation time */
u32 byte_chunks[64];
u32 bytes_count;
u32 chars_count;
u32 args_count;
b32 overflowed;
};
void G_PushPrintByte(inout G_TempPrintBuffer buff, u32 v)
{
u32 chunk_idx = buff.bytes_count / 4;
if (chunk_idx < countof(buff.byte_chunks))
{ {
/* NOTE: The larger the array size, the longer the compilation time */ u32 byte_idx_in_chunk = buff.bytes_count & 0x03;
u32 byte_chunks[64]; if (byte_idx_in_chunk == 0)
u32 bytes_count; {
u32 chars_count; /* Since buff is not zero initialized, we set the chunk on first write here */
u32 args_count; buff.byte_chunks[chunk_idx] = v & 0xFF;
b32 overflowed; }
}; else
{
void G_PushPrintByte(inout G_TempPrintBuffer buff, u32 v) buff.byte_chunks[chunk_idx] |= (v & 0xFF) << (byte_idx_in_chunk * 8);
}
buff.bytes_count += 1;
}
else
{ {
u32 chunk_idx = buff.bytes_count / 4; buff.overflowed = 1;
if (chunk_idx < countof(buff.byte_chunks)) }
{ }
u32 byte_idx_in_chunk = buff.bytes_count & 0x03;
if (byte_idx_in_chunk == 0) void G_CommitPrint(G_TempPrintBuffer buff)
{ {
/* Since buff is not zero initialized, we set the chunk on first write here */ RWByteAddressBuffer rw = G_Dereference(G_ShaderConst_PrintBufferRef);
buff.byte_chunks[chunk_idx] = v & 0xFF;
} if (buff.overflowed)
else {
{ buff.bytes_count = 0;
buff.byte_chunks[chunk_idx] |= (v & 0xFF) << (byte_idx_in_chunk * 8); buff.chars_count = 0;
} buff.args_count = 0;
buff.bytes_count += 1;
}
else
{
buff.overflowed = 1;
}
} }
void G_CommitPrint(G_TempPrintBuffer buff) u32 chunks_count = (buff.bytes_count + 3) / 4;
u32 alloc_size = 0;
alloc_size += 4; /* Header */
alloc_size += chunks_count * 4; /* Chunks */
/* Atomic fetch + add to base counter */
u32 base;
rw.InterlockedAdd(0, alloc_size, base);
base += 4; /* Offset for allocation counter */
base += 4; /* Offset for success counter */
base += 4; /* Offset for overflow counter */
if ((base + alloc_size) < countof(rw))
{ {
RWByteAddressBuffer rw = G_Dereference(G_ShaderConst_PrintBufferRef); /* Increment success counter */
rw.InterlockedAdd(4, 1);
u32 pos = 0;
if (buff.overflowed) /* Write header */
{ {
buff.bytes_count = 0; u32 header = 0;
buff.chars_count = 0; header |= (buff.chars_count << 0) & 0x0000FFFF;
buff.args_count = 0; header |= (buff.args_count << 16) & 0x7FFF0000;
} header |= (buff.overflowed << 31) & 0xF0000000;
rw.Store(base + pos, header);
pos += 4;
}
u32 chunks_count = (buff.bytes_count + 3) / 4; /* Write chunks */
u32 alloc_size = 0; for (u32 chunk_idx = 0; chunk_idx < chunks_count; ++chunk_idx)
alloc_size += 4; /* Header */ {
alloc_size += chunks_count * 4; /* Chunks */ u32 chunk = buff.byte_chunks[chunk_idx];
rw.Store(base + pos, chunk);
/* Atomic fetch + add to base counter */ pos += 4;
u32 base; }
rw.InterlockedAdd(0, alloc_size, base);
base += 4; /* Offset for allocation counter */
base += 4; /* Offset for success counter */
base += 4; /* Offset for overflow counter */
if ((base + alloc_size) < countof(rw))
{
/* Increment success counter */
rw.InterlockedAdd(4, 1);
u32 pos = 0;
/* Write header */
{
u32 header = 0;
header |= (buff.chars_count << 0) & 0x0000FFFF;
header |= (buff.args_count << 16) & 0x7FFF0000;
header |= (buff.overflowed << 31) & 0xF0000000;
rw.Store(base + pos, header);
pos += 4;
}
/* Write chunks */
for (u32 chunk_idx = 0; chunk_idx < chunks_count; ++chunk_idx)
{
u32 chunk = buff.byte_chunks[chunk_idx];
rw.Store(base + pos, chunk);
pos += 4;
}
}
else
{
/* Increment overflow counter */
rw.InterlockedAdd(8, 1);
}
} }
else
{
/* Increment overflow counter */
rw.InterlockedAdd(8, 1);
}
}
#define G_PrintF_(fmt, ...) do { \ #define G_PrintF_(fmt, ...) do { \
G_TempPrintBuffer __tmp; \ G_TempPrintBuffer __tmp; \
__tmp.bytes_count = 0; \ __tmp.bytes_count = 0; \
__tmp.overflowed = 0; \ __tmp.overflowed = 0; \
u32 __char_idx = 0; \ u32 __char_idx = 0; \
while (U32FromChar(fmt[__char_idx]) != 0) \ while (U32FromChar(fmt[__char_idx]) != 0) \
{ \ { \
G_PushPrintByte(__tmp, U32FromChar(fmt[__char_idx])); \ G_PushPrintByte(__tmp, U32FromChar(fmt[__char_idx])); \
++__char_idx; \ ++__char_idx; \
} \ } \
G_FmtArg __args[] = { __VA_ARGS__ }; \ G_FmtArg __args[] = { __VA_ARGS__ }; \
__tmp.chars_count = __char_idx; \ __tmp.chars_count = __char_idx; \
__tmp.args_count = (countof(__args) - 1); \ __tmp.args_count = (countof(__args) - 1); \
for (u32 __arg_idx = 0; __arg_idx < __tmp.args_count; ++__arg_idx) \ for (u32 __arg_idx = 0; __arg_idx < __tmp.args_count; ++__arg_idx) \
{ \ { \
G_FmtArg __arg = __args[__arg_idx]; \ G_FmtArg __arg = __args[__arg_idx]; \
G_PushPrintByte(__tmp, __arg.kind); \ G_PushPrintByte(__tmp, __arg.kind); \
if (__arg.kind > G_FmtArgKind_BEGINSIZE1) \ if (__arg.kind > G_FmtArgKind_BEGINSIZE1) \
{ \ { \
G_PushPrintByte(__tmp, __arg.v.x >> 0); \ G_PushPrintByte(__tmp, __arg.v.x >> 0); \
G_PushPrintByte(__tmp, __arg.v.x >> 8); \ G_PushPrintByte(__tmp, __arg.v.x >> 8); \
G_PushPrintByte(__tmp, __arg.v.x >> 16); \ G_PushPrintByte(__tmp, __arg.v.x >> 16); \
G_PushPrintByte(__tmp, __arg.v.x >> 24); \ G_PushPrintByte(__tmp, __arg.v.x >> 24); \
} \ } \
if (__arg.kind > G_FmtArgKind_BEGINSIZE2) \ if (__arg.kind > G_FmtArgKind_BEGINSIZE2) \
{ \ { \
G_PushPrintByte(__tmp, __arg.v.y >> 0); \ G_PushPrintByte(__tmp, __arg.v.y >> 0); \
G_PushPrintByte(__tmp, __arg.v.y >> 8); \ G_PushPrintByte(__tmp, __arg.v.y >> 8); \
G_PushPrintByte(__tmp, __arg.v.y >> 16); \ G_PushPrintByte(__tmp, __arg.v.y >> 16); \
G_PushPrintByte(__tmp, __arg.v.y >> 24); \ G_PushPrintByte(__tmp, __arg.v.y >> 24); \
} \ } \
if (__arg.kind > G_FmtArgKind_BEGINSIZE3) \ if (__arg.kind > G_FmtArgKind_BEGINSIZE3) \
{ \ { \
G_PushPrintByte(__tmp, __arg.v.z >> 0); \ G_PushPrintByte(__tmp, __arg.v.z >> 0); \
G_PushPrintByte(__tmp, __arg.v.z >> 8); \ G_PushPrintByte(__tmp, __arg.v.z >> 8); \
G_PushPrintByte(__tmp, __arg.v.z >> 16); \ G_PushPrintByte(__tmp, __arg.v.z >> 16); \
G_PushPrintByte(__tmp, __arg.v.z >> 24); \ G_PushPrintByte(__tmp, __arg.v.z >> 24); \
} \ } \
if (__arg.kind > G_FmtArgKind_BEGINSIZE4) \ if (__arg.kind > G_FmtArgKind_BEGINSIZE4) \
{ \ { \
G_PushPrintByte(__tmp, __arg.v.w >> 0); \ G_PushPrintByte(__tmp, __arg.v.w >> 0); \
G_PushPrintByte(__tmp, __arg.v.w >> 8); \ G_PushPrintByte(__tmp, __arg.v.w >> 8); \
G_PushPrintByte(__tmp, __arg.v.w >> 16); \ G_PushPrintByte(__tmp, __arg.v.w >> 16); \
G_PushPrintByte(__tmp, __arg.v.w >> 24); \ G_PushPrintByte(__tmp, __arg.v.w >> 24); \
} \ } \
} \ } \
G_CommitPrint(__tmp); \ G_CommitPrint(__tmp); \
} while (0) } while (0)
#define G_PrintF(fmt, ...) G_PrintF_(fmt, ##__VA_ARGS__, G_FmtEnd()) #define G_PrintF(fmt, ...) G_PrintF_(fmt, ##__VA_ARGS__, G_FmtEnd())
#else #else
#define G_PrintF(fmt) #define G_PrintF(fmt)
#endif #endif

File diff suppressed because it is too large Load Diff

View File

@ -3,126 +3,126 @@
Enum(JSON_Type) Enum(JSON_Type)
{ {
JSON_Type_Null, JSON_Type_Null,
JSON_Type_Bool, JSON_Type_Bool,
JSON_Type_Number, JSON_Type_Number,
JSON_Type_String, JSON_Type_String,
JSON_Type_Array, JSON_Type_Array,
JSON_Type_Object JSON_Type_Object
}; };
Struct(JSON_Blob) Struct(JSON_Blob)
{ {
JSON_Type type; JSON_Type type;
String key; String key;
JSON_Blob *parent; JSON_Blob *parent;
JSON_Blob *next; JSON_Blob *next;
JSON_Blob *child_first; JSON_Blob *child_first;
JSON_Blob *child_last; JSON_Blob *child_last;
union union
{ {
String string; String string;
f64 number; f64 number;
b32 boolean; b32 boolean;
} value; } value;
}; };
Struct(JSON_Error) Struct(JSON_Error)
{ {
String msg; String msg;
u64 start; u64 start;
u64 end; u64 end;
JSON_Error *next; JSON_Error *next;
}; };
Struct(JSON_ErrorList) Struct(JSON_ErrorList)
{ {
u64 count; u64 count;
JSON_Error *first; JSON_Error *first;
JSON_Error *last; JSON_Error *last;
}; };
Struct(JSON_Result) Struct(JSON_Result)
{ {
JSON_Blob *root; JSON_Blob *root;
JSON_ErrorList errors; JSON_ErrorList errors;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Lexer types //~ Lexer types
#define JSON_Case_Newline \ #define JSON_Case_Newline \
0x0A: /* Line feed or New line */ \ 0x0A: /* Line feed or New line */ \
case 0x0D /* Carriage return */ case 0x0D /* Carriage return */
#define JSON_Case_Space \ #define JSON_Case_Space \
0x20: /* Space */ \ 0x20: /* Space */ \
case 0x09 /* Horizontal tab */ case 0x09 /* Horizontal tab */
#define JSON_Case_Digit0Through9 \ #define JSON_Case_Digit0Through9 \
'0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9' '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9'
#define JSON_Case_Digit1Through9 \ #define JSON_Case_Digit1Through9 \
'1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9' '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9'
#define JSON_Case_Symbol \ #define JSON_Case_Symbol \
',': case ':': case '[': case ']': case '{': case '}' ',': case ':': case '[': case ']': case '{': case '}'
Enum(JSON_TokenKind) Enum(JSON_TokenKind)
{ {
JSON_TokenKind_Unknown, JSON_TokenKind_Unknown,
JSON_TokenKind_Number, JSON_TokenKind_Number,
JSON_TokenKind_String, JSON_TokenKind_String,
JSON_TokenKind_KeywordTrue, JSON_TokenKind_KeywordTrue,
JSON_TokenKind_KeywordFalse, JSON_TokenKind_KeywordFalse,
JSON_TokenKind_KeywordNull, JSON_TokenKind_KeywordNull,
JSON_TokenKind_Comma, JSON_TokenKind_Comma,
JSON_TokenKind_Colon, JSON_TokenKind_Colon,
JSON_TokenKind_SquareBraceOpen, JSON_TokenKind_SquareBraceOpen,
JSON_TokenKind_SquareBraceClose, JSON_TokenKind_SquareBraceClose,
JSON_TokenKind_CurlyBraceOpen, JSON_TokenKind_CurlyBraceOpen,
JSON_TokenKind_CurlyBraceClose, JSON_TokenKind_CurlyBraceClose,
JSON_TokenKind_Bof, JSON_TokenKind_Bof,
JSON_TokenKind_Eof JSON_TokenKind_Eof
}; };
Struct(JSON_Token) Struct(JSON_Token)
{ {
JSON_TokenKind kind; JSON_TokenKind kind;
u64 start; u64 start;
u64 end; u64 end;
JSON_Token *next; JSON_Token *next;
}; };
Struct(JSON_TokenList) Struct(JSON_TokenList)
{ {
JSON_Token *token_first; JSON_Token *token_first;
JSON_Token *token_last; JSON_Token *token_last;
}; };
Enum(JSON_LexNumberState) Enum(JSON_LexNumberState)
{ {
JSON_LexNumberState_Whole, JSON_LexNumberState_Whole,
JSON_LexNumberState_Fraction, JSON_LexNumberState_Fraction,
JSON_LexNumberState_Exponent JSON_LexNumberState_Exponent
}; };
Global Readonly String JSON_keyword_strings[] = { Global Readonly String JSON_keyword_strings[] = {
['t'] = CompLit("true"), ['t'] = CompLit("true"),
['f'] = CompLit("false"), ['f'] = CompLit("false"),
['n'] = CompLit("null") ['n'] = CompLit("null")
}; };
Global Readonly JSON_TokenKind JSON_keyword_types[] = { Global Readonly JSON_TokenKind JSON_keyword_types[] = {
['t'] = JSON_TokenKind_KeywordTrue, ['t'] = JSON_TokenKind_KeywordTrue,
['f'] = JSON_TokenKind_KeywordFalse, ['f'] = JSON_TokenKind_KeywordFalse,
['n'] = JSON_TokenKind_KeywordNull ['n'] = JSON_TokenKind_KeywordNull
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -130,13 +130,13 @@ Global Readonly JSON_TokenKind JSON_keyword_types[] = {
Struct(JSON_Parser) Struct(JSON_Parser)
{ {
/* Input */ /* Input */
String src; String src;
JSON_Token *at; JSON_Token *at;
/* Output */ /* Output */
JSON_Blob *root; JSON_Blob *root;
JSON_ErrorList errors; JSON_ErrorList errors;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////

File diff suppressed because it is too large Load Diff

View File

@ -4,43 +4,43 @@
//~ Base layer definitions //~ Base layer definitions
#ifndef IsConsoleApp #ifndef IsConsoleApp
# define IsConsoleApp 1 #define IsConsoleApp 1
#endif #endif
#ifndef IsRtcEnabled #ifndef IsRtcEnabled
# define IsRtcEnabled 1 #define IsRtcEnabled 1
#endif #endif
#ifndef IsUnoptimized #ifndef IsUnoptimized
# define IsUnoptimized 1 #define IsUnoptimized 1
#endif #endif
#ifndef IsAsanEnabled #ifndef IsAsanEnabled
# define IsAsanEnabled 0 #define IsAsanEnabled 0
#endif #endif
#ifndef IsCrtlibEnabled #ifndef IsCrtlibEnabled
# define IsCrtlibEnabled 1 #define IsCrtlibEnabled 1
#endif #endif
#ifndef IsDebinfoEnabled #ifndef IsDebinfoEnabled
# define IsDebinfoEnabled 1 #define IsDebinfoEnabled 1
#endif #endif
#ifndef IsDeveloperModeEnabled #ifndef IsDeveloperModeEnabled
# define IsDeveloperModeEnabled 1 #define IsDeveloperModeEnabled 1
#endif #endif
#ifndef IsUnoptimized #ifndef IsUnoptimized
# define IsUnoptimized 1 #define IsUnoptimized 1
#endif #endif
#ifndef IsTestingEnabled #ifndef IsTestingEnabled
# define IsTestingEnabled 0 #define IsTestingEnabled 0
#endif #endif
#ifndef IsHotSwappingEnabled #ifndef IsHotSwappingEnabled
# define IsHotSwappingEnabled 0 #define IsHotSwappingEnabled 0
#endif #endif
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -60,8 +60,8 @@
Struct(LineCol) Struct(LineCol)
{ {
i64 line; i64 line;
i64 col; i64 col;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -69,109 +69,109 @@ Struct(LineCol)
Struct(CompilerParams) Struct(CompilerParams)
{ {
StringList defs; StringList defs;
StringList warnings_msvc; StringList warnings_msvc;
StringList warnings_clang; StringList warnings_clang;
StringList warnings_dxc; StringList warnings_dxc;
StringList flags_msvc; StringList flags_msvc;
StringList flags_clang; StringList flags_clang;
StringList flags_dxc; StringList flags_dxc;
StringList compiler_only_flags_msvc; StringList compiler_only_flags_msvc;
StringList compiler_only_flags_clang; StringList compiler_only_flags_clang;
StringList linker_only_flags_msvc; StringList linker_only_flags_msvc;
StringList linker_only_flags_clang; StringList linker_only_flags_clang;
}; };
Enum(ShaderEntryKind) Enum(ShaderEntryKind)
{ {
ShaderEntryKind_VS, ShaderEntryKind_VS,
ShaderEntryKind_PS, ShaderEntryKind_PS,
ShaderEntryKind_CS, ShaderEntryKind_CS,
}; };
Struct(ShaderEntry) Struct(ShaderEntry)
{ {
ShaderEntry *next; ShaderEntry *next;
ShaderEntryKind kind; ShaderEntryKind kind;
String name; String name;
}; };
Struct(ResDir) Struct(ResDir)
{ {
ResDir *next; ResDir *next;
String dir_path; String dir_path;
String store_name; String store_name;
}; };
Struct(GpuObj) Struct(GpuObj)
{ {
String output; String output;
i32 return_code; i32 return_code;
}; };
Struct(EmbedObj) Struct(EmbedObj)
{ {
String obj_file; String obj_file;
String output; String output;
i32 return_code; i32 return_code;
}; };
Struct(BuildCtx) Struct(BuildCtx)
{ {
Atomic32 status; Atomic32 status;
M_Layer layers_parse; M_Layer layers_parse;
struct struct
{ {
M_ErrorList errors; M_ErrorList errors;
} c_parse; } c_parse;
struct struct
{ {
M_ErrorList errors; M_ErrorList errors;
ShaderEntry *first_shader_entry; ShaderEntry *first_shader_entry;
ShaderEntry *last_shader_entry; ShaderEntry *last_shader_entry;
u64 shader_entries_count; u64 shader_entries_count;
} gpu_parse; } gpu_parse;
struct struct
{ {
M_ErrorList errors; M_ErrorList errors;
ResDir *first_res_dir; ResDir *first_res_dir;
ResDir *last_res_dir; ResDir *last_res_dir;
u64 res_dirs_count; u64 res_dirs_count;
} res_dir_parse; } res_dir_parse;
struct struct
{ {
String obj_file; String obj_file;
String output; String output;
i32 return_code; i32 return_code;
} c_obj; } c_obj;
struct struct
{ {
GpuObj *array; GpuObj *array;
u32 count; u32 count;
Atomic32 finished_count; Atomic32 finished_count;
} gpu_objs; } gpu_objs;
struct struct
{ {
EmbedObj *array; EmbedObj *array;
u32 count; u32 count;
} embed_objs; } embed_objs;
struct struct
{ {
String output; String output;
i32 return_code; i32 return_code;
} link; } link;
}; };
extern BuildCtx Build; extern BuildCtx Build;

View File

@ -3,82 +3,82 @@
String F_GetFull(Arena *arena, String path) String F_GetFull(Arena *arena, String path)
{ {
return OS_GetFullPath(arena, path); return OS_GetFullPath(arena, path);
} }
String F_GetFullCrossPlatform(Arena *arena, String path) String F_GetFullCrossPlatform(Arena *arena, String path)
{ {
String result = OS_GetFullPath(arena, path); String result = OS_GetFullPath(arena, path);
for (u64 i = 0; i < result.len; ++i) for (u64 i = 0; i < result.len; ++i)
{
if (result.text[i] == '\\')
{ {
if (result.text[i] == '\\') result.text[i] = '/';
{
result.text[i] = '/';
}
} }
return result; }
return result;
} }
String F_GetFileName(String path) String F_GetFileName(String path)
{ {
String result = path; String result = path;
u64 start = path.len; u64 start = path.len;
for (u64 i = path.len; i-- > 0;) for (u64 i = path.len; i-- > 0;)
{
if (path.text[i] == '\\' || path.text[i] == '/')
{ {
if (path.text[i] == '\\' || path.text[i] == '/') start = i + 1;
{ break;
start = i + 1;
break;
}
} }
if (start < path.len) }
{ if (start < path.len)
result.text = &path.text[start]; {
result.len = path.len - start; result.text = &path.text[start];
result.len = path.len - start;
} }
return result; return result;
} }
String F_GetParentDir(String path) String F_GetParentDir(String path)
{ {
String result = Zi; String result = Zi;
result.text = path.text; result.text = path.text;
u64 end = path.len; u64 end = path.len;
for (u64 i = path.len; i-- > 0;) for (u64 i = path.len; i-- > 0;)
{
if (path.text[i] == '\\' || path.text[i] == '/')
{ {
if (path.text[i] == '\\' || path.text[i] == '/') end = i + 1;
{ break;
end = i + 1;
break;
}
} }
if (end < path.len) }
{ if (end < path.len)
result.len = end; {
} result.len = end;
return result; }
return result;
} }
String F_ExtensionFromFile(String path) String F_ExtensionFromFile(String path)
{ {
String result = Zi; String result = Zi;
u64 start = path.len; u64 start = path.len;
for (u64 i = path.len; i-- > 0;) for (u64 i = path.len; i-- > 0;)
{
if (path.text[i] == '.')
{ {
if (path.text[i] == '.') start = i + 1;
{ break;
start = i + 1;
break;
}
} }
if (start < path.len) }
{ if (start < path.len)
result.text = &path.text[start]; {
result.len = path.len - start; result.text = &path.text[start];
result.len = path.len - start;
} }
return result; return result;
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -86,11 +86,11 @@ String F_ExtensionFromFile(String path)
String F_DataFromFile(Arena *arena, String path) String F_DataFromFile(Arena *arena, String path)
{ {
String result = Zi; String result = Zi;
OS_File file = OS_OpenFile(path, OS_FileFlag_Read, I64Max); OS_File file = OS_OpenFile(path, OS_FileFlag_Read, I64Max);
result = OS_ReadEntireFile(arena, file); result = OS_ReadEntireFile(arena, file);
OS_CloseFile(file); OS_CloseFile(file);
return result; return result;
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -98,9 +98,9 @@ String F_DataFromFile(Arena *arena, String path)
void F_ClearWrite(String path, String data) void F_ClearWrite(String path, String data)
{ {
OS_File file = OS_OpenFile(path, OS_FileFlag_Write | OS_FileFlag_Create, I64Max); OS_File file = OS_OpenFile(path, OS_FileFlag_Write | OS_FileFlag_Create, I64Max);
OS_ClearWriteFile(file, data); OS_ClearWriteFile(file, data);
OS_CloseFile(file); OS_CloseFile(file);
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -108,12 +108,12 @@ void F_ClearWrite(String path, String data)
b32 F_IsFile(String path) b32 F_IsFile(String path)
{ {
return OS_FileExists(path); return OS_FileExists(path);
} }
b32 F_IsDir(String path) b32 F_IsDir(String path)
{ {
return OS_DirExists(path); return OS_DirExists(path);
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -121,18 +121,18 @@ b32 F_IsDir(String path)
void F_FilesFromDir(Arena *arena, StringList *list, String dir, F_IterFlag flags) void F_FilesFromDir(Arena *arena, StringList *list, String dir, F_IterFlag flags)
{ {
TempArena scratch = BeginScratch(arena); TempArena scratch = BeginScratch(arena);
StringList tmp = Zi; StringList tmp = Zi;
String dir_full_path = F_GetFull(scratch.arena, dir); String dir_full_path = F_GetFull(scratch.arena, dir);
OS_DirContentsFromFullPath(scratch.arena, &tmp, dir_full_path); OS_DirContentsFromFullPath(scratch.arena, &tmp, dir_full_path);
for (StringListNode *n = tmp.first; n; n = n->next) for (StringListNode *n = tmp.first; n; n = n->next)
{
String file_joined_path = StringF(arena, "%F/%F", FmtString(dir), FmtString(n->s));
PushStringToList(arena, list, file_joined_path);
if (flags & F_IterFlag_Recurse && F_IsDir(file_joined_path))
{ {
String file_joined_path = StringF(arena, "%F/%F", FmtString(dir), FmtString(n->s)); F_FilesFromDir(arena, list, file_joined_path, flags);
PushStringToList(arena, list, file_joined_path);
if (flags & F_IterFlag_Recurse && F_IsDir(file_joined_path))
{
F_FilesFromDir(arena, list, file_joined_path, flags);
}
} }
EndScratch(scratch); }
EndScratch(scratch);
} }

View File

@ -3,8 +3,8 @@
Enum(F_IterFlag) Enum(F_IterFlag)
{ {
F_IterFlag_None = 0, F_IterFlag_None = 0,
F_IterFlag_Recurse = (1 << 0) F_IterFlag_Recurse = (1 << 0)
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////

File diff suppressed because it is too large Load Diff

View File

@ -3,16 +3,16 @@
Struct(M_Error) Struct(M_Error)
{ {
M_Error *next; M_Error *next;
String msg; String msg;
struct M_Token *token; struct M_Token *token;
}; };
Struct(M_ErrorList) Struct(M_ErrorList)
{ {
M_Error *first; M_Error *first;
M_Error *last; M_Error *last;
u64 count; u64 count;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -20,8 +20,8 @@ Struct(M_ErrorList)
Struct(M_File) Struct(M_File)
{ {
String name; String name;
String data; String data;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -29,41 +29,41 @@ Struct(M_File)
Enum(M_TokenKind) Enum(M_TokenKind)
{ {
M_TokenKind_Ident, M_TokenKind_Ident,
M_TokenKind_Eol, /* End of line */ M_TokenKind_Eol, /* End of line */
}; };
Struct(M_Token) Struct(M_Token)
{ {
b32 valid; b32 valid;
M_Token *next; M_Token *next;
M_TokenKind kind; M_TokenKind kind;
struct M_TokenFile *file; struct M_TokenFile *file;
String s; String s;
} extern Readonly M_NilToken; } extern Readonly M_NilToken;
Struct(M_TokenFile) Struct(M_TokenFile)
{ {
b32 valid; b32 valid;
M_TokenFile *next; M_TokenFile *next;
String name; String name;
String data; String data;
M_Token *first_token; M_Token *first_token;
M_Token *last_token; M_Token *last_token;
u64 tokens_count; u64 tokens_count;
M_ErrorList errors; M_ErrorList errors;
} extern Readonly M_NilTokenFile; } extern Readonly M_NilTokenFile;
Struct(M_TokenFileList) Struct(M_TokenFileList)
{ {
M_TokenFile *first; M_TokenFile *first;
M_TokenFile *last; M_TokenFile *last;
u64 count; u64 count;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -71,68 +71,68 @@ Struct(M_TokenFileList)
Enum(M_EntryKind) Enum(M_EntryKind)
{ {
M_EntryKind_Unknown, M_EntryKind_Unknown,
M_EntryKind_Layer, M_EntryKind_Layer,
M_EntryKind_Dep, M_EntryKind_Dep,
M_EntryKind_IncludeC, M_EntryKind_IncludeC,
M_EntryKind_IncludeG, M_EntryKind_IncludeG,
M_EntryKind_DefaultDownstream, M_EntryKind_DefaultDownstream,
M_EntryKind_Bootstrap, M_EntryKind_Bootstrap,
M_EntryKind_VertexShader, M_EntryKind_VertexShader,
M_EntryKind_PixelShader, M_EntryKind_PixelShader,
M_EntryKind_ComputeShader, M_EntryKind_ComputeShader,
M_EntryKind_EmbedDir, M_EntryKind_EmbedDir,
}; };
Enum(M_PlatformKind) Enum(M_PlatformKind)
{ {
M_PlatformKind_Any, M_PlatformKind_Any,
M_PlatformKind_Win32, M_PlatformKind_Win32,
}; };
Global Readonly char *M_entry_kind_rules[] = { Global Readonly char *M_entry_kind_rules[] = {
[M_EntryKind_Layer] = "@Layer", [M_EntryKind_Layer] = "@Layer",
[M_EntryKind_Dep] = "@Dep", [M_EntryKind_Dep] = "@Dep",
[M_EntryKind_IncludeC] = "@IncludeC", [M_EntryKind_IncludeC] = "@IncludeC",
[M_EntryKind_IncludeG] = "@IncludeG", [M_EntryKind_IncludeG] = "@IncludeG",
[M_EntryKind_DefaultDownstream] = "@DefaultDownstream", [M_EntryKind_DefaultDownstream] = "@DefaultDownstream",
[M_EntryKind_Bootstrap] = "@Bootstrap", [M_EntryKind_Bootstrap] = "@Bootstrap",
[M_EntryKind_VertexShader] = "@VertexShader", [M_EntryKind_VertexShader] = "@VertexShader",
[M_EntryKind_PixelShader] = "@PixelShader", [M_EntryKind_PixelShader] = "@PixelShader",
[M_EntryKind_ComputeShader] = "@ComputeShader", [M_EntryKind_ComputeShader] = "@ComputeShader",
[M_EntryKind_EmbedDir] = "@EmbedDir", [M_EntryKind_EmbedDir] = "@EmbedDir",
}; };
Struct(M_Entry) Struct(M_Entry)
{ {
b32 valid; b32 valid;
M_Entry *next; M_Entry *next;
M_EntryKind kind; M_EntryKind kind;
M_Token *name_token; M_Token *name_token;
M_Token *arg_tokens[2]; M_Token *arg_tokens[2];
u64 args_count; u64 args_count;
} extern Readonly M_NilEntry; } extern Readonly M_NilEntry;
Struct(M_Layer) Struct(M_Layer)
{ {
b32 valid; b32 valid;
M_Layer *next; M_Layer *next;
M_TokenFile *file; M_TokenFile *file;
M_Entry *first; M_Entry *first;
M_Entry *last; M_Entry *last;
u64 count; u64 count;
M_ErrorList errors; M_ErrorList errors;
} extern Readonly M_NilLayer; } extern Readonly M_NilLayer;
Struct(M_LayerList) Struct(M_LayerList)
{ {
M_Layer *first; M_Layer *first;
M_Layer *last; M_Layer *last;
u64 count; u64 count;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////

View File

@ -3,15 +3,15 @@
Enum(OS_FileFlag) Enum(OS_FileFlag)
{ {
OS_FileFlag_None = 0, OS_FileFlag_None = 0,
OS_FileFlag_Read = (1 << 0), OS_FileFlag_Read = (1 << 0),
OS_FileFlag_Write = (1 << 1), OS_FileFlag_Write = (1 << 1),
OS_FileFlag_Create = (1 << 2), OS_FileFlag_Create = (1 << 2),
}; };
Struct(OS_File) Struct(OS_File)
{ {
u64 handle; u64 handle;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -19,8 +19,8 @@ Struct(OS_File)
Struct(OS_CommandResult) Struct(OS_CommandResult)
{ {
i32 code; i32 code;
String output; String output;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////

View File

@ -1,5 +1,5 @@
#include "meta_os.h" #include "meta_os.h"
#if IsPlatformWindows #if IsPlatformWindows
# include "meta_os_win32/meta_os_win32_inc.h" #include "meta_os_win32/meta_os_win32_inc.h"
#endif #endif

View File

@ -3,27 +3,27 @@
String W32_StringFromError(Arena *arena, DWORD err) String W32_StringFromError(Arena *arena, DWORD err)
{ {
String result = Zi; String result = Zi;
char *msg_cstr = 0; char *msg_cstr = 0;
i64 len = FormatMessageA( i64 len = FormatMessageA(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
0, 0,
err, err,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPSTR)&msg_cstr, (LPSTR)&msg_cstr,
0, 0,
0 0
); );
if (len > 0) if (len > 0)
{ {
result = PushString(arena, TrimWhitespace(StringFromCstr(msg_cstr, len))); result = PushString(arena, TrimWhitespace(StringFromCstr(msg_cstr, len)));
LocalFree(msg_cstr); LocalFree(msg_cstr);
} }
else else
{ {
result = StringF(arena, "Unknown win32 error - %F", FmtHex(err)); result = StringF(arena, "Unknown win32 error - %F", FmtHex(err));
} }
return result; return result;
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -38,117 +38,117 @@ void OS_Bootstrap(void)
OS_File OS_OpenFile(String path, OS_FileFlag flags, i64 timeout_ns) OS_File OS_OpenFile(String path, OS_FileFlag flags, i64 timeout_ns)
{ {
TempArena scratch = BeginScratchNoConflict(); TempArena scratch = BeginScratchNoConflict();
OS_File result = Zi; OS_File result = Zi;
wchar_t *path_wstr = WstrFromString(scratch.arena, path); wchar_t *path_wstr = WstrFromString(scratch.arena, path);
u32 share_mode = FILE_SHARE_READ; u32 share_mode = FILE_SHARE_READ;
u32 create_mode = OPEN_EXISTING; u32 create_mode = OPEN_EXISTING;
u32 access_flags = 0; u32 access_flags = 0;
if (flags & OS_FileFlag_Read) access_flags |= GENERIC_READ; if (flags & OS_FileFlag_Read) access_flags |= GENERIC_READ;
if (flags & OS_FileFlag_Write) access_flags |= GENERIC_WRITE; if (flags & OS_FileFlag_Write) access_flags |= GENERIC_WRITE;
if (flags & OS_FileFlag_Create) create_mode = OPEN_ALWAYS; if (flags & OS_FileFlag_Create) create_mode = OPEN_ALWAYS;
i32 timeout_ms = timeout_ns / 1000000; i32 timeout_ms = timeout_ns / 1000000;
i32 elapsed_ms = 0; i32 elapsed_ms = 0;
i32 delay_ms = 1; i32 delay_ms = 1;
HANDLE handle = INVALID_HANDLE_VALUE; HANDLE handle = INVALID_HANDLE_VALUE;
for (;;) for (;;)
{
handle = CreateFileW(path_wstr, access_flags, share_mode, 0, create_mode, FILE_ATTRIBUTE_NORMAL, 0);
if (handle == INVALID_HANDLE_VALUE && elapsed_ms < timeout_ms && GetLastError() == ERROR_SHARING_VIOLATION)
{ {
handle = CreateFileW(path_wstr, access_flags, share_mode, 0, create_mode, FILE_ATTRIBUTE_NORMAL, 0); Sleep(delay_ms);
if (handle == INVALID_HANDLE_VALUE && elapsed_ms < timeout_ms && GetLastError() == ERROR_SHARING_VIOLATION) elapsed_ms += delay_ms;
{ delay_ms = MinI32(delay_ms * 2, 1024);
Sleep(delay_ms);
elapsed_ms += delay_ms;
delay_ms = MinI32(delay_ms * 2, 1024);
}
else
{
break;
}
} }
EndScratch(scratch); else
result.handle = (u64)handle; {
return result; break;
}
}
EndScratch(scratch);
result.handle = (u64)handle;
return result;
} }
void OS_CloseFile(OS_File file) void OS_CloseFile(OS_File file)
{ {
HANDLE handle = (HANDLE)file.handle; HANDLE handle = (HANDLE)file.handle;
CloseHandle(handle); CloseHandle(handle);
} }
String OS_ReadEntireFile(Arena *arena, OS_File file) String OS_ReadEntireFile(Arena *arena, OS_File file)
{ {
String result = Zi; String result = Zi;
HANDLE handle = (HANDLE)file.handle; HANDLE handle = (HANDLE)file.handle;
u32 chunk_size = Kibi(64); u32 chunk_size = Kibi(64);
result.text = ArenaNext(arena, u8); result.text = ArenaNext(arena, u8);
for (;;) for (;;)
{
u8 *chunk = PushStructsNoZero(arena, u8, chunk_size);
DWORD chunk_bytes_read = 0;
ReadFile(handle, chunk, chunk_size, &chunk_bytes_read, 0);
result.len += chunk_bytes_read;
if (chunk_bytes_read < chunk_size)
{ {
u8 *chunk = PushStructsNoZero(arena, u8, chunk_size); PopStructsNoCopy(arena, u8, chunk_size - chunk_bytes_read);
DWORD chunk_bytes_read = 0; break;
ReadFile(handle, chunk, chunk_size, &chunk_bytes_read, 0);
result.len += chunk_bytes_read;
if (chunk_bytes_read < chunk_size)
{
PopStructsNoCopy(arena, u8, chunk_size - chunk_bytes_read);
break;
}
} }
return result; }
return result;
} }
void OS_ClearWriteFile(OS_File file, String data) void OS_ClearWriteFile(OS_File file, String data)
{ {
HANDLE handle = (HANDLE)file.handle; HANDLE handle = (HANDLE)file.handle;
SetFilePointer(handle, 0, 0, FILE_BEGIN); SetFilePointer(handle, 0, 0, FILE_BEGIN);
SetEndOfFile(handle); SetEndOfFile(handle);
WriteFile(handle, data.text, data.len, 0, 0); WriteFile(handle, data.text, data.len, 0, 0);
} }
void OS_DirContentsFromFullPath(Arena *arena, StringList *list, String path) void OS_DirContentsFromFullPath(Arena *arena, StringList *list, String path)
{ {
TempArena scratch = BeginScratch(arena); TempArena scratch = BeginScratch(arena);
WIN32_FIND_DATAW find_data = Zi; WIN32_FIND_DATAW find_data = Zi;
String filter = StringF(scratch.arena, "%F\\*", FmtString(path)); String filter = StringF(scratch.arena, "%F\\*", FmtString(path));
wchar_t *filter_wstr = WstrFromString(scratch.arena, filter); wchar_t *filter_wstr = WstrFromString(scratch.arena, filter);
HANDLE find_handle = FindFirstFileExW(filter_wstr, FindExInfoStandard, &find_data, FindExSearchNameMatch, 0, FIND_FIRST_EX_CASE_SENSITIVE | FIND_FIRST_EX_LARGE_FETCH); HANDLE find_handle = FindFirstFileExW(filter_wstr, FindExInfoStandard, &find_data, FindExSearchNameMatch, 0, FIND_FIRST_EX_CASE_SENSITIVE | FIND_FIRST_EX_LARGE_FETCH);
b32 found = find_handle && find_handle != INVALID_HANDLE_VALUE; b32 found = find_handle && find_handle != INVALID_HANDLE_VALUE;
while (found) while (found)
{
String file_name = StringFromWstrNoLimit(arena, find_data.cFileName);
if (!MatchString(file_name, Lit(".")) && !MatchString(file_name, Lit("..")))
{ {
String file_name = StringFromWstrNoLimit(arena, find_data.cFileName); PushStringToList(arena, list, file_name);
if (!MatchString(file_name, Lit(".")) && !MatchString(file_name, Lit("..")))
{
PushStringToList(arena, list, file_name);
}
found = FindNextFileW(find_handle, &find_data);
} }
EndScratch(scratch); found = FindNextFileW(find_handle, &find_data);
}
EndScratch(scratch);
} }
String OS_GetFullPath(Arena *arena, String path) String OS_GetFullPath(Arena *arena, String path)
{ {
TempArena scratch = BeginScratch(arena); TempArena scratch = BeginScratch(arena);
wchar_t *rel_path_wstr = WstrFromString(scratch.arena, path); wchar_t *rel_path_wstr = WstrFromString(scratch.arena, path);
wchar_t full_path_wstr_buff[4096]; wchar_t full_path_wstr_buff[4096];
GetFullPathNameW(rel_path_wstr, countof(full_path_wstr_buff), full_path_wstr_buff, 0); GetFullPathNameW(rel_path_wstr, countof(full_path_wstr_buff), full_path_wstr_buff, 0);
String res = StringFromWstr(arena, full_path_wstr_buff, countof(full_path_wstr_buff)); String res = StringFromWstr(arena, full_path_wstr_buff, countof(full_path_wstr_buff));
EndScratch(scratch); EndScratch(scratch);
return res; return res;
} }
u64 OS_LastWriteTimestampFromPath(String path) u64 OS_LastWriteTimestampFromPath(String path)
{ {
TempArena scratch = BeginScratchNoConflict(); TempArena scratch = BeginScratchNoConflict();
u64 result = 0; u64 result = 0;
WIN32_FILE_ATTRIBUTE_DATA a = Zi; WIN32_FILE_ATTRIBUTE_DATA a = Zi;
wchar_t *path_wstr = WstrFromString(scratch.arena, path); wchar_t *path_wstr = WstrFromString(scratch.arena, path);
if (GetFileAttributesExW(path_wstr, GetFileExInfoStandard, &a)) if (GetFileAttributesExW(path_wstr, GetFileExInfoStandard, &a))
{ {
result = ((ULONGLONG)a.ftLastWriteTime.dwHighDateTime << 32) | result = ((ULONGLONG)a.ftLastWriteTime.dwHighDateTime << 32) |
(ULONGLONG)a.ftLastWriteTime.dwLowDateTime; (ULONGLONG)a.ftLastWriteTime.dwLowDateTime;
} }
EndScratch(scratch); EndScratch(scratch);
return result; return result;
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -156,45 +156,45 @@ u64 OS_LastWriteTimestampFromPath(String path)
b32 OS_FileOrDirExists(String path) b32 OS_FileOrDirExists(String path)
{ {
TempArena scratch = BeginScratchNoConflict(); TempArena scratch = BeginScratchNoConflict();
wchar_t *path_wstr = WstrFromString(scratch.arena, path); wchar_t *path_wstr = WstrFromString(scratch.arena, path);
DWORD attributes = GetFileAttributesW(path_wstr); DWORD attributes = GetFileAttributesW(path_wstr);
EndScratch(scratch); EndScratch(scratch);
return attributes != INVALID_FILE_ATTRIBUTES; return attributes != INVALID_FILE_ATTRIBUTES;
} }
b32 OS_FileExists(String path) b32 OS_FileExists(String path)
{ {
TempArena scratch = BeginScratchNoConflict(); TempArena scratch = BeginScratchNoConflict();
wchar_t *path_wstr = WstrFromString(scratch.arena, path); wchar_t *path_wstr = WstrFromString(scratch.arena, path);
DWORD attributes = GetFileAttributesW(path_wstr); DWORD attributes = GetFileAttributesW(path_wstr);
EndScratch(scratch); EndScratch(scratch);
return attributes != INVALID_FILE_ATTRIBUTES && !(attributes & FILE_ATTRIBUTE_DIRECTORY); return attributes != INVALID_FILE_ATTRIBUTES && !(attributes & FILE_ATTRIBUTE_DIRECTORY);
} }
b32 OS_DirExists(String path) b32 OS_DirExists(String path)
{ {
TempArena scratch = BeginScratchNoConflict(); TempArena scratch = BeginScratchNoConflict();
wchar_t *path_wstr = WstrFromString(scratch.arena, path); wchar_t *path_wstr = WstrFromString(scratch.arena, path);
DWORD attributes = GetFileAttributesW(path_wstr); DWORD attributes = GetFileAttributesW(path_wstr);
EndScratch(scratch); EndScratch(scratch);
return attributes != INVALID_FILE_ATTRIBUTES && (attributes & FILE_ATTRIBUTE_DIRECTORY); return attributes != INVALID_FILE_ATTRIBUTES && (attributes & FILE_ATTRIBUTE_DIRECTORY);
} }
void OS_Mkdir(String path) void OS_Mkdir(String path)
{ {
TempArena scratch = BeginScratchNoConflict(); TempArena scratch = BeginScratchNoConflict();
wchar_t *path_wstr = WstrFromString(scratch.arena, path); wchar_t *path_wstr = WstrFromString(scratch.arena, path);
CreateDirectoryW(path_wstr, 0); CreateDirectoryW(path_wstr, 0);
EndScratch(scratch); EndScratch(scratch);
} }
void OS_Rm(String path) void OS_Rm(String path)
{ {
TempArena scratch = BeginScratchNoConflict(); TempArena scratch = BeginScratchNoConflict();
wchar_t *path_wstr = WstrFromString(scratch.arena, path); wchar_t *path_wstr = WstrFromString(scratch.arena, path);
DeleteFile(path_wstr); DeleteFile(path_wstr);
EndScratch(scratch); EndScratch(scratch);
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -202,150 +202,150 @@ void OS_Rm(String path)
OS_CommandResult OS_RunCommand(Arena *arena, String cmd) OS_CommandResult OS_RunCommand(Arena *arena, String cmd)
{ {
TempArena scratch = BeginScratch(arena); TempArena scratch = BeginScratch(arena);
OS_CommandResult result = Zi; OS_CommandResult result = Zi;
b32 ok = 1; b32 ok = 1;
wchar_t *cmd_wstr = WstrFromString(scratch.arena, cmd); wchar_t *cmd_wstr = WstrFromString(scratch.arena, cmd);
SECURITY_ATTRIBUTES sa = Zi; SECURITY_ATTRIBUTES sa = Zi;
sa.nLength = sizeof(sa); sa.nLength = sizeof(sa);
sa.bInheritHandle = 0; sa.bInheritHandle = 0;
/* Create pipe */ /* Create pipe */
HANDLE pipe_read = 0; HANDLE pipe_read = 0;
HANDLE pipe_write = 0; HANDLE pipe_write = 0;
if (ok)
{
ok = CreatePipe(&pipe_read, &pipe_write, &sa, 0) != 0;
if (!ok)
{
result.output = Lit("Failed to create pipe");
pipe_read = 0;
pipe_write = 0;
}
}
/* Duplicate pipe for child process */
HANDLE child_pipe_write = 0;
if (ok)
{
ok = DuplicateHandle(GetCurrentProcess(), pipe_write, GetCurrentProcess(), &child_pipe_write, 0, 1, DUPLICATE_SAME_ACCESS) != 0;
if (!ok)
{
result.output = Lit("Failed to create child pipe");
child_pipe_write = 0;
}
}
/* Initialize attrs list */
LPPROC_THREAD_ATTRIBUTE_LIST attrs = Zi;
if (ok)
{
u64 attrs_size = 0;
InitializeProcThreadAttributeList(0, 1, 0, &attrs_size);
ok = attrs_size > 0;
if (ok) if (ok)
{ {
ok = CreatePipe(&pipe_read, &pipe_write, &sa, 0) != 0; attrs = PushBytes(scratch.arena, attrs_size, 64);
if (!ok) ok = InitializeProcThreadAttributeList(attrs, 1, 0, &attrs_size) != 0;
{
result.output = Lit("Failed to create pipe");
pipe_read = 0;
pipe_write = 0;
}
} }
if (!ok)
{
result.output = Lit("Failed to initialize attrs list");
}
}
/* Duplicate pipe for child process */ /* Build the handle inheritance whitelist */
HANDLE child_pipe_write = 0; if (ok) {
HANDLE inherit_list[] = { child_pipe_write };
ok = UpdateProcThreadAttribute(attrs, 0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST, inherit_list, sizeof(inherit_list), 0, 0) != 0;
if (!ok)
{
result.output = Lit("Failed to update attributes");
}
}
/* Create process */
/* TODO: Allow caller to set child process's thread affinity by job pool */
HANDLE process = 0;
HANDLE process_thread = 0;
if (ok)
{
PROCESS_INFORMATION pi = Zi;
STARTUPINFOEXW si = Zi;
si.StartupInfo.cb = sizeof(si);
si.StartupInfo.dwFlags = STARTF_USESTDHANDLES;
si.StartupInfo.hStdOutput = child_pipe_write;
si.StartupInfo.hStdError = child_pipe_write;
si.lpAttributeList = attrs;
ok = CreateProcessW(0, cmd_wstr, 0, 0, 1, EXTENDED_STARTUPINFO_PRESENT, 0, 0, &si.StartupInfo, &pi) != 0;
if (ok) if (ok)
{ {
ok = DuplicateHandle(GetCurrentProcess(), pipe_write, GetCurrentProcess(), &child_pipe_write, 0, 1, DUPLICATE_SAME_ACCESS) != 0; process = pi.hProcess;
if (!ok) process_thread = pi.hThread;
{
result.output = Lit("Failed to create child pipe");
child_pipe_write = 0;
}
} }
else
/* Initialize attrs list */
LPPROC_THREAD_ATTRIBUTE_LIST attrs = Zi;
if (ok)
{ {
u64 attrs_size = 0; result.output = W32_StringFromError(arena, GetLastError());
InitializeProcThreadAttributeList(0, 1, 0, &attrs_size);
ok = attrs_size > 0;
if (ok)
{
attrs = PushBytes(scratch.arena, attrs_size, 64);
ok = InitializeProcThreadAttributeList(attrs, 1, 0, &attrs_size) != 0;
}
if (!ok)
{
result.output = Lit("Failed to initialize attrs list");
}
} }
/* Close write pipe handles */
/* Build the handle inheritance whitelist */
if (ok) {
HANDLE inherit_list[] = { child_pipe_write };
ok = UpdateProcThreadAttribute(attrs, 0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST, inherit_list, sizeof(inherit_list), 0, 0) != 0;
if (!ok)
{
result.output = Lit("Failed to update attributes");
}
}
/* Create process */
/* TODO: Allow caller to set child process's thread affinity by job pool */
HANDLE process = 0;
HANDLE process_thread = 0;
if (ok)
{ {
PROCESS_INFORMATION pi = Zi; CloseHandle(child_pipe_write);
STARTUPINFOEXW si = Zi; CloseHandle(pipe_write);
si.StartupInfo.cb = sizeof(si); child_pipe_write = 0;
si.StartupInfo.dwFlags = STARTF_USESTDHANDLES; pipe_write = 0;
si.StartupInfo.hStdOutput = child_pipe_write; }
si.StartupInfo.hStdError = child_pipe_write; }
si.lpAttributeList = attrs;
ok = CreateProcessW(0, cmd_wstr, 0, 0, 1, EXTENDED_STARTUPINFO_PRESENT, 0, 0, &si.StartupInfo, &pi) != 0; /* Read process output */
if (ok) if (ok)
{
result.output.text = ArenaNext(arena, u8);
b32 exit_code_valid = 0;
DWORD exit_code = 0;
b32 stdout_finished = 0;
while (!stdout_finished)
{
u8 buff[4096] = Zi;
DWORD bytes_read = 0;
if (!ReadFile(pipe_read, buff, countof(buff), &bytes_read, 0))
{
DWORD err = GetLastError();
if (err == ERROR_BROKEN_PIPE)
{ {
process = pi.hProcess; GetExitCodeProcess(process, &exit_code);
process_thread = pi.hThread; exit_code_valid = 1;
} }
else else
{ {
result.output = W32_StringFromError(arena, GetLastError()); result.output.len += W32_StringFromError(arena, err).len;
}
/* Close write pipe handles */
{
CloseHandle(child_pipe_write);
CloseHandle(pipe_write);
child_pipe_write = 0;
pipe_write = 0;
} }
stdout_finished = 1;
}
PushStructsNoZero(arena, u8, bytes_read);
CopyBytes(result.output.text + result.output.len, buff, bytes_read);
result.output.len += bytes_read;
} }
if (exit_code_valid)
/* Read process output */
if (ok)
{ {
result.output.text = ArenaNext(arena, u8); result.code = exit_code;
b32 exit_code_valid = 0;
DWORD exit_code = 0;
b32 stdout_finished = 0;
while (!stdout_finished)
{
u8 buff[4096] = Zi;
DWORD bytes_read = 0;
if (!ReadFile(pipe_read, buff, countof(buff), &bytes_read, 0))
{
DWORD err = GetLastError();
if (err == ERROR_BROKEN_PIPE)
{
GetExitCodeProcess(process, &exit_code);
exit_code_valid = 1;
}
else
{
result.output.len += W32_StringFromError(arena, err).len;
}
stdout_finished = 1;
}
PushStructsNoZero(arena, u8, bytes_read);
CopyBytes(result.output.text + result.output.len, buff, bytes_read);
result.output.len += bytes_read;
}
if (exit_code_valid)
{
result.code = exit_code;
}
} }
}
/* Close handles */ /* Close handles */
if (attrs) DeleteProcThreadAttributeList(attrs); if (attrs) DeleteProcThreadAttributeList(attrs);
if (process_thread) CloseHandle(process_thread); if (process_thread) CloseHandle(process_thread);
if (process) CloseHandle(process); if (process) CloseHandle(process);
if (child_pipe_write) CloseHandle(child_pipe_write); if (child_pipe_write) CloseHandle(child_pipe_write);
if (pipe_read) CloseHandle(pipe_read); if (pipe_read) CloseHandle(pipe_read);
if (pipe_write) CloseHandle(pipe_write); if (pipe_write) CloseHandle(pipe_write);
if (!ok && result.code == 0) if (!ok && result.code == 0)
{ {
result.code = -1; result.code = -1;
} }
EndScratch(scratch); EndScratch(scratch);
return result; return result;
} }

View File

@ -21,10 +21,10 @@ MIX_SharedState M_shared_state = ZI;
void MIX_Bootstrap(void) void MIX_Bootstrap(void)
{ {
MIX_SharedState *g = &M_shared_state; MIX_SharedState *g = &M_shared_state;
g->track_arena = AcquireArena(Gibi(64)); g->track_arena = AcquireArena(Gibi(64));
g->listener_pos = VEC2(0, 0); g->listener_pos = VEC2(0, 0);
g->listener_dir = VEC2(0, -1); g->listener_dir = VEC2(0, -1);
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -32,187 +32,187 @@ void MIX_Bootstrap(void)
MIX_Handle MIX_HandleFromTrack(MIX_Track *track) MIX_Handle MIX_HandleFromTrack(MIX_Track *track)
{ {
MIX_Handle result = ZI; MIX_Handle result = ZI;
result.gen = track->gen; result.gen = track->gen;
result.data = track; result.data = track;
return result; return result;
} }
MIX_Track *MIX_TrackFromHandle(MIX_Handle handle) MIX_Track *MIX_TrackFromHandle(MIX_Handle handle)
{ {
MIX_Track *track = (MIX_Track *)handle.data; MIX_Track *track = (MIX_Track *)handle.data;
if (track && track->gen == handle.gen) if (track && track->gen == handle.gen)
{ {
return track; return track;
} }
else else
{ {
return 0; return 0;
} }
} }
MIX_Track *MIX_AcquireTrackLocked(Lock *lock, SND_Sound *sound) MIX_Track *MIX_AcquireTrackLocked(Lock *lock, SND_Sound *sound)
{ {
MIX_SharedState *g = &M_shared_state; MIX_SharedState *g = &M_shared_state;
AssertLockedE(lock, &g->mutex); AssertLockedE(lock, &g->mutex);
MIX_Track *track = 0; MIX_Track *track = 0;
if (g->track_first_free) if (g->track_first_free)
{
/* Take from free list */
track = g->track_first_free;
MIX_Track *next_free = track->next;
g->track_first_free = next_free;
if (next_free)
{ {
/* Take from free list */ next_free->prev = 0;
track = g->track_first_free;
MIX_Track *next_free = track->next;
g->track_first_free = next_free;
if (next_free)
{
next_free->prev = 0;
}
*track = (MIX_Track) { .gen = track->gen + 1 };
}
else
{
/* Acquire new */
track = PushStruct(g->track_arena, MIX_Track);
track->gen = 1;
} }
*track = (MIX_Track) { .gen = track->gen + 1 };
}
else
{
/* Acquire new */
track = PushStruct(g->track_arena, MIX_Track);
track->gen = 1;
}
track->sound = sound; track->sound = sound;
track->mix.source = sound; track->mix.source = sound;
track->mix.track_handle = MIX_HandleFromTrack(track); track->mix.track_handle = MIX_HandleFromTrack(track);
/* Append to playing list */ /* Append to playing list */
MIX_Track *prev = g->track_last_playing; MIX_Track *prev = g->track_last_playing;
if (prev) if (prev)
{ {
prev->next = track; prev->next = track;
} }
else else
{ {
g->track_first_playing = track; g->track_first_playing = track;
} }
g->track_last_playing = track; g->track_last_playing = track;
track->prev = prev; track->prev = prev;
++g->track_playing_count; ++g->track_playing_count;
return track; return track;
} }
void MIX_ReleaseTrackLocked(Lock *lock, MIX_Track *track) void MIX_ReleaseTrackLocked(Lock *lock, MIX_Track *track)
{ {
MIX_SharedState *g = &M_shared_state; MIX_SharedState *g = &M_shared_state;
AssertLockedE(lock, &g->mutex); AssertLockedE(lock, &g->mutex);
/* Remove from playing list */ /* Remove from playing list */
MIX_Track *prev = track->prev; MIX_Track *prev = track->prev;
MIX_Track *next = track->next; MIX_Track *next = track->next;
if (prev) if (prev)
{ {
prev->next = next; prev->next = next;
} }
else else
{ {
/* Track was first in list */ /* Track was first in list */
g->track_first_playing = next; g->track_first_playing = next;
} }
if (next) if (next)
{ {
next->prev = prev; next->prev = prev;
} }
else else
{ {
/* Track was last in list */ /* Track was last in list */
g->track_last_playing = prev; g->track_last_playing = prev;
} }
--g->track_playing_count; --g->track_playing_count;
++track->gen; ++track->gen;
/* Add to free list */ /* Add to free list */
track->prev = 0; track->prev = 0;
track->next = g->track_first_free; track->next = g->track_first_free;
if (g->track_first_free) if (g->track_first_free)
{ {
g->track_first_free->prev = track; g->track_first_free->prev = track;
} }
g->track_first_free = track; g->track_first_free = track;
} }
/* TODO: Rework interface to be command based instead of directly modifying tracks. */ /* TODO: Rework interface to be command based instead of directly modifying tracks. */
MIX_Handle MIX_PlaySound(SND_Sound *sound) MIX_Handle MIX_PlaySound(SND_Sound *sound)
{ {
return MIX_PlaySoundEx(sound, M_TRACKDESC()); return MIX_PlaySoundEx(sound, M_TRACKDESC());
} }
MIX_Handle MIX_PlaySoundEx(SND_Sound *sound, MIX_TrackDesc desc) MIX_Handle MIX_PlaySoundEx(SND_Sound *sound, MIX_TrackDesc desc)
{ {
MIX_SharedState *g = &M_shared_state; MIX_SharedState *g = &M_shared_state;
MIX_Track *track; MIX_Track *track;
{
Lock lock = LockE(&g->mutex);
{ {
Lock lock = LockE(&g->mutex); track = MIX_AcquireTrackLocked(&lock, sound);
{ track->desc = desc;
track = MIX_AcquireTrackLocked(&lock, sound);
track->desc = desc;
}
Unlock(&lock);
} }
return MIX_HandleFromTrack(track); Unlock(&lock);
}
return MIX_HandleFromTrack(track);
} }
/* NOTE: This is quite inefficient. */ /* NOTE: This is quite inefficient. */
MIX_TrackDesc MIX_TrackDescFromHandle(MIX_Handle handle) MIX_TrackDesc MIX_TrackDescFromHandle(MIX_Handle handle)
{ {
MIX_SharedState *g = &M_shared_state; MIX_SharedState *g = &M_shared_state;
MIX_TrackDesc result = ZI; MIX_TrackDesc result = ZI;
MIX_Track *track = MIX_TrackFromHandle(handle); MIX_Track *track = MIX_TrackFromHandle(handle);
if (track) if (track)
{
/* TODO: Only lock mutex on track itself or something */
Lock lock = LockE(&g->mutex);
{ {
/* TODO: Only lock mutex on track itself or something */ /* Confirm handle is still valid now that we're locked */
Lock lock = LockE(&g->mutex); track = MIX_TrackFromHandle(handle);
{ if (track)
/* Confirm handle is still valid now that we're locked */ {
track = MIX_TrackFromHandle(handle); result = track->desc;
if (track) }
{
result = track->desc;
}
}
Unlock(&lock);
} }
Unlock(&lock);
}
return result; return result;
} }
/* NOTE: This is quite inefficient. */ /* NOTE: This is quite inefficient. */
void MIX_UpdateTrack(MIX_Handle handle, MIX_TrackDesc desc) void MIX_UpdateTrack(MIX_Handle handle, MIX_TrackDesc desc)
{ {
MIX_SharedState *g = &M_shared_state; MIX_SharedState *g = &M_shared_state;
MIX_Track *track = MIX_TrackFromHandle(handle); MIX_Track *track = MIX_TrackFromHandle(handle);
if (track) if (track)
{
/* TODO: Only lock mutex on track itself or something */
Lock lock = LockE(&g->mutex);
{ {
/* TODO: Only lock mutex on track itself or something */ /* Confirm handle is still valid now that we're locked */
Lock lock = LockE(&g->mutex); track = MIX_TrackFromHandle(handle);
{ if (track)
/* Confirm handle is still valid now that we're locked */ {
track = MIX_TrackFromHandle(handle); track->desc = desc;
if (track) }
{
track->desc = desc;
}
}
Unlock(&lock);
} }
Unlock(&lock);
}
} }
void MIX_UpdateListener(Vec2 pos, Vec2 dir) void MIX_UpdateListener(Vec2 pos, Vec2 dir)
{ {
MIX_SharedState *g = &M_shared_state; MIX_SharedState *g = &M_shared_state;
Lock lock = LockE(&g->mutex); Lock lock = LockE(&g->mutex);
{ {
g->listener_pos = pos; g->listener_pos = pos;
g->listener_dir = NormVec2(dir); g->listener_dir = NormVec2(dir);
} }
Unlock(&lock); Unlock(&lock);
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -220,250 +220,250 @@ void MIX_UpdateListener(Vec2 pos, Vec2 dir)
i16 MIX_SampleSound(SND_Sound *sound, u64 sample_pos, b32 wrap) i16 MIX_SampleSound(SND_Sound *sound, u64 sample_pos, b32 wrap)
{ {
if (wrap) if (wrap)
{ {
return sound->samples[sample_pos % sound->samples_count]; return sound->samples[sample_pos % sound->samples_count];
} }
else if (sample_pos < sound->samples_count) else if (sample_pos < sound->samples_count)
{ {
return sound->samples[sample_pos]; return sound->samples[sample_pos];
} }
else else
{ {
return 0; return 0;
} }
} }
/* To be called once per audio playback interval */ /* To be called once per audio playback interval */
MIX_PcmF32 MIX_MixAllTracks(Arena *arena, u64 frame_count) MIX_PcmF32 MIX_MixAllTracks(Arena *arena, u64 frame_count)
{ {
TempArena scratch = BeginScratch(arena); TempArena scratch = BeginScratch(arena);
MIX_SharedState *g = &M_shared_state; MIX_SharedState *g = &M_shared_state;
MIX_PcmF32 result = ZI; MIX_PcmF32 result = ZI;
result.count = frame_count * 2; result.count = frame_count * 2;
result.samples = PushStructs(arena, f32, result.count); result.samples = PushStructs(arena, f32, result.count);
Vec2 listener_pos = VEC2(0, 0); Vec2 listener_pos = VEC2(0, 0);
Vec2 listener_dir = VEC2(0, 0); Vec2 listener_dir = VEC2(0, 0);
//- Create temp mix array //- Create temp mix array
MIX_MixData **mixes = 0; MIX_MixData **mixes = 0;
u64 mixes_count = 0; u64 mixes_count = 0;
{
Lock lock = LockE(&g->mutex);
/* Read listener info */
listener_pos = g->listener_pos;
listener_dir = g->listener_dir;
/* Update & read mixes */
mixes = PushStructsNoZero(scratch.arena, MIX_MixData *, g->track_playing_count);
for (MIX_Track *track = g->track_first_playing; track; track = track->next)
{ {
Lock lock = LockE(&g->mutex); MIX_MixData *mix = &track->mix;
mix->desc = track->desc;
/* Read listener info */ mixes[mixes_count++] = mix;
listener_pos = g->listener_pos;
listener_dir = g->listener_dir;
/* Update & read mixes */
mixes = PushStructsNoZero(scratch.arena, MIX_MixData *, g->track_playing_count);
for (MIX_Track *track = g->track_first_playing; track; track = track->next)
{
MIX_MixData *mix = &track->mix;
mix->desc = track->desc;
mixes[mixes_count++] = mix;
}
Unlock(&lock);
} }
//- Process mix data Unlock(&lock);
}
for (u64 mix_index = 0; mix_index < mixes_count; ++mix_index) //- Process mix data
for (u64 mix_index = 0; mix_index < mixes_count; ++mix_index)
{
MIX_MixData *mix = mixes[mix_index];
if (mix->source->samples_count <= 0)
{ {
MIX_MixData *mix = mixes[mix_index]; /* Skip empty sounds */
continue;
if (mix->source->samples_count <= 0)
{
/* Skip empty sounds */
continue;
}
SND_Sound *source = mix->source;
MIX_TrackDesc desc = mix->desc;
MIX_EffectData *effect_data = &mix->effect_data;
b32 source_is_stereo = source->flags & SND_SoundFlag_Stereo;
f32 speed = MaxF32(0, desc.speed);
//- Determine sample range
u64 source_samples_count = 0;
if (source_is_stereo)
{
source_samples_count = frame_count * 2;
/* Round <samples_count * speed> to nearest frame boundary (nearest multiple of 2) */
source_samples_count = (u64)CeilF32ToI32((f32)source_samples_count * speed);
source_samples_count &= ~1;
}
else
{
source_samples_count = frame_count;
/* Round <samples_count * speed> to nearest sample */
source_samples_count = (u64)RoundF32ToI32((f32)source_samples_count * speed);
}
u64 source_sample_pos_start = mix->source_pos;
u64 source_sample_pos_end = source_sample_pos_start + source_samples_count;
if (source_sample_pos_end >= source->samples_count)
{
if (desc.looping)
{
source_sample_pos_end = source_sample_pos_end % source->samples_count;
}
else
{
source_sample_pos_end = source->samples_count;
mix->track_finished = 1;
}
}
u64 source_frames_count = source_is_stereo ? source_samples_count / 2 : source_samples_count;
u64 source_frame_pos_start = source_is_stereo ? source_sample_pos_start / 2 : source_sample_pos_start;
mix->source_pos = source_sample_pos_end;
MIX_PcmF32 mix_pcm = {
.count = result.count,
.samples = PushStructs(scratch.arena, f32, result.count)
};
//- Resample
/* Transform 16 bit source -> 32 bit stereo at output duration */
{
f32 *out_samples = mix_pcm.samples;
u64 out_frames_count = mix_pcm.count / 2;
/* TODO: Fast path for 1:1 copy when speed = 1.0? */
/* TODO: Optimize */
if (source_is_stereo)
{
/* 16 bit Stereo -> 32 bit Stereo */
for (u64 out_frame_pos = 0; out_frame_pos < out_frames_count; ++out_frame_pos)
{
f32 in_frame_pos_exact = source_frame_pos_start + (((f32)out_frame_pos / (f32)out_frames_count) * (f32)source_frames_count);
u32 in_frame_pos_prev = FloorF32ToI32(in_frame_pos_exact);
u32 in_frame_pos_next = CeilF32ToI32(in_frame_pos_exact);
/* Sample source */
f32 sample1_prev = MIX_SampleSound(source, (in_frame_pos_prev * 2) + 0, desc.looping) * (1.f / 32768.f);
f32 sample1_next = MIX_SampleSound(source, (in_frame_pos_next * 2) + 0, desc.looping) * (1.f / 32768.f);
f32 sample2_prev = MIX_SampleSound(source, (in_frame_pos_prev * 2) + 1, desc.looping) * (1.f / 32768.f);
f32 sample2_next = MIX_SampleSound(source, (in_frame_pos_next * 2) + 1, desc.looping) * (1.f / 32768.f);
/* Lerp */
f32 t = in_frame_pos_exact - (f32)in_frame_pos_prev;
f32 sample1 = LerpF32(sample1_prev, sample1_next, t);
f32 sample2 = LerpF32(sample2_prev, sample2_next, t);
out_samples[(out_frame_pos * 2) + 0] += sample1;
out_samples[(out_frame_pos * 2) + 1] += sample2;
}
}
else
{
/* 16 bit Mono -> 32 bit Stereo */
for (u64 out_frame_pos = 0; out_frame_pos < out_frames_count; ++out_frame_pos)
{
f32 in_frame_pos_exact = source_frame_pos_start + (((f32)out_frame_pos / (f32)out_frames_count) * (f32)source_frames_count);
u32 in_frame_pos_prev = FloorF32ToI32(in_frame_pos_exact);
u32 in_frame_pos_next = CeilF32ToI32(in_frame_pos_exact);
/* Sample source */
f32 sample_prev = MIX_SampleSound(source, in_frame_pos_prev, desc.looping) * (1.f / 32768.f);
f32 sample_next = MIX_SampleSound(source, in_frame_pos_next, desc.looping) * (1.f / 32768.f);
/* Lerp */
f32 t = (f32)in_frame_pos_exact - in_frame_pos_prev;
f32 sample = LerpF32(sample_prev, sample_next, t);
out_samples[(out_frame_pos * 2) + 0] += sample;
out_samples[(out_frame_pos * 2) + 1] += sample;
}
}
}
//- Spatialize
if (desc.flags & MIX_TrackFlag_Spatialize)
{
/* Algorithm constants */
const f32 rolloff_height = 1.2f;
const f32 rolloff_scale = 6.0f;
const f32 pan_scale = 0.75;
Vec2 pos = desc.pos;
/* If sound pos = listener pos, pretend sound is close in front of listener. */
if (MatchVec2(listener_pos, pos))
{
pos = AddVec2(listener_pos, MulVec2(listener_dir, 0.001f));
}
Vec2 sound_rel = SubVec2(pos, listener_pos);
Vec2 sound_rel_dir = NormVec2(sound_rel);
/* Compute volume */
f32 volume_start = effect_data->spatial_volume;
f32 volume_end;
{
/* https://www.desmos.com/calculator/c2h941hobz
* h = `rolloff_height`
* s = `rolloff_scale`
*/
f32 dist = Vec2Len(sound_rel);
f32 v = (dist / rolloff_scale) + 1.0f;
volume_end = rolloff_height * (1.0f / (v * v));
}
effect_data->spatial_volume = volume_end;
/* Compute pan */
f32 pan_start = effect_data->spatial_pan;
f32 pan_end = WedgeVec2(listener_dir, sound_rel_dir) * pan_scale;
effect_data->spatial_pan = pan_end;
/* Spatialize samples */
for (u64 frame_pos = 0; frame_pos < frame_count; ++frame_pos)
{
f32 t = (f32)frame_pos / (f32)(frame_count - 1);
f32 volume = LerpF32(volume_start, volume_end, t);
f32 pan = LerpF32(pan_start, pan_end, t);
u64 sample1_index = frame_pos * 2;
u64 sample2_index = sample1_index + 1;
f32 sample_mono = ((mix_pcm.samples[sample1_index + 0] / 2.0f) + (mix_pcm.samples[sample2_index] / 2.0f)) * volume;
mix_pcm.samples[sample1_index] = sample_mono * (1.0f - pan);
mix_pcm.samples[sample2_index] = sample_mono * (1.0f + pan);
}
}
//- Mix into result
for (u64 i = 0; i < mix_pcm.count; ++i)
{
result.samples[i] += mix_pcm.samples[i] * desc.volume;
}
} }
//- Update track effect data SND_Sound *source = mix->source;
MIX_TrackDesc desc = mix->desc;
MIX_EffectData *effect_data = &mix->effect_data;
b32 source_is_stereo = source->flags & SND_SoundFlag_Stereo;
f32 speed = MaxF32(0, desc.speed);
//- Determine sample range
u64 source_samples_count = 0;
if (source_is_stereo)
{ {
Lock lock = LockE(&g->mutex); source_samples_count = frame_count * 2;
for (u64 i = 0; i < mixes_count; ++i) /* Round <samples_count * speed> to nearest frame boundary (nearest multiple of 2) */
{ source_samples_count = (u64)CeilF32ToI32((f32)source_samples_count * speed);
MIX_MixData *mix = mixes[i]; source_samples_count &= ~1;
MIX_Track *track = MIX_TrackFromHandle(mix->track_handle); }
if (track) else
{ {
if (mix->track_finished) source_samples_count = frame_count;
{ /* Round <samples_count * speed> to nearest sample */
/* Release finished tracks */ source_samples_count = (u64)RoundF32ToI32((f32)source_samples_count * speed);
MIX_ReleaseTrackLocked(&lock, track);
}
}
}
Unlock(&lock);
} }
EndScratch(scratch); u64 source_sample_pos_start = mix->source_pos;
return result; u64 source_sample_pos_end = source_sample_pos_start + source_samples_count;
if (source_sample_pos_end >= source->samples_count)
{
if (desc.looping)
{
source_sample_pos_end = source_sample_pos_end % source->samples_count;
}
else
{
source_sample_pos_end = source->samples_count;
mix->track_finished = 1;
}
}
u64 source_frames_count = source_is_stereo ? source_samples_count / 2 : source_samples_count;
u64 source_frame_pos_start = source_is_stereo ? source_sample_pos_start / 2 : source_sample_pos_start;
mix->source_pos = source_sample_pos_end;
MIX_PcmF32 mix_pcm = {
.count = result.count,
.samples = PushStructs(scratch.arena, f32, result.count)
};
//- Resample
/* Transform 16 bit source -> 32 bit stereo at output duration */
{
f32 *out_samples = mix_pcm.samples;
u64 out_frames_count = mix_pcm.count / 2;
/* TODO: Fast path for 1:1 copy when speed = 1.0? */
/* TODO: Optimize */
if (source_is_stereo)
{
/* 16 bit Stereo -> 32 bit Stereo */
for (u64 out_frame_pos = 0; out_frame_pos < out_frames_count; ++out_frame_pos)
{
f32 in_frame_pos_exact = source_frame_pos_start + (((f32)out_frame_pos / (f32)out_frames_count) * (f32)source_frames_count);
u32 in_frame_pos_prev = FloorF32ToI32(in_frame_pos_exact);
u32 in_frame_pos_next = CeilF32ToI32(in_frame_pos_exact);
/* Sample source */
f32 sample1_prev = MIX_SampleSound(source, (in_frame_pos_prev * 2) + 0, desc.looping) * (1.f / 32768.f);
f32 sample1_next = MIX_SampleSound(source, (in_frame_pos_next * 2) + 0, desc.looping) * (1.f / 32768.f);
f32 sample2_prev = MIX_SampleSound(source, (in_frame_pos_prev * 2) + 1, desc.looping) * (1.f / 32768.f);
f32 sample2_next = MIX_SampleSound(source, (in_frame_pos_next * 2) + 1, desc.looping) * (1.f / 32768.f);
/* Lerp */
f32 t = in_frame_pos_exact - (f32)in_frame_pos_prev;
f32 sample1 = LerpF32(sample1_prev, sample1_next, t);
f32 sample2 = LerpF32(sample2_prev, sample2_next, t);
out_samples[(out_frame_pos * 2) + 0] += sample1;
out_samples[(out_frame_pos * 2) + 1] += sample2;
}
}
else
{
/* 16 bit Mono -> 32 bit Stereo */
for (u64 out_frame_pos = 0; out_frame_pos < out_frames_count; ++out_frame_pos)
{
f32 in_frame_pos_exact = source_frame_pos_start + (((f32)out_frame_pos / (f32)out_frames_count) * (f32)source_frames_count);
u32 in_frame_pos_prev = FloorF32ToI32(in_frame_pos_exact);
u32 in_frame_pos_next = CeilF32ToI32(in_frame_pos_exact);
/* Sample source */
f32 sample_prev = MIX_SampleSound(source, in_frame_pos_prev, desc.looping) * (1.f / 32768.f);
f32 sample_next = MIX_SampleSound(source, in_frame_pos_next, desc.looping) * (1.f / 32768.f);
/* Lerp */
f32 t = (f32)in_frame_pos_exact - in_frame_pos_prev;
f32 sample = LerpF32(sample_prev, sample_next, t);
out_samples[(out_frame_pos * 2) + 0] += sample;
out_samples[(out_frame_pos * 2) + 1] += sample;
}
}
}
//- Spatialize
if (desc.flags & MIX_TrackFlag_Spatialize)
{
/* Algorithm constants */
const f32 rolloff_height = 1.2f;
const f32 rolloff_scale = 6.0f;
const f32 pan_scale = 0.75;
Vec2 pos = desc.pos;
/* If sound pos = listener pos, pretend sound is close in front of listener. */
if (MatchVec2(listener_pos, pos))
{
pos = AddVec2(listener_pos, MulVec2(listener_dir, 0.001f));
}
Vec2 sound_rel = SubVec2(pos, listener_pos);
Vec2 sound_rel_dir = NormVec2(sound_rel);
/* Compute volume */
f32 volume_start = effect_data->spatial_volume;
f32 volume_end;
{
/* https://www.desmos.com/calculator/c2h941hobz
* h = `rolloff_height`
* s = `rolloff_scale`
*/
f32 dist = Vec2Len(sound_rel);
f32 v = (dist / rolloff_scale) + 1.0f;
volume_end = rolloff_height * (1.0f / (v * v));
}
effect_data->spatial_volume = volume_end;
/* Compute pan */
f32 pan_start = effect_data->spatial_pan;
f32 pan_end = WedgeVec2(listener_dir, sound_rel_dir) * pan_scale;
effect_data->spatial_pan = pan_end;
/* Spatialize samples */
for (u64 frame_pos = 0; frame_pos < frame_count; ++frame_pos)
{
f32 t = (f32)frame_pos / (f32)(frame_count - 1);
f32 volume = LerpF32(volume_start, volume_end, t);
f32 pan = LerpF32(pan_start, pan_end, t);
u64 sample1_index = frame_pos * 2;
u64 sample2_index = sample1_index + 1;
f32 sample_mono = ((mix_pcm.samples[sample1_index + 0] / 2.0f) + (mix_pcm.samples[sample2_index] / 2.0f)) * volume;
mix_pcm.samples[sample1_index] = sample_mono * (1.0f - pan);
mix_pcm.samples[sample2_index] = sample_mono * (1.0f + pan);
}
}
//- Mix into result
for (u64 i = 0; i < mix_pcm.count; ++i)
{
result.samples[i] += mix_pcm.samples[i] * desc.volume;
}
}
//- Update track effect data
{
Lock lock = LockE(&g->mutex);
for (u64 i = 0; i < mixes_count; ++i)
{
MIX_MixData *mix = mixes[i];
MIX_Track *track = MIX_TrackFromHandle(mix->track_handle);
if (track)
{
if (mix->track_finished)
{
/* Release finished tracks */
MIX_ReleaseTrackLocked(&lock, track);
}
}
}
Unlock(&lock);
}
EndScratch(scratch);
return result;
} }

View File

@ -3,33 +3,33 @@
Enum(MIX_TrackFlag) Enum(MIX_TrackFlag)
{ {
MIX_TrackFlag_None = 0, MIX_TrackFlag_None = 0,
MIX_TrackFlag_Spatialize = (1 << 0) MIX_TrackFlag_Spatialize = (1 << 0)
}; };
Struct(MIX_Handle) Struct(MIX_Handle)
{ {
u64 gen; u64 gen;
void *data; void *data;
}; };
Struct(MIX_TrackDesc) Struct(MIX_TrackDesc)
{ {
MIX_TrackFlag flags; MIX_TrackFlag flags;
f32 volume; /* 0 -> 1.0+ */ f32 volume; /* 0 -> 1.0+ */
f32 speed; /* 0 -> 1.0+ */ f32 speed; /* 0 -> 1.0+ */
b32 looping; b32 looping;
/* MIX_TrackFlag_Spatialize */ /* MIX_TrackFlag_Spatialize */
Vec2 pos; Vec2 pos;
}; };
#define M_TRACKDESC(...) ((MIX_TrackDesc) { \ #define M_TRACKDESC(...) ((MIX_TrackDesc) { \
.flags = 0, \ .flags = 0, \
.volume = 1.0, \ .volume = 1.0, \
.speed = 1.0, \ .speed = 1.0, \
.looping = 0, \ .looping = 0, \
.pos = VEC2(0, 0), \ .pos = VEC2(0, 0), \
__VA_ARGS__ \ __VA_ARGS__ \
}) })
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -38,40 +38,40 @@ Struct(MIX_TrackDesc)
/* Stereo mix of 32 bit float samples */ /* Stereo mix of 32 bit float samples */
Struct(MIX_PcmF32) Struct(MIX_PcmF32)
{ {
u64 count; u64 count;
f32 *samples; f32 *samples;
}; };
Struct(MIX_EffectData) Struct(MIX_EffectData)
{ {
/* Spatialization */ /* Spatialization */
f32 spatial_volume; f32 spatial_volume;
f32 spatial_pan; f32 spatial_pan;
}; };
Struct(MIX_MixData) Struct(MIX_MixData)
{ {
MIX_Handle track_handle; MIX_Handle track_handle;
b32 track_finished; b32 track_finished;
MIX_TrackDesc desc; MIX_TrackDesc desc;
MIX_EffectData effect_data; MIX_EffectData effect_data;
SND_Sound *source; SND_Sound *source;
u64 source_pos; u64 source_pos;
}; };
Struct(MIX_Track){ Struct(MIX_Track){
u64 gen; u64 gen;
/* Controlled via interface */ /* Controlled via interface */
SND_Sound *sound; SND_Sound *sound;
MIX_TrackDesc desc; MIX_TrackDesc desc;
/* Internal */ /* Internal */
MIX_MixData mix; MIX_MixData mix;
MIX_Track *next; MIX_Track *next;
MIX_Track *prev; MIX_Track *prev;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -79,18 +79,18 @@ Struct(MIX_Track){
Struct(MIX_SharedState) Struct(MIX_SharedState)
{ {
Mutex mutex; Mutex mutex;
/* Listener */ /* Listener */
Vec2 listener_pos; Vec2 listener_pos;
Vec2 listener_dir; Vec2 listener_dir;
/* Track list */ /* Track list */
Arena *track_arena; Arena *track_arena;
MIX_Track *track_first_playing; MIX_Track *track_first_playing;
MIX_Track *track_last_playing; MIX_Track *track_last_playing;
u64 track_playing_count; u64 track_playing_count;
MIX_Track *track_first_free; MIX_Track *track_first_free;
} extern M_shared_state; } extern M_shared_state;
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////

View File

@ -3,15 +3,15 @@
Enum(MP3_DecodeFlag) Enum(MP3_DecodeFlag)
{ {
MP3_DecodeFlag_None = 0, MP3_DecodeFlag_None = 0,
MP3_DecodeFlag_Stereo = (1 << 0), MP3_DecodeFlag_Stereo = (1 << 0),
}; };
Struct(MP3_Result) Struct(MP3_Result)
{ {
u64 samples_count; u64 samples_count;
i16 *samples; i16 *samples;
b32 ok; b32 ok;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////

View File

@ -3,114 +3,114 @@
MP3_Result MP3_Decode(Arena *arena, String encoded, u32 sample_rate, MP3_DecodeFlag flags) MP3_Result MP3_Decode(Arena *arena, String encoded, u32 sample_rate, MP3_DecodeFlag flags)
{ {
MP3_Result result = ZI; MP3_Result result = ZI;
u64 bytes_per_sample = 2; u64 bytes_per_sample = 2;
u64 channel_count; u64 channel_count;
u32 channel_mask; u32 channel_mask;
if (flags & MP3_DecodeFlag_Stereo) if (flags & MP3_DecodeFlag_Stereo)
{
channel_count = 2;
channel_mask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
}
else
{
channel_count = 1;
channel_mask = SPEAKER_FRONT_CENTER;
}
//- Startup
MFStartup(MF_VERSION, MFSTARTUP_LITE);
/* Create IStream from encoded string */
IStream *i_stream = SHCreateMemStream(encoded.text, encoded.len);
/* Create IMFByteStream from IStream */
IMFByteStream *byte_stream = 0;
MFCreateMFByteStreamOnStream(i_stream, &byte_stream);
/* Create reader from IMFByteStream */
IMFSourceReader *reader;
MFCreateSourceReaderFromByteStream(byte_stream, 0, &reader);
//- Get media type
/* Read only first audio stream */
IMFSourceReader_SetStreamSelection(reader, (DWORD)MF_SOURCE_READER_ALL_STREAMS, 0);
IMFSourceReader_SetStreamSelection(reader, (DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM, 1);
WAVEFORMATEXTENSIBLE format = {
.Format = {
.wFormatTag = WAVE_FORMAT_EXTENSIBLE,
.nChannels = (WORD)channel_count,
.nSamplesPerSec = (WORD)sample_rate,
.nAvgBytesPerSec = (DWORD)(sample_rate * channel_count * bytes_per_sample),
.nBlockAlign = (WORD)(channel_count * bytes_per_sample),
.wBitsPerSample = (WORD)(8 * bytes_per_sample),
.cbSize = sizeof(format) - sizeof(format.Format)
},
.Samples.wValidBitsPerSample = 8 * bytes_per_sample,
.dwChannelMask = channel_mask,
.SubFormat = MEDIASUBTYPE_PCM
};
/* Media Foundation in Windows 8+ allows reader to convert output to different format than native */
IMFMediaType *type;
MFCreateMediaType(&type);
MFInitMediaTypeFromWaveFormatEx(type, &format.Format, sizeof(format));
IMFSourceReader_SetCurrentMediaType(reader, (DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM, 0, type);
IMFMediaType_Release(type);
//- Read
result.samples = ArenaNext(arena, i16);
u64 sample_bytes_read = 0;
for (;;)
{
IMFSample *sample;
DWORD sample_flags = 0;
HRESULT hr = IMFSourceReader_ReadSample(reader, (DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM, 0, 0, &sample_flags, 0, &sample);
if (FAILED(hr))
{ {
channel_count = 2; break;
channel_mask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
}
else
{
channel_count = 1;
channel_mask = SPEAKER_FRONT_CENTER;
} }
//- Startup /* Check if done */
if (sample_flags & MF_SOURCE_READERF_ENDOFSTREAM)
MFStartup(MF_VERSION, MFSTARTUP_LITE);
/* Create IStream from encoded string */
IStream *i_stream = SHCreateMemStream(encoded.text, encoded.len);
/* Create IMFByteStream from IStream */
IMFByteStream *byte_stream = 0;
MFCreateMFByteStreamOnStream(i_stream, &byte_stream);
/* Create reader from IMFByteStream */
IMFSourceReader *reader;
MFCreateSourceReaderFromByteStream(byte_stream, 0, &reader);
//- Get media type
/* Read only first audio stream */
IMFSourceReader_SetStreamSelection(reader, (DWORD)MF_SOURCE_READER_ALL_STREAMS, 0);
IMFSourceReader_SetStreamSelection(reader, (DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM, 1);
WAVEFORMATEXTENSIBLE format = {
.Format = {
.wFormatTag = WAVE_FORMAT_EXTENSIBLE,
.nChannels = (WORD)channel_count,
.nSamplesPerSec = (WORD)sample_rate,
.nAvgBytesPerSec = (DWORD)(sample_rate * channel_count * bytes_per_sample),
.nBlockAlign = (WORD)(channel_count * bytes_per_sample),
.wBitsPerSample = (WORD)(8 * bytes_per_sample),
.cbSize = sizeof(format) - sizeof(format.Format)
},
.Samples.wValidBitsPerSample = 8 * bytes_per_sample,
.dwChannelMask = channel_mask,
.SubFormat = MEDIASUBTYPE_PCM
};
/* Media Foundation in Windows 8+ allows reader to convert output to different format than native */
IMFMediaType *type;
MFCreateMediaType(&type);
MFInitMediaTypeFromWaveFormatEx(type, &format.Format, sizeof(format));
IMFSourceReader_SetCurrentMediaType(reader, (DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM, 0, type);
IMFMediaType_Release(type);
//- Read
result.samples = ArenaNext(arena, i16);
u64 sample_bytes_read = 0;
for (;;)
{ {
IMFSample *sample; result.ok = 1;
DWORD sample_flags = 0; break;
HRESULT hr = IMFSourceReader_ReadSample(reader, (DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM, 0, 0, &sample_flags, 0, &sample);
if (FAILED(hr))
{
break;
}
/* Check if done */
if (sample_flags & MF_SOURCE_READERF_ENDOFSTREAM)
{
result.ok = 1;
break;
}
Assert(sample_flags == 0);
/* Read samples */
IMFMediaBuffer *buffer;
IMFSample_ConvertToContiguousBuffer(sample, &buffer);
BYTE *src;
DWORD size_bytes;
IMFMediaBuffer_Lock(buffer, &src, 0, &size_bytes);
{
i16 *dst = PushStructsNoZero(arena, i16, (size_bytes + 1) >> 1);
CopyBytes(dst, src, size_bytes);
sample_bytes_read += size_bytes;
}
IMFMediaBuffer_Unlock(buffer);
IMediaBuffer_Release(buffer);
IMFSample_Release(sample);
} }
Assert(sample_flags == 0);
result.samples_count = sample_bytes_read / bytes_per_sample; /* Read samples */
IMFMediaBuffer *buffer;
IMFSample_ConvertToContiguousBuffer(sample, &buffer);
//- Cleanup BYTE *src;
DWORD size_bytes;
IMFMediaBuffer_Lock(buffer, &src, 0, &size_bytes);
{
i16 *dst = PushStructsNoZero(arena, i16, (size_bytes + 1) >> 1);
CopyBytes(dst, src, size_bytes);
sample_bytes_read += size_bytes;
}
IMFMediaBuffer_Unlock(buffer);
IMFSourceReader_Release(reader); IMediaBuffer_Release(buffer);
IMFByteStream_Close(byte_stream); IMFSample_Release(sample);
/* FIXME: Enable this */ }
//IStream_Release(i_stream);
MFShutdown();
return result; result.samples_count = sample_bytes_read / bytes_per_sample;
//- Cleanup
IMFSourceReader_Release(reader);
IMFByteStream_Close(byte_stream);
/* FIXME: Enable this */
//IStream_Release(i_stream);
MFShutdown();
return result;
} }

View File

@ -2,11 +2,11 @@
//~ Windows headers //~ Windows headers
#pragma warning(push, 0) #pragma warning(push, 0)
# include <mfapi.h> #include <mfapi.h>
# include <mfidl.h> #include <mfidl.h>
# include <mfreadwrite.h> #include <mfreadwrite.h>
# include <Shlwapi.h> #include <Shlwapi.h>
# include <objidl.h> #include <objidl.h>
#pragma warning(pop) #pragma warning(pop)
#pragma comment(lib, "mfplat") #pragma comment(lib, "mfplat")

File diff suppressed because it is too large Load Diff

View File

@ -3,8 +3,8 @@
Struct(N_ChannelId) Struct(N_ChannelId)
{ {
u32 gen; u32 gen;
u32 idx; u32 idx;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -12,32 +12,32 @@ Struct(N_ChannelId)
Enum(N_CmdKind) Enum(N_CmdKind)
{ {
N_CmdKind_None, N_CmdKind_None,
N_CmdKind_TryConnect, N_CmdKind_TryConnect,
N_CmdKind_ConnectSuccess, N_CmdKind_ConnectSuccess,
N_CmdKind_Disconnect, N_CmdKind_Disconnect,
N_CmdKind_Heartbeat, N_CmdKind_Heartbeat,
N_CmdKind_Write N_CmdKind_Write
}; };
Enum(N_WriteFlag) Enum(N_WriteFlag)
{ {
N_WriteFlag_None = 0, N_WriteFlag_None = 0,
N_WriteFlag_Reliable = (1 << 0) N_WriteFlag_Reliable = (1 << 0)
}; };
Struct(N_Cmd) Struct(N_Cmd)
{ {
N_CmdKind kind; N_CmdKind kind;
N_ChannelId channel_id; N_ChannelId channel_id;
u16 heartbeat_id; u16 heartbeat_id;
u16 heartbeat_ack_id; u16 heartbeat_ack_id;
b32 write_reliable; b32 write_reliable;
String write_msg; String write_msg;
N_Cmd *next; N_Cmd *next;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -45,31 +45,31 @@ Struct(N_Cmd)
Enum(N_EventKind) Enum(N_EventKind)
{ {
N_EventKind_None, N_EventKind_None,
N_EventKind_ChannelOpened, N_EventKind_ChannelOpened,
N_EventKind_ChannelClosed, N_EventKind_ChannelClosed,
N_EventKind_Msg N_EventKind_Msg
}; };
Struct(N_Event) Struct(N_Event)
{ {
N_EventKind kind; N_EventKind kind;
N_ChannelId channel_id; N_ChannelId channel_id;
String msg; String msg;
N_Event *next; N_Event *next;
}; };
Struct(N_EventList) Struct(N_EventList)
{ {
N_Event *first; N_Event *first;
N_Event *last; N_Event *last;
}; };
Struct(N_ChannelLookupBin) Struct(N_ChannelLookupBin)
{ {
struct N_Channel *first; struct N_Channel *first;
struct N_Channel *last; struct N_Channel *last;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -81,42 +81,42 @@ Struct(N_ChannelLookupBin)
Enum(N_PacketKind) Enum(N_PacketKind)
{ {
N_PacketKind_None, N_PacketKind_None,
N_PacketKind_TryConnect, N_PacketKind_TryConnect,
N_PacketKind_ConnectSuccess, N_PacketKind_ConnectSuccess,
N_PacketKind_Disconnect, N_PacketKind_Disconnect,
N_PacketKind_Heartbeat, N_PacketKind_Heartbeat,
N_PacketKind_MsgChunk N_PacketKind_MsgChunk
}; };
Enum(N_PacketFlag) Enum(N_PacketFlag)
{ {
N_PacketFlag_None = 0, N_PacketFlag_None = 0,
N_PacketFlag_Reliable = (1 << 0) N_PacketFlag_Reliable = (1 << 0)
}; };
Struct(N_SndPacket) Struct(N_SndPacket)
{ {
N_SndPacket *next; N_SndPacket *next;
u64 seq; u64 seq;
u64 data_len; u64 data_len;
u8 data[N_MaxPacketLen]; u8 data[N_MaxPacketLen];
}; };
Struct(N_RcvPacket) Struct(N_RcvPacket)
{ {
P_Sock *sock; P_Sock *sock;
P_Address address; P_Address address;
String data; String data;
N_RcvPacket *next; N_RcvPacket *next;
}; };
Struct(N_RcvBuffer) Struct(N_RcvBuffer)
{ {
Arena *arena; Arena *arena;
N_RcvPacket *first_packet; N_RcvPacket *first_packet;
N_RcvPacket *last_packet; N_RcvPacket *last_packet;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -124,53 +124,53 @@ Struct(N_RcvBuffer)
Struct(N_Channel) Struct(N_Channel)
{ {
N_ChannelId id; N_ChannelId id;
b32 valid; b32 valid;
b32 connected; b32 connected;
struct N_Host *host; struct N_Host *host;
N_Channel *next_free; N_Channel *next_free;
P_Address address; P_Address address;
u64 address_hash; u64 address_hash;
N_Channel *next_address_hash; N_Channel *next_address_hash;
N_Channel *prev_address_hash; N_Channel *prev_address_hash;
/* NOTE: Packets are allocated in host's `arena` */ /* NOTE: Packets are allocated in host's `arena` */
N_SndPacket *first_reliable_packet; N_SndPacket *first_reliable_packet;
N_SndPacket *last_reliable_packet; N_SndPacket *last_reliable_packet;
N_SndPacket *first_unreliable_packet; N_SndPacket *first_unreliable_packet;
N_SndPacket *last_unreliable_packet; N_SndPacket *last_unreliable_packet;
u64 num_reliable_packets; u64 num_reliable_packets;
u64 num_unreliable_packets; u64 num_unreliable_packets;
/* NOTE: Msg assemblers are allocated in host's `arena` */ /* NOTE: Msg assemblers are allocated in host's `arena` */
struct N_MsgAssembler *least_recent_msg_assembler; struct N_MsgAssembler *least_recent_msg_assembler;
struct N_MsgAssembler *most_recent_msg_assembler; struct N_MsgAssembler *most_recent_msg_assembler;
u16 last_heartbeat_received_id; u16 last_heartbeat_received_id;
u16 last_heartbeat_acked_id; u16 last_heartbeat_acked_id;
i64 last_heartbeat_acked_ns; i64 last_heartbeat_acked_ns;
i64 last_heartbeat_rtt_ns; i64 last_heartbeat_rtt_ns;
u64 last_sent_msg_id; u64 last_sent_msg_id;
u64 their_acked_seq; u64 their_acked_seq;
u64 our_acked_seq; u64 our_acked_seq;
u64 last_sent_seq; u64 last_sent_seq;
i64 last_packet_received_ns; i64 last_packet_received_ns;
}; };
Struct(N_ChannelNode) Struct(N_ChannelNode)
{ {
N_Channel *channel; N_Channel *channel;
N_ChannelNode *next; N_ChannelNode *next;
}; };
Struct(N_ChannelList) Struct(N_ChannelList)
{ {
N_ChannelNode *first; N_ChannelNode *first;
N_ChannelNode *last; N_ChannelNode *last;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -178,38 +178,38 @@ Struct(N_ChannelList)
Struct(N_MsgAssembler) Struct(N_MsgAssembler)
{ {
N_Channel *channel; N_Channel *channel;
b32 is_reliable; b32 is_reliable;
/* Free list */ /* Free list */
N_MsgAssembler *next_free; N_MsgAssembler *next_free;
/* Bucket list */ /* Bucket list */
N_MsgAssembler *next_hash; N_MsgAssembler *next_hash;
N_MsgAssembler *prev_hash; N_MsgAssembler *prev_hash;
/* Channel list */ /* Channel list */
N_MsgAssembler *less_recent; N_MsgAssembler *less_recent;
N_MsgAssembler *more_recent; N_MsgAssembler *more_recent;
u64 msg_id; u64 msg_id;
u64 hash; u64 hash;
u64 last_chunk_len; u64 last_chunk_len;
u64 num_chunks_total; u64 num_chunks_total;
u64 num_chunks_received; u64 num_chunks_received;
i64 touched_ns; i64 touched_ns;
BuddyBlock *buddy_block; BuddyBlock *buddy_block;
u8 *chunk_bitmap; u8 *chunk_bitmap;
u8 *chunk_data; u8 *chunk_data;
}; };
Struct(N_MsgAssemblerLookupBin) Struct(N_MsgAssemblerLookupBin)
{ {
N_MsgAssembler *first; N_MsgAssembler *first;
N_MsgAssembler *last; N_MsgAssembler *last;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -220,38 +220,38 @@ Struct(N_MsgAssemblerLookupBin)
Struct(N_Host) Struct(N_Host)
{ {
Arena *arena; Arena *arena;
P_Sock *sock; P_Sock *sock;
BuddyCtx *buddy; /* For storing msg assembler data */ BuddyCtx *buddy; /* For storing msg assembler data */
Arena *cmd_arena; Arena *cmd_arena;
N_Cmd *first_cmd; N_Cmd *first_cmd;
N_Cmd *last_cmd; N_Cmd *last_cmd;
N_Cmd *first_free_cmd; N_Cmd *first_free_cmd;
Arena *channel_arena; Arena *channel_arena;
N_Channel *channels; N_Channel *channels;
N_Channel *first_free_channel; N_Channel *first_free_channel;
u64 num_channels_reserved; u64 num_channels_reserved;
N_SndPacket *first_free_packet; /* Acquired in `arena` */ N_SndPacket *first_free_packet; /* Acquired in `arena` */
N_MsgAssembler *first_free_msg_assembler; /* Acquired in `arena` */ N_MsgAssembler *first_free_msg_assembler; /* Acquired in `arena` */
N_ChannelLookupBin *channel_lookup_bins; /* Acquired in `arena` */ N_ChannelLookupBin *channel_lookup_bins; /* Acquired in `arena` */
u64 num_channel_lookup_bins; u64 num_channel_lookup_bins;
N_MsgAssemblerLookupBin *msg_assembler_lookup_bins; /* Acquired in `arena` */ N_MsgAssemblerLookupBin *msg_assembler_lookup_bins; /* Acquired in `arena` */
u64 num_msg_assembler_lookup_bins; u64 num_msg_assembler_lookup_bins;
/* Double buffer for incoming data */ /* Double buffer for incoming data */
Mutex rcv_buffer_write_mutex; Mutex rcv_buffer_write_mutex;
N_RcvBuffer *rcv_buffer_read; N_RcvBuffer *rcv_buffer_read;
N_RcvBuffer *rcv_buffer_write; N_RcvBuffer *rcv_buffer_write;
u64 bytes_received; u64 bytes_received;
u64 bytes_sent; u64 bytes_sent;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////

View File

@ -9,22 +9,22 @@ Struct(P_Sock);
Struct(P_File) Struct(P_File)
{ {
u64 handle; u64 handle;
b32 valid; b32 valid;
}; };
Struct(P_FileTime) Struct(P_FileTime)
{ {
DateTime created; DateTime created;
DateTime accessed; DateTime accessed;
DateTime modified; DateTime modified;
}; };
Struct(P_FileMap) Struct(P_FileMap)
{ {
String mapped_memory; String mapped_memory;
u64 handle; u64 handle;
b32 valid; b32 valid;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -32,17 +32,17 @@ Struct(P_FileMap)
Enum(P_AddressFamily) Enum(P_AddressFamily)
{ {
P_AddressFamily_Ipv4, P_AddressFamily_Ipv4,
P_AddressFamily_Ipv6 P_AddressFamily_Ipv6
}; };
Struct(P_Address) Struct(P_Address)
{ {
b32 valid; b32 valid;
P_AddressFamily family; P_AddressFamily family;
/* NOTE: ipnb & portnb are stored in network byte order */ /* NOTE: ipnb & portnb are stored in network byte order */
u8 ipnb[16]; u8 ipnb[16];
u16 portnb; u16 portnb;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -50,9 +50,9 @@ Struct(P_Address)
Struct(P_SockReadResult) Struct(P_SockReadResult)
{ {
b32 valid; /* Since data.len = 0 can be valid */ b32 valid; /* Since data.len = 0 can be valid */
P_Address address; P_Address address;
String data; String data;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -60,10 +60,10 @@ Struct(P_SockReadResult)
Enum(P_MessageBoxKind) Enum(P_MessageBoxKind)
{ {
P_MessageBoxKind_Ok, P_MessageBoxKind_Ok,
P_MessageBoxKind_Warning, P_MessageBoxKind_Warning,
P_MessageBoxKind_Error, P_MessageBoxKind_Error,
P_MessageBoxKind_Fatal P_MessageBoxKind_Fatal
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////

File diff suppressed because it is too large Load Diff

View File

@ -2,15 +2,15 @@
//~ Win32 libs //~ Win32 libs
#pragma warning(push, 0) #pragma warning(push, 0)
# include <WinSock2.h> #include <WinSock2.h>
# include <TlHelp32.h> #include <TlHelp32.h>
# include <WS2tcpip.h> #include <WS2tcpip.h>
# include <windowsx.h> #include <windowsx.h>
# include <ShlObj_core.h> #include <ShlObj_core.h>
# include <fileapi.h> #include <fileapi.h>
# include <dwmapi.h> #include <dwmapi.h>
# include <avrt.h> #include <avrt.h>
# include <shellapi.h> #include <shellapi.h>
#pragma warning(pop) #pragma warning(pop)
#pragma comment(lib, "kernel32") #pragma comment(lib, "kernel32")
@ -28,10 +28,10 @@
Struct(P_W32_Watch) Struct(P_W32_Watch)
{ {
HANDLE dir_handle; HANDLE dir_handle;
HANDLE wake_handle; HANDLE wake_handle;
P_W32_Watch *next_free; P_W32_Watch *next_free;
u8 results_buff[Kibi(64)]; u8 results_buff[Kibi(64)];
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -39,15 +39,15 @@ Struct(P_W32_Watch)
Struct(P_W32_Address) Struct(P_W32_Address)
{ {
i32 size; i32 size;
i32 family; i32 family;
union union
{ {
struct sockaddr_storage sas; struct sockaddr_storage sas;
struct sockaddr sa; struct sockaddr sa;
struct sockaddr_in sin; struct sockaddr_in sin;
struct sockaddr_in6 sin6; struct sockaddr_in6 sin6;
}; };
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -55,8 +55,8 @@ Struct(P_W32_Address)
Struct(P_W32_Sock) Struct(P_W32_Sock)
{ {
SOCKET sock; SOCKET sock;
P_W32_Sock *next_free; P_W32_Sock *next_free;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -67,20 +67,20 @@ Struct(P_W32_Sock)
Struct(P_W32_SharedState) Struct(P_W32_SharedState)
{ {
//- Watches pool //- Watches pool
Mutex watches_mutex; Mutex watches_mutex;
Arena *watches_arena; Arena *watches_arena;
P_W32_Watch *watches_first_free; P_W32_Watch *watches_first_free;
//- Socket pool //- Socket pool
WSADATA wsa_data; WSADATA wsa_data;
Arena *socks_arena; Arena *socks_arena;
Mutex socks_mutex; Mutex socks_mutex;
P_W32_Sock *first_free_sock; P_W32_Sock *first_free_sock;
//- Timer //- Timer
Fence timer_fence; Fence timer_fence;
Atomic64Padded average_timer_period_ns; Atomic64Padded average_timer_period_ns;
} extern P_W32_shared_state; } extern P_W32_shared_state;
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////

View File

@ -11,12 +11,12 @@ PB_WSP_SharedState PB_WSP_shared_state = ZI;
void PB_Bootstrap(void) void PB_Bootstrap(void)
{ {
PB_WSP_SharedState *g = &PB_WSP_shared_state; PB_WSP_SharedState *g = &PB_WSP_shared_state;
PB_WSP_InitializeWasapi(); PB_WSP_InitializeWasapi();
/* Start playback job */ /* Start playback job */
JobPoolId playback_pool = InitJobPool(1, Lit("Playback"), JobPoolPriority_Audio); JobPoolId playback_pool = InitJobPool(1, Lit("Playback"), JobPoolPriority_Audio);
g->shutdown_jobs_count += RunJob(PB_WSP_Playback, .pool = playback_pool, .fence = &g->shutdown_jobs_fence); g->shutdown_jobs_count += RunJob(PB_WSP_Playback, .pool = playback_pool, .fence = &g->shutdown_jobs_fence);
OnExit(&PB_WSP_Shutdown); OnExit(&PB_WSP_Shutdown);
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -24,102 +24,102 @@ void PB_Bootstrap(void)
ExitFuncDef(PB_WSP_Shutdown) ExitFuncDef(PB_WSP_Shutdown)
{ {
PB_WSP_SharedState *g = &PB_WSP_shared_state; PB_WSP_SharedState *g = &PB_WSP_shared_state;
Atomic32Set(&g->shutdown, 1); Atomic32Set(&g->shutdown, 1);
YieldOnFence(&g->shutdown_jobs_fence, g->shutdown_jobs_count); YieldOnFence(&g->shutdown_jobs_fence, g->shutdown_jobs_count);
} }
void PB_WSP_InitializeWasapi(void) void PB_WSP_InitializeWasapi(void)
{ {
PB_WSP_SharedState *g = &PB_WSP_shared_state; PB_WSP_SharedState *g = &PB_WSP_shared_state;
u64 sample_rate = PB_SampleRate; u64 sample_rate = PB_SampleRate;
u64 channel_count = 2; u64 channel_count = 2;
u32 channel_mask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT; u32 channel_mask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
/* Create enumerator to get audio device */ /* Create enumerator to get audio device */
IMMDeviceEnumerator *enumerator; IMMDeviceEnumerator *enumerator;
CoCreateInstance(&CLSID_MMDeviceEnumerator, 0, CLSCTX_ALL, &IID_IMMDeviceEnumerator, (LPVOID *)&enumerator); CoCreateInstance(&CLSID_MMDeviceEnumerator, 0, CLSCTX_ALL, &IID_IMMDeviceEnumerator, (LPVOID *)&enumerator);
/* Get default playback device */ /* Get default playback device */
IMMDevice *device; IMMDevice *device;
IMMDeviceEnumerator_GetDefaultAudioEndpoint(enumerator, eRender, eConsole, &device); IMMDeviceEnumerator_GetDefaultAudioEndpoint(enumerator, eRender, eConsole, &device);
IMMDeviceEnumerator_Release(enumerator); IMMDeviceEnumerator_Release(enumerator);
/* Create audio client for device */ /* Create audio client for device */
IMMDevice_Activate(device, &IID_IAudioClient, CLSCTX_ALL, 0, (LPVOID *)&g->client); IMMDevice_Activate(device, &IID_IAudioClient, CLSCTX_ALL, 0, (LPVOID *)&g->client);
IMMDevice_Release(device); IMMDevice_Release(device);
WAVEFORMATEXTENSIBLE format_ex = { WAVEFORMATEXTENSIBLE format_ex = {
.Format = { .Format = {
.wFormatTag = WAVE_FORMAT_EXTENSIBLE, .wFormatTag = WAVE_FORMAT_EXTENSIBLE,
.nChannels = (WORD)channel_count, .nChannels = (WORD)channel_count,
.nSamplesPerSec = (WORD)sample_rate, .nSamplesPerSec = (WORD)sample_rate,
.nAvgBytesPerSec = (DWORD)(sample_rate * channel_count * sizeof(f32)), .nAvgBytesPerSec = (DWORD)(sample_rate * channel_count * sizeof(f32)),
.nBlockAlign = (WORD)(channel_count * sizeof(f32)), .nBlockAlign = (WORD)(channel_count * sizeof(f32)),
.wBitsPerSample = (WORD)(8 * sizeof(f32)), .wBitsPerSample = (WORD)(8 * sizeof(f32)),
.cbSize = sizeof(format_ex) - sizeof(format_ex.Format), .cbSize = sizeof(format_ex) - sizeof(format_ex.Format),
}, },
.Samples.wValidBitsPerSample = 8 * sizeof(f32), .Samples.wValidBitsPerSample = 8 * sizeof(f32),
.dwChannelMask = channel_mask, .dwChannelMask = channel_mask,
.SubFormat = MEDIASUBTYPE_IEEE_FLOAT, .SubFormat = MEDIASUBTYPE_IEEE_FLOAT,
}; };
WAVEFORMATEX *wfx = &format_ex.Format; WAVEFORMATEX *wfx = &format_ex.Format;
#if 0 #if 0
b32 client_initialized = 0; b32 client_initialized = 0;
IAudioClient3 *client3; IAudioClient3 *client3;
if (SUCCEEDED(IAudioClient_QueryInterface(g->client, &IID_IAudioClient3, (LPVOID *)&client3))) if (SUCCEEDED(IAudioClient_QueryInterface(g->client, &IID_IAudioClient3, (LPVOID *)&client3)))
{
/* From Martins: Minimum buffer size will typically be 480 samples (10msec @ 48khz)
* but it can be 128 samples (2.66 msec @ 48khz) if driver is properly installed
* see bullet-point instructions here: https://learn.microsoft.com/en-us/windows-hardware/drivers/audio/low-latency-audio#measurement-tools
*/
UINT32 default_period_samples, fundamental_period_samples, min_period_samples, max_period_samples;
IAudioClient3_GetSharedModeEnginePeriod(client3, wfx, &default_period_samples, &fundamental_period_samples, &min_period_samples, &max_period_samples);
const DWORD flags = AUDCLNT_STREAMFLAGS_EVENTCALLBACK;
if (SUCCEEDED(IAudioClient3_InitializeSharedAudioStream(client3, flags, min_period_samples, wfx, 0)))
{ {
/* From Martins: Minimum buffer size will typically be 480 samples (10msec @ 48khz) client_initialized = 1;
* but it can be 128 samples (2.66 msec @ 48khz) if driver is properly installed
* see bullet-point instructions here: https://learn.microsoft.com/en-us/windows-hardware/drivers/audio/low-latency-audio#measurement-tools
*/
UINT32 default_period_samples, fundamental_period_samples, min_period_samples, max_period_samples;
IAudioClient3_GetSharedModeEnginePeriod(client3, wfx, &default_period_samples, &fundamental_period_samples, &min_period_samples, &max_period_samples);
const DWORD flags = AUDCLNT_STREAMFLAGS_EVENTCALLBACK;
if (SUCCEEDED(IAudioClient3_InitializeSharedAudioStream(client3, flags, min_period_samples, wfx, 0)))
{
client_initialized = 1;
}
IAudioClient3_Release(client3);
}
#else
b32 client_initialized = 0;
#endif
if (!client_initialized)
{
/* Get duration for shared-mode streams, this will typically be 480 samples (10msec @ 48khz) */
REFERENCE_TIME duration;
IAudioClient_GetDevicePeriod(g->client, &duration, 0);
/* Initialize audio playback
*
* NOTE:
* Passing AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM will tell WASAPI to
* always convert to native mixing format. This may introduce latency
* but allows for any input format.
*/
const DWORD flags = AUDCLNT_STREAMFLAGS_EVENTCALLBACK | AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM | AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY;
IAudioClient_Initialize(g->client, AUDCLNT_SHAREMODE_SHARED, flags, duration, 0, wfx, 0);
} }
IAudioClient_GetMixFormat(g->client, &g->buffer_format); IAudioClient3_Release(client3);
}
#else
b32 client_initialized = 0;
#endif
/* Set up event handler to wait on */ if (!client_initialized)
g->event = CreateEventW(0, 0, 0, 0); {
IAudioClient_SetEventHandle(g->client, g->event); /* Get duration for shared-mode streams, this will typically be 480 samples (10msec @ 48khz) */
REFERENCE_TIME duration;
IAudioClient_GetDevicePeriod(g->client, &duration, 0);
/* Get playback client */ /* Initialize audio playback
IAudioClient_GetService(g->client, &IID_IAudioRenderClient, (LPVOID *)&g->playback); *
* NOTE:
* Passing AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM will tell WASAPI to
* always convert to native mixing format. This may introduce latency
* but allows for any input format.
*/
const DWORD flags = AUDCLNT_STREAMFLAGS_EVENTCALLBACK | AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM | AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY;
IAudioClient_Initialize(g->client, AUDCLNT_SHAREMODE_SHARED, flags, duration, 0, wfx, 0);
}
/* Start the playback */ IAudioClient_GetMixFormat(g->client, &g->buffer_format);
IAudioClient_Start(g->client);
/* Get audio buffer size in samples */ /* Set up event handler to wait on */
IAudioClient_GetBufferSize(g->client, &g->buffer_frames); g->event = CreateEventW(0, 0, 0, 0);
IAudioClient_SetEventHandle(g->client, g->event);
/* Get playback client */
IAudioClient_GetService(g->client, &IID_IAudioRenderClient, (LPVOID *)&g->playback);
/* Start the playback */
IAudioClient_Start(g->client);
/* Get audio buffer size in samples */
IAudioClient_GetBufferSize(g->client, &g->buffer_frames);
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -127,54 +127,55 @@ void PB_WSP_InitializeWasapi(void)
PB_WSP_Buff PB_WSP_BeginUpdate(void) PB_WSP_Buff PB_WSP_BeginUpdate(void)
{ {
PB_WSP_SharedState *g = &PB_WSP_shared_state; PB_WSP_SharedState *g = &PB_WSP_shared_state;
PB_WSP_Buff wspbuf = ZI; PB_WSP_Buff wspbuf = ZI;
/* Get padding frames */ /* Get padding frames */
u32 padding_frames; u32 padding_frames;
IAudioClient_GetCurrentPadding(g->client, &padding_frames); IAudioClient_GetCurrentPadding(g->client, &padding_frames);
/* Get output buffer from WASAPI */ /* Get output buffer from WASAPI */
wspbuf.frames_count = 0; wspbuf.frames_count = 0;
if (padding_frames <= g->buffer_frames) if (padding_frames <= g->buffer_frames)
{ {
wspbuf.frames_count = g->buffer_frames - padding_frames; wspbuf.frames_count = g->buffer_frames - padding_frames;
} }
IAudioRenderClient_GetBuffer(g->playback, wspbuf.frames_count, &wspbuf.frames); IAudioRenderClient_GetBuffer(g->playback, wspbuf.frames_count, &wspbuf.frames);
return wspbuf; return wspbuf;
} }
void PB_WSP_EndUpdate(PB_WSP_Buff *wspbuf, MIX_PcmF32 src) void PB_WSP_EndUpdate(PB_WSP_Buff *wspbuf, MIX_PcmF32 src)
{ {
PB_WSP_SharedState *g = &PB_WSP_shared_state; PB_WSP_SharedState *g = &PB_WSP_shared_state;
u32 frames_in_source = src.count / 2; u32 frames_in_source = src.count / 2;
u32 frames_in_output = wspbuf->frames_count; u32 frames_in_output = wspbuf->frames_count;
u32 flags = 0; u32 flags = 0;
if (frames_in_source == frames_in_output) if (frames_in_source == frames_in_output)
{ {
/* Copy bytes to output */ /* Copy bytes to output */
u32 bytes_per_sample = g->buffer_format->nBlockAlign / g->buffer_format->nChannels; u32 bytes_per_sample = g->buffer_format->nBlockAlign / g->buffer_format->nChannels;
u32 write_size = frames_in_source * 2 * bytes_per_sample; u32 write_size = frames_in_source * 2 * bytes_per_sample;
CopyBytes(wspbuf->frames, src.samples, write_size); CopyBytes(wspbuf->frames, src.samples, write_size);
} }
else else
{ {
/* Submit silence if not enough samples */ /* Submit silence if not enough samples */
flags = AUDCLNT_BUFFERFLAGS_SILENT; flags |= AUDCLNT_BUFFERFLAGS_SILENT;
/* This shouldn't occur, mixer should be generating samples equivilent /* This shouldn't occur, mixer should be generating samples equivilent
* to value returned from `PB_WSP_BeginUpdate`. */ * to value returned from `PB_WSP_BeginUpdate`. */
Assert(0); Assert(0);
} }
#if !AUDIO_ENABLED if (!AUDIO_ENABLED)
flags = AUDCLNT_BUFFERFLAGS_SILENT; {
#endif flags |= AUDCLNT_BUFFERFLAGS_SILENT;
}
/* Submit output buffer to WASAPI */ /* Submit output buffer to WASAPI */
IAudioRenderClient_ReleaseBuffer(g->playback, frames_in_source, flags); IAudioRenderClient_ReleaseBuffer(g->playback, frames_in_source, flags);
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -182,22 +183,22 @@ void PB_WSP_EndUpdate(PB_WSP_Buff *wspbuf, MIX_PcmF32 src)
JobImpl(PB_WSP_Playback, sig, id) JobImpl(PB_WSP_Playback, sig, id)
{ {
PB_WSP_SharedState *g = &PB_WSP_shared_state; PB_WSP_SharedState *g = &PB_WSP_shared_state;
/* FIXME: If playback fails at any point and mixer stops advancing, we /* FIXME: If playback fails at any point and mixer stops advancing, we
* need to halt mixer to prevent memory leak when sounds are played. */ * need to halt mixer to prevent memory leak when sounds are played. */
/* TODO: Signal counter that running job wiats on, rather than scheduling job manually */ /* TODO: Signal counter that running job wiats on, rather than scheduling job manually */
while (!Atomic32Fetch(&g->shutdown)) while (!Atomic32Fetch(&g->shutdown))
{
TempArena scratch = BeginScratchNoConflict();
{ {
TempArena scratch = BeginScratchNoConflict(); WaitForSingleObject(g->event, INFINITE);
{
WaitForSingleObject(g->event, INFINITE);
}
{
PB_WSP_Buff wspbuf = PB_WSP_BeginUpdate();
MIX_PcmF32 pcm = MIX_MixAllTracks(scratch.arena, wspbuf.frames_count);
PB_WSP_EndUpdate(&wspbuf, pcm);
}
EndScratch(scratch);
} }
{
PB_WSP_Buff wspbuf = PB_WSP_BeginUpdate();
MIX_PcmF32 pcm = MIX_MixAllTracks(scratch.arena, wspbuf.frames_count);
PB_WSP_EndUpdate(&wspbuf, pcm);
}
EndScratch(scratch);
}
} }

View File

@ -2,8 +2,8 @@
//~ Win32 libs //~ Win32 libs
#pragma warning(push, 0) #pragma warning(push, 0)
# include <Audioclient.h> #include <Audioclient.h>
# include <mmdeviceapi.h> #include <mmdeviceapi.h>
#pragma warning(pop) #pragma warning(pop)
DEFINE_GUID(CLSID_MMDeviceEnumerator, 0xbcde0395, 0xe52f, 0x467c, 0x8e, 0x3d, 0xc4, 0x57, 0x92, 0x91, 0x69, 0x2e); DEFINE_GUID(CLSID_MMDeviceEnumerator, 0xbcde0395, 0xe52f, 0x467c, 0x8e, 0x3d, 0xc4, 0x57, 0x92, 0x91, 0x69, 0x2e);
@ -17,8 +17,8 @@ DEFINE_GUID(IID_IAudioRenderClient, 0xf294acfc, 0x3146, 0x4483, 0xa7, 0xbf, 0x
Struct(PB_WSP_Buff) Struct(PB_WSP_Buff)
{ {
u32 frames_count; u32 frames_count;
u8 *frames; u8 *frames;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -26,14 +26,14 @@ Struct(PB_WSP_Buff)
Struct(PB_WSP_SharedState) Struct(PB_WSP_SharedState)
{ {
Atomic32 shutdown; Atomic32 shutdown;
IAudioClient *client; IAudioClient *client;
HANDLE event; HANDLE event;
IAudioRenderClient *playback; IAudioRenderClient *playback;
WAVEFORMATEX *buffer_format; WAVEFORMATEX *buffer_format;
u32 buffer_frames; u32 buffer_frames;
Fence shutdown_jobs_fence; Fence shutdown_jobs_fence;
u32 shutdown_jobs_count; u32 shutdown_jobs_count;
} extern PB_WSP_shared_state; } extern PB_WSP_shared_state;
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////

View File

@ -1,9 +1,9 @@
S_Ctx S = Zi; S_Ctx S = Zi;
Readonly S_ReadonlyCtx S_ro = { Readonly S_ReadonlyCtx S_ro = {
.nil_ent = { .nil_ent = {
.xf = CompXformIdentity .xf = CompXformIdentity
} }
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -11,26 +11,26 @@ Readonly S_ReadonlyCtx S_ro = {
void S_Bootstrap(void) void S_Bootstrap(void)
{ {
/* Initialize shared state */ /* Initialize shared state */
for (u64 i = 0; i < countof(S.input_states); ++i) for (u64 i = 0; i < countof(S.input_states); ++i)
{ {
S_InputState *input = &S.input_states[i]; S_InputState *input = &S.input_states[i];
input->arena = AcquireArena(Gibi(64)); input->arena = AcquireArena(Gibi(64));
} }
for (u64 i = 0; i < countof(S.output_states); ++i) for (u64 i = 0; i < countof(S.output_states); ++i)
{ {
S_OutputState *output = &S.output_states[i]; S_OutputState *output = &S.output_states[i];
output->arena = AcquireArena(Gibi(64)); output->arena = AcquireArena(Gibi(64));
} }
/* Dispatch sim wave */ /* Dispatch sim wave */
DispatchWave(Lit("Sim"), 1, S_TickForever, 0); DispatchWave(Lit("Sim"), 1, S_TickForever, 0);
} }
void S_Shutdown(void) void S_Shutdown(void)
{ {
Atomic32Set(&S.shutdown, 1); Atomic32Set(&S.shutdown, 1);
YieldOnFence(&S.worker_completion_fence, S.workers_count); YieldOnFence(&S.worker_completion_fence, S.workers_count);
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -38,17 +38,17 @@ void S_Shutdown(void)
b32 S_IsKeyNil(S_Key key) b32 S_IsKeyNil(S_Key key)
{ {
return key.v.hi == 0 && key.v.lo == 0; return key.v.hi == 0 && key.v.lo == 0;
} }
b32 S_IsEntNil(S_Ent *ent) b32 S_IsEntNil(S_Ent *ent)
{ {
return ent == 0 || ent == &S_ro.nil_ent; return ent == 0 || ent == &S_ro.nil_ent;
} }
b32 S_MatchKey(S_Key a, S_Key b) b32 S_MatchKey(S_Key a, S_Key b)
{ {
return a.v.hi == b.v.hi && a.v.lo == b.v.lo; return a.v.hi == b.v.hi && a.v.lo == b.v.lo;
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -56,10 +56,10 @@ b32 S_MatchKey(S_Key a, S_Key b)
S_Key S_RandKey(void) S_Key S_RandKey(void)
{ {
/* TODO: Don't use true randomness for entity keys. It's overkill & non-deterministic. */ /* TODO: Don't use true randomness for entity keys. It's overkill & non-deterministic. */
S_Key result = Zi; S_Key result = Zi;
TrueRand(StringFromStruct(&result)); TrueRand(StringFromStruct(&result));
return result; return result;
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -67,26 +67,26 @@ S_Key S_RandKey(void)
Rng2I32 S_UpdateTilesInPlaceFromPlacement(u8 *tiles, S_TilePlacement placement) Rng2I32 S_UpdateTilesInPlaceFromPlacement(u8 *tiles, S_TilePlacement placement)
{ {
Rng2I32 dirty_rect = Zi; Rng2I32 dirty_rect = Zi;
switch (placement.placement_kind) switch (placement.placement_kind)
{
case S_TilePlacementKind_Range:
{ {
case S_TilePlacementKind_Range: S_TileKind tile = placement.tile_kind;
Rng2I32 range = placement.range;
for (i32 tile_y = range.p0.y; tile_y < range.p1.y; ++tile_y)
{
for (i32 tile_x = range.p0.x; tile_x < range.p1.x; ++tile_x)
{ {
S_TileKind tile = placement.tile_kind; Vec2I32 tile_pos = VEC2I32(tile_x, tile_y);
Rng2I32 range = placement.range; i32 tile_idx = S_TileIdxFromTilePos(tile_pos);
for (i32 tile_y = range.p0.y; tile_y < range.p1.y; ++tile_y) tiles[tile_idx] = (u8)tile;
{ }
for (i32 tile_x = range.p0.x; tile_x < range.p1.x; ++tile_x) }
{ dirty_rect = range;
Vec2I32 tile_pos = VEC2I32(tile_x, tile_y); } break;
i32 tile_idx = S_TileIdxFromTilePos(tile_pos); }
tiles[tile_idx] = (u8)tile; return dirty_rect;
}
}
dirty_rect = range;
} break;
}
return dirty_rect;
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -94,52 +94,52 @@ Rng2I32 S_UpdateTilesInPlaceFromPlacement(u8 *tiles, S_TilePlacement placement)
S_Shape S_ShapeFromDescEx(S_ShapeDesc desc) S_Shape S_ShapeFromDescEx(S_ShapeDesc desc)
{ {
desc.count = MaxI32(desc.count, 1); desc.count = MaxI32(desc.count, 1);
S_Shape result = Zi; S_Shape result = Zi;
{
result.points_count = desc.count;
CopyStructs(result.points, desc.points, result.points_count);
Vec2 accum = Zi;
for (i32 p_idx = 0; p_idx < result.points_count; ++p_idx)
{ {
result.points_count = desc.count; accum = AddVec2(accum, result.points[p_idx]);
CopyStructs(result.points, desc.points, result.points_count);
Vec2 accum = Zi;
for (i32 p_idx = 0; p_idx < result.points_count; ++p_idx)
{
accum = AddVec2(accum, result.points[p_idx]);
}
result.centroid = DivVec2(accum, result.points_count);
result.center_of_mass = result.centroid;
result.radius = desc.radius;
result.mass = desc.mass;
} }
return result; result.centroid = DivVec2(accum, result.points_count);
result.center_of_mass = result.centroid;
result.radius = desc.radius;
result.mass = desc.mass;
}
return result;
} }
S_Shape S_MulXformShape(Xform xf, S_Shape shape) S_Shape S_MulXformShape(Xform xf, S_Shape shape)
{ {
S_Shape result = shape; S_Shape result = shape;
for (i32 i = 0; i < shape.points_count; ++i) for (i32 i = 0; i < shape.points_count; ++i)
{ {
result.points[i] = MulXformV2(xf, shape.points[i]); result.points[i] = MulXformV2(xf, shape.points[i]);
} }
Vec2 scale = ScaleFromXform(xf); Vec2 scale = ScaleFromXform(xf);
result.radius *= MaxF32(scale.x, scale.y); result.radius *= MaxF32(scale.x, scale.y);
return result; return result;
} }
Vec2 S_SupportPointFromShape(S_Shape shape, Vec2 dir) Vec2 S_SupportPointFromShape(S_Shape shape, Vec2 dir)
{ {
Vec2 result = Zi; Vec2 result = Zi;
f32 max_dot = -F32Infinity; f32 max_dot = -F32Infinity;
for (i32 i = 0; i < shape.points_count; ++i) for (i32 i = 0; i < shape.points_count; ++i)
{
Vec2 p = shape.points[i];
f32 dot = DotVec2(p, dir);
if (dot > max_dot)
{ {
Vec2 p = shape.points[i]; max_dot = dot;
f32 dot = DotVec2(p, dir); result = p;
if (dot > max_dot)
{
max_dot = dot;
result = p;
}
} }
result = AddVec2(result, MulVec2(dir, shape.radius)); }
return result; result = AddVec2(result, MulVec2(dir, shape.radius));
return result;
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -147,46 +147,46 @@ Vec2 S_SupportPointFromShape(S_Shape shape, Vec2 dir)
S_Lookup S_LookupFromWorld(Arena *arena, S_World *world) S_Lookup S_LookupFromWorld(Arena *arena, S_World *world)
{ {
S_Lookup lookup = Zi; S_Lookup lookup = Zi;
lookup.bins_count = 4096; lookup.bins_count = 4096;
lookup.bins = PushStructs(arena, S_LookupEntNode *, lookup.bins_count); lookup.bins = PushStructs(arena, S_LookupEntNode *, lookup.bins_count);
for (i64 ent_idx = 0; ent_idx < world->ents_count; ++ent_idx) for (i64 ent_idx = 0; ent_idx < world->ents_count; ++ent_idx)
{
S_Ent *ent = &world->ents[ent_idx];
if (ent->active)
{ {
S_Ent *ent = &world->ents[ent_idx]; S_Key key = ent->key;
if (ent->active) S_LookupEntNode *n = PushStruct(arena, S_LookupEntNode);
{ n->ent = ent;
S_Key key = ent->key; S_LookupEntNode **bin = &lookup.bins[ent->key.v.lo % lookup.bins_count];
S_LookupEntNode *n = PushStruct(arena, S_LookupEntNode); SllStackPush(*bin, n);
n->ent = ent;
S_LookupEntNode **bin = &lookup.bins[ent->key.v.lo % lookup.bins_count];
SllStackPush(*bin, n);
}
} }
}
return lookup; return lookup;
} }
S_Ent *S_EntFromKey(S_Lookup *lookup, S_Key key) S_Ent *S_EntFromKey(S_Lookup *lookup, S_Key key)
{ {
S_Ent *result = &S_ro.nil_ent; S_Ent *result = &S_ro.nil_ent;
if (!S_IsKeyNil(key)) if (!S_IsKeyNil(key))
{
i64 bins_count = lookup->bins_count;
if (bins_count > 0)
{ {
i64 bins_count = lookup->bins_count; S_LookupEntNode *n = lookup->bins[key.v.lo % bins_count];
if (bins_count > 0) for (; n; n = n->next)
{
if (S_MatchKey(n->ent->key, key))
{ {
S_LookupEntNode *n = lookup->bins[key.v.lo % bins_count]; result = n->ent;
for (; n; n = n->next) break;
{
if (S_MatchKey(n->ent->key, key))
{
result = n->ent;
break;
}
}
} }
}
} }
return result; }
return result;
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -194,29 +194,29 @@ S_Ent *S_EntFromKey(S_Lookup *lookup, S_Key key)
S_Ent *S_FirstEnt(S_Iter *iter, S_World *world) S_Ent *S_FirstEnt(S_Iter *iter, S_World *world)
{ {
ZeroStruct(iter); ZeroStruct(iter);
iter->world = world; iter->world = world;
return S_NextEnt(iter); return S_NextEnt(iter);
} }
S_Ent *S_NextEnt(S_Iter *iter) S_Ent *S_NextEnt(S_Iter *iter)
{ {
S_World *world = iter->world; S_World *world = iter->world;
S_Ent *result = &S_ro.nil_ent; S_Ent *result = &S_ro.nil_ent;
i64 ent_idx = iter->cur_idx; i64 ent_idx = iter->cur_idx;
for (; ent_idx < world->ents_count; ++ent_idx) for (; ent_idx < world->ents_count; ++ent_idx)
{
S_Ent *ent = &world->ents[ent_idx];
if (ent->active)
{ {
S_Ent *ent = &world->ents[ent_idx]; result = ent;
if (ent->active) break;
{
result = ent;
break;
}
} }
iter->cur_idx = ent_idx + 1; }
iter->cur_idx = ent_idx + 1;
return result; return result;
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -224,15 +224,15 @@ S_Ent *S_NextEnt(S_Iter *iter)
S_World *S_WorldFromSnapshot(Arena *arena, S_Snapshot *snapshot) S_World *S_WorldFromSnapshot(Arena *arena, S_Snapshot *snapshot)
{ {
S_World *world = PushStruct(arena, S_World); S_World *world = PushStruct(arena, S_World);
/* Copy ents */ /* Copy ents */
world->ents = PushStructsNoZero(arena, S_Ent, snapshot->ents_count); world->ents = PushStructsNoZero(arena, S_Ent, snapshot->ents_count);
CopyStructs(world->ents, snapshot->ents, snapshot->ents_count); CopyStructs(world->ents, snapshot->ents, snapshot->ents_count);
world->ents_count = snapshot->ents_count; world->ents_count = snapshot->ents_count;
world->tick = snapshot->tick; world->tick = snapshot->tick;
return world; return world;
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -240,20 +240,20 @@ S_World *S_WorldFromSnapshot(Arena *arena, S_Snapshot *snapshot)
MergesortCompareFuncDef(S_SortEntsByKeyCmp, arg_a, arg_b, _) MergesortCompareFuncDef(S_SortEntsByKeyCmp, arg_a, arg_b, _)
{ {
S_Ent *a = *(S_Ent **)arg_a; S_Ent *a = *(S_Ent **)arg_a;
S_Ent *b = *(S_Ent **)arg_b; S_Ent *b = *(S_Ent **)arg_b;
S_Key a_key = a->key; S_Key a_key = a->key;
S_Key b_key = b->key; S_Key b_key = b->key;
i32 result = 0; i32 result = 0;
if (result == 0) if (result == 0)
{ {
result = ((a_key.v.lo < b_key.v.lo) - (a_key.v.lo > b_key.v.lo)); result = ((a_key.v.lo < b_key.v.lo) - (a_key.v.lo > b_key.v.lo));
} }
if (result == 0) if (result == 0)
{ {
result = ((a_key.v.hi < b_key.v.hi) - (a_key.v.hi > b_key.v.hi)); result = ((a_key.v.hi < b_key.v.hi) - (a_key.v.hi > b_key.v.hi));
} }
return result; return result;
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -261,204 +261,204 @@ MergesortCompareFuncDef(S_SortEntsByKeyCmp, arg_a, arg_b, _)
void S_TickForever(WaveLaneCtx *lane) void S_TickForever(WaveLaneCtx *lane)
{ {
Arena *frame_arena = AcquireArena(Gibi(64)); Arena *frame_arena = AcquireArena(Gibi(64));
Arena *perm = PermArena(); Arena *perm = PermArena();
const i32 world_size = S_WorldSize; const i32 world_size = S_WorldSize;
//- World data //- World data
Arena *ents_arena = AcquireArena(Gibi(64)); Arena *ents_arena = AcquireArena(Gibi(64));
S_World *world = PushStruct(perm, S_World); S_World *world = PushStruct(perm, S_World);
world->ents = ArenaFirst(ents_arena, S_Ent); world->ents = ArenaFirst(ents_arena, S_Ent);
i64 first_free_ent_num = 0; i64 first_free_ent_num = 0;
i64 sim_time_ns = 0; i64 sim_time_ns = 0;
u8 *tiles = PushBytes(perm, world_size * world_size * 4, alignof(S_TileKind)); u8 *tiles = PushBytes(perm, world_size * world_size * 4, alignof(S_TileKind));
//////////////////////////////
//- Sim loop
b32 shutdown = 0;
while (!shutdown)
{
ResetArena(frame_arena);
S_Iter iter = Zi;
S_Lookup lookup = Zi;
////////////////////////////// //////////////////////////////
//- Sim loop //- Begin sim frame
b32 shutdown = 0; i64 frame_begin_ns = TimeNs();
while (!shutdown) i64 sim_dt_ns = NsFromSeconds(1) / SIM_TICKS_PER_SECOND;
f64 sim_dt = SecondsFromNs(sim_dt_ns);
world->tick += 1;
lookup = S_LookupFromWorld(frame_arena, world);
//////////////////////////////
//- Pop sim commands
S_InputState *input = 0;
LockTicketMutex(&S.input_back_tm);
{ {
ResetArena(frame_arena); input = &S.input_states[S.input_back_idx];
S_Iter iter = Zi; ++S.input_back_idx;
S_Lookup lookup = Zi; if (S.input_back_idx >= countof(S.input_states))
{
////////////////////////////// S.input_back_idx = 0;
//- Begin sim frame }
i64 frame_begin_ns = TimeNs();
i64 sim_dt_ns = NsFromSeconds(1) / SIM_TICKS_PER_SECOND;
f64 sim_dt = SecondsFromNs(sim_dt_ns);
world->tick += 1;
lookup = S_LookupFromWorld(frame_arena, world);
//////////////////////////////
//- Pop sim commands
S_InputState *input = 0;
LockTicketMutex(&S.input_back_tm);
{
input = &S.input_states[S.input_back_idx];
++S.input_back_idx;
if (S.input_back_idx >= countof(S.input_states))
{
S.input_back_idx = 0;
}
}
UnlockTicketMutex(&S.input_back_tm);
//////////////////////////////
//- Process world edit commands
u64 tile_placements_count = 0;
for (S_CmdNode *cmd_node = input->first_cmd_node; cmd_node; cmd_node = cmd_node->next)
{
S_Cmd *cmd = &cmd_node->cmd;
/* Spawn entity */
if (cmd->kind == S_CmdKind_Spawn)
{
S_Ent *src = &cmd->ent;
S_Key key = src->key;
if (!S_IsKeyNil(key))
{
S_Ent *dst = S_EntFromKey(&lookup, key);
if (S_IsEntNil(dst))
{
if (first_free_ent_num > 0)
{
dst = &world->ents[first_free_ent_num - 1];
first_free_ent_num = dst->next_free_ent_num;
}
else
{
dst = PushStructNoZero(ents_arena, S_Ent);
}
*dst = S_ro.nil_ent;
dst->key = key;
++world->ents_count;
}
*dst = *src;
dst->local_shape.points_count = MaxI32(dst->local_shape.points_count, 1);
dst->active = 1;
}
}
/* Place tiles */
if (cmd->kind == S_CmdKind_Tile)
{
tile_placements_count += 1;
S_TilePlacement placement = cmd->tile_placement;
S_UpdateTilesInPlaceFromPlacement(tiles, placement);
}
}
lookup = S_LookupFromWorld(frame_arena, world);
//////////////////////////////
//- Update ent controls
for (S_CmdNode *cmd_node = input->first_cmd_node; cmd_node; cmd_node = cmd_node->next)
{
S_Cmd cmd = cmd_node->cmd;
if (cmd.kind == S_CmdKind_Control)
{
S_Ent *target = S_EntFromKey(&lookup, cmd.target);
if (target->active)
{
target->move = ClampVec2Len(cmd.move, 1);
target->look = cmd.look;
}
}
}
//////////////////////////////
//- Apply control forces
for (S_Ent *ent = S_FirstEnt(&iter, world); ent->active; ent = S_NextEnt(&iter))
{
if (!IsVec2Zero(ent->move))
{
DEBUGBREAKABLE;
}
Xform xf = ent->xf;
if (!IsVec2Zero(ent->look))
{
xf = XformWithWorldRotation(xf, AngleFromVec2(ent->look));
}
xf.og = AddVec2(xf.og, MulVec2(ent->move, ent->move_speed));
ent->xf = xf;
}
//////////////////////////////
//- Publish sim state
/* TODO: Only copy active entities */
LockTicketMutex(&S.output_back_tm);
{
S_OutputState *output = &S.output_states[S.output_back_idx];
ResetArena(output->arena);
S_SnapshotNode *snapshot_node = PushStruct(output->arena, S_SnapshotNode);
S_Snapshot *snapshot = &snapshot_node->snapshot;
SllQueuePush(output->first_snapshot_node, output->last_snapshot_node, snapshot_node);
++output->snapshots_count;
snapshot->ents_count = world->ents_count;
snapshot->tick = world->tick;
snapshot->ents = PushStructsNoZero(output->arena, S_Ent, snapshot->ents_count);
for (i64 ent_idx = 0; ent_idx < snapshot->ents_count; ++ent_idx)
{
S_Ent *src = &world->ents[ent_idx];
S_Ent *dst = &snapshot->ents[ent_idx];
*dst = *src;
}
/* Forward tile placements */
snapshot->tile_placements_count = tile_placements_count;
snapshot->tile_placements = PushStructs(output->arena, S_TilePlacement, tile_placements_count);
{
u64 tile_placement_idx = 0;
for (S_CmdNode *cmd_node = input->first_cmd_node; cmd_node && tile_placement_idx < tile_placements_count; cmd_node = cmd_node->next)
{
S_Cmd *cmd = &cmd_node->cmd;
if (cmd->kind == S_CmdKind_Tile)
{
S_TilePlacement *dst_placement = &snapshot->tile_placements[tile_placement_idx];
*dst_placement = cmd->tile_placement;
tile_placement_idx += 1;
}
}
}
}
UnlockTicketMutex(&S.output_back_tm);
//////////////////////////////
//- End sim frame
/* Reset front input state */
{
Arena *arena = input->arena;
ResetArena(arena);
ZeroStruct(input);
input->arena = arena;
}
i64 frame_end_ns = TimeNs();
sim_time_ns += sim_dt_ns;
//////////////////////////////
//- Sleep
if (!Atomic32Fetch(&S.shutdown))
{
i64 step_dt_ns = NsFromSeconds(1) / SIM_TICKS_PER_SECOND;
P_SleepFrame(frame_begin_ns, step_dt_ns);
}
shutdown = Atomic32Fetch(&S.shutdown);
} }
UnlockTicketMutex(&S.input_back_tm);
//////////////////////////////
//- Process world edit commands
u64 tile_placements_count = 0;
for (S_CmdNode *cmd_node = input->first_cmd_node; cmd_node; cmd_node = cmd_node->next)
{
S_Cmd *cmd = &cmd_node->cmd;
/* Spawn entity */
if (cmd->kind == S_CmdKind_Spawn)
{
S_Ent *src = &cmd->ent;
S_Key key = src->key;
if (!S_IsKeyNil(key))
{
S_Ent *dst = S_EntFromKey(&lookup, key);
if (S_IsEntNil(dst))
{
if (first_free_ent_num > 0)
{
dst = &world->ents[first_free_ent_num - 1];
first_free_ent_num = dst->next_free_ent_num;
}
else
{
dst = PushStructNoZero(ents_arena, S_Ent);
}
*dst = S_ro.nil_ent;
dst->key = key;
++world->ents_count;
}
*dst = *src;
dst->local_shape.points_count = MaxI32(dst->local_shape.points_count, 1);
dst->active = 1;
}
}
/* Place tiles */
if (cmd->kind == S_CmdKind_Tile)
{
tile_placements_count += 1;
S_TilePlacement placement = cmd->tile_placement;
S_UpdateTilesInPlaceFromPlacement(tiles, placement);
}
}
lookup = S_LookupFromWorld(frame_arena, world);
//////////////////////////////
//- Update ent controls
for (S_CmdNode *cmd_node = input->first_cmd_node; cmd_node; cmd_node = cmd_node->next)
{
S_Cmd cmd = cmd_node->cmd;
if (cmd.kind == S_CmdKind_Control)
{
S_Ent *target = S_EntFromKey(&lookup, cmd.target);
if (target->active)
{
target->move = ClampVec2Len(cmd.move, 1);
target->look = cmd.look;
}
}
}
//////////////////////////////
//- Apply control forces
for (S_Ent *ent = S_FirstEnt(&iter, world); ent->active; ent = S_NextEnt(&iter))
{
if (!IsVec2Zero(ent->move))
{
DEBUGBREAKABLE;
}
Xform xf = ent->xf;
if (!IsVec2Zero(ent->look))
{
xf = XformWithWorldRotation(xf, AngleFromVec2(ent->look));
}
xf.og = AddVec2(xf.og, MulVec2(ent->move, ent->move_speed));
ent->xf = xf;
}
//////////////////////////////
//- Publish sim state
/* TODO: Only copy active entities */
LockTicketMutex(&S.output_back_tm);
{
S_OutputState *output = &S.output_states[S.output_back_idx];
ResetArena(output->arena);
S_SnapshotNode *snapshot_node = PushStruct(output->arena, S_SnapshotNode);
S_Snapshot *snapshot = &snapshot_node->snapshot;
SllQueuePush(output->first_snapshot_node, output->last_snapshot_node, snapshot_node);
++output->snapshots_count;
snapshot->ents_count = world->ents_count;
snapshot->tick = world->tick;
snapshot->ents = PushStructsNoZero(output->arena, S_Ent, snapshot->ents_count);
for (i64 ent_idx = 0; ent_idx < snapshot->ents_count; ++ent_idx)
{
S_Ent *src = &world->ents[ent_idx];
S_Ent *dst = &snapshot->ents[ent_idx];
*dst = *src;
}
/* Forward tile placements */
snapshot->tile_placements_count = tile_placements_count;
snapshot->tile_placements = PushStructs(output->arena, S_TilePlacement, tile_placements_count);
{
u64 tile_placement_idx = 0;
for (S_CmdNode *cmd_node = input->first_cmd_node; cmd_node && tile_placement_idx < tile_placements_count; cmd_node = cmd_node->next)
{
S_Cmd *cmd = &cmd_node->cmd;
if (cmd->kind == S_CmdKind_Tile)
{
S_TilePlacement *dst_placement = &snapshot->tile_placements[tile_placement_idx];
*dst_placement = cmd->tile_placement;
tile_placement_idx += 1;
}
}
}
}
UnlockTicketMutex(&S.output_back_tm);
//////////////////////////////
//- End sim frame
/* Reset front input state */
{
Arena *arena = input->arena;
ResetArena(arena);
ZeroStruct(input);
input->arena = arena;
}
i64 frame_end_ns = TimeNs();
sim_time_ns += sim_dt_ns;
//////////////////////////////
//- Sleep
if (!Atomic32Fetch(&S.shutdown))
{
i64 step_dt_ns = NsFromSeconds(1) / SIM_TICKS_PER_SECOND;
P_SleepFrame(frame_begin_ns, step_dt_ns);
}
shutdown = Atomic32Fetch(&S.shutdown);
}
} }

View File

@ -5,7 +5,7 @@
Struct(S_Key) Struct(S_Key)
{ {
U128 v; U128 v;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -13,21 +13,21 @@ Struct(S_Key)
Struct(S_ShapeDesc) Struct(S_ShapeDesc)
{ {
f32 radius; f32 radius;
f32 mass; f32 mass;
i32 count; i32 count;
Vec2 points[8]; Vec2 points[8];
}; };
Struct(S_Shape) Struct(S_Shape)
{ {
f32 mass; f32 mass;
Vec2 centroid; Vec2 centroid;
Vec2 center_of_mass; Vec2 center_of_mass;
f32 radius; f32 radius;
i32 points_count; i32 points_count;
Vec2 points[8]; Vec2 points[8];
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -37,28 +37,28 @@ Struct(S_Shape)
Struct(S_Ent) Struct(S_Ent)
{ {
////////////////////////////// //////////////////////////////
//- Persistent data //- Persistent data
b32 active; b32 active;
S_Key key; S_Key key;
////////////////////////////// //////////////////////////////
//- Build data //- Build data
Xform xf; Xform xf;
S_Shape local_shape; S_Shape local_shape;
f32 move_speed; f32 move_speed;
Vec2 move; Vec2 move;
Vec2 look; Vec2 look;
b32 has_weapon; b32 has_weapon;
////////////////////////////// //////////////////////////////
//- Internal sim data //- Internal sim data
i64 next_free_ent_num; i64 next_free_ent_num;
}; };
@ -67,21 +67,21 @@ Struct(S_Ent)
Struct(S_EntArray) Struct(S_EntArray)
{ {
u64 count; u64 count;
S_Ent *ents; S_Ent *ents;
}; };
Struct(S_EntListNode) Struct(S_EntListNode)
{ {
S_EntListNode *next; S_EntListNode *next;
S_Ent ent; S_Ent ent;
}; };
Struct(S_EntList) Struct(S_EntList)
{ {
S_EntListNode *first; S_EntListNode *first;
S_EntListNode *last; S_EntListNode *last;
u64 count; u64 count;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -89,14 +89,14 @@ Struct(S_EntList)
Struct(S_LookupEntNode) Struct(S_LookupEntNode)
{ {
S_LookupEntNode *next; S_LookupEntNode *next;
S_Ent *ent; S_Ent *ent;
}; };
Struct(S_Lookup) Struct(S_Lookup)
{ {
S_LookupEntNode **bins; S_LookupEntNode **bins;
i64 bins_count; i64 bins_count;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -104,27 +104,27 @@ Struct(S_Lookup)
Struct(S_World) Struct(S_World)
{ {
i64 tick; i64 tick;
S_Ent *ents; S_Ent *ents;
i64 ents_count; i64 ents_count;
}; };
Struct(S_Snapshot) Struct(S_Snapshot)
{ {
i64 tick; i64 tick;
S_Ent *ents; S_Ent *ents;
i64 ents_count; i64 ents_count;
S_TilePlacement *tile_placements; S_TilePlacement *tile_placements;
u64 tile_placements_count; u64 tile_placements_count;
}; };
Struct(S_SnapshotNode) Struct(S_SnapshotNode)
{ {
S_SnapshotNode *next; S_SnapshotNode *next;
S_Snapshot snapshot; S_Snapshot snapshot;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -132,8 +132,8 @@ Struct(S_SnapshotNode)
Struct(S_Iter) Struct(S_Iter)
{ {
S_World *world; S_World *world;
i64 cur_idx; i64 cur_idx;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -141,32 +141,32 @@ Struct(S_Iter)
Enum(S_CmdKind) Enum(S_CmdKind)
{ {
S_CmdKind_Nop, S_CmdKind_Nop,
S_CmdKind_Tile, S_CmdKind_Tile,
S_CmdKind_Spawn, S_CmdKind_Spawn,
S_CmdKind_Control, S_CmdKind_Control,
}; };
Struct(S_Cmd) Struct(S_Cmd)
{ {
S_CmdKind kind; S_CmdKind kind;
/* Tiles */ /* Tiles */
S_TilePlacement tile_placement; S_TilePlacement tile_placement;
/* Spawn */ /* Spawn */
S_Ent ent; S_Ent ent;
/* Control */ /* Control */
S_Key target; S_Key target;
Vec2 move; Vec2 move;
Vec2 look; Vec2 look;
}; };
Struct(S_CmdNode) Struct(S_CmdNode)
{ {
S_CmdNode *next; S_CmdNode *next;
S_Cmd cmd; S_Cmd cmd;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -177,41 +177,41 @@ Struct(S_CmdNode)
Struct(S_InputState) Struct(S_InputState)
{ {
Arena *arena; Arena *arena;
S_CmdNode *first_cmd_node; S_CmdNode *first_cmd_node;
S_CmdNode *last_cmd_node; S_CmdNode *last_cmd_node;
u64 cmds_count; u64 cmds_count;
}; };
Struct(S_OutputState) Struct(S_OutputState)
{ {
Arena *arena; Arena *arena;
S_SnapshotNode *first_snapshot_node; S_SnapshotNode *first_snapshot_node;
S_SnapshotNode *last_snapshot_node; S_SnapshotNode *last_snapshot_node;
u64 snapshots_count; u64 snapshots_count;
}; };
Struct(S_Ctx) Struct(S_Ctx)
{ {
Atomic32 shutdown; Atomic32 shutdown;
Fence worker_completion_fence; Fence worker_completion_fence;
i64 workers_count; i64 workers_count;
//- Sim input //- Sim input
TicketMutex input_back_tm; TicketMutex input_back_tm;
i32 input_back_idx; i32 input_back_idx;
S_InputState input_states[S_InputStatesCount]; S_InputState input_states[S_InputStatesCount];
//- Sim output //- Sim output
TicketMutex output_back_tm; TicketMutex output_back_tm;
i32 output_back_idx; i32 output_back_idx;
S_OutputState output_states[S_OutputStatesCount]; S_OutputState output_states[S_OutputStatesCount];
}; };
Struct(S_ReadonlyCtx) Struct(S_ReadonlyCtx)
{ {
S_Ent nil_ent; S_Ent nil_ent;
}; };
extern S_Ctx S; extern S_Ctx S;

View File

@ -3,14 +3,14 @@
Vec2I32 S_TilePosFromWorldPos(Vec2 p) Vec2I32 S_TilePosFromWorldPos(Vec2 p)
{ {
Vec2I32 result; Vec2I32 result;
result.x = ClampI32((p.x + S_WorldSize / 2) * 2, 0, (S_WorldSize * 2) - 1); result.x = ClampI32((p.x + S_WorldSize / 2) * 2, 0, (S_WorldSize * 2) - 1);
result.y = ClampI32((p.y + S_WorldSize / 2) * 2, 0, (S_WorldSize * 2) - 1); result.y = ClampI32((p.y + S_WorldSize / 2) * 2, 0, (S_WorldSize * 2) - 1);
return result; return result;
} }
i32 S_TileIdxFromTilePos(Vec2I32 p) i32 S_TileIdxFromTilePos(Vec2I32 p)
{ {
i32 result = ClampI32(p.x + (p.y * S_WorldSize * 2), 0, S_WorldSize * S_WorldSize * 4); i32 result = ClampI32(p.x + (p.y * S_WorldSize * 2), 0, S_WorldSize * S_WorldSize * 4);
return result; return result;
} }

View File

@ -5,21 +5,21 @@
Enum(S_TileKind) Enum(S_TileKind)
{ {
S_TileKind_None, S_TileKind_None,
S_TileKind_Floor, S_TileKind_Floor,
S_TileKind_Wall, S_TileKind_Wall,
}; };
Enum(S_TilePlacementKind) Enum(S_TilePlacementKind)
{ {
S_TilePlacementKind_Range S_TilePlacementKind_Range
}; };
Struct(S_TilePlacement) Struct(S_TilePlacement)
{ {
S_TilePlacementKind placement_kind; S_TilePlacementKind placement_kind;
S_TileKind tile_kind; S_TileKind tile_kind;
Rng2I32 range; Rng2I32 range;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////

File diff suppressed because it is too large Load Diff

View File

@ -1,38 +1,38 @@
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Command table //~ Command table
#define V_CmdsTableXMacro(X) \ #define V_CmdsTableXMacro(X) \
X(nop, NOP, V_CmdDescFlag_HideFromPalette, V_HOTKEY(0), ) \ X(nop, NOP, V_CmdDescFlag_HideFromPalette, V_HOTKEY(0), ) \
X(exit_program, Exit Program, V_CmdDescFlag_HideFromPalette, V_HOTKEY( Button_Escape ) ) \ X(exit_program, Exit Program, V_CmdDescFlag_HideFromPalette, V_HOTKEY( Button_Escape ) ) \
X(toggle_command_palette, Toggle Command Palette, V_CmdDescFlag_HideFromPalette, V_HOTKEY( Button_P, .ctrl = 1, .shift = 1 ), ) \ X(toggle_command_palette, Toggle Command Palette, V_CmdDescFlag_HideFromPalette, V_HOTKEY( Button_P, .ctrl = 1, .shift = 1 ), ) \
X(zoom_in, Zoom In, V_CmdDescFlag_HideFromPalette, V_HOTKEY( Button_MWheelUp ), ) \ X(zoom_in, Zoom In, V_CmdDescFlag_HideFromPalette, V_HOTKEY( Button_MWheelUp ), ) \
X(zoom_out, Zoom Out, V_CmdDescFlag_HideFromPalette, V_HOTKEY( Button_MWheelDown ), ) \ X(zoom_out, Zoom Out, V_CmdDescFlag_HideFromPalette, V_HOTKEY( Button_MWheelDown ), ) \
X(toggle_editor, Toggle Editor, V_CmdDescFlag_None, V_HOTKEY( Button_F1 ), ) \ X(toggle_editor, Toggle Editor, V_CmdDescFlag_None, V_HOTKEY( Button_F1 ), ) \
X(toggle_ui_debug, Toggle UI Debug, V_CmdDescFlag_None, V_HOTKEY( Button_F5 ), ) \ X(toggle_ui_debug, Toggle UI Debug, V_CmdDescFlag_None, V_HOTKEY( Button_F5 ), ) \
X(toggle_console, Toggle Developer Console, V_CmdDescFlag_None, V_HOTKEY( Button_GraveAccent ), ) \ X(toggle_console, Toggle Developer Console, V_CmdDescFlag_None, V_HOTKEY( Button_GraveAccent ), ) \
X(toggle_fullscreen, Toggle Fullscreen Mode, V_CmdDescFlag_None, V_HOTKEY( Button_Enter, .alt = 1 ) ) \ X(toggle_fullscreen, Toggle Fullscreen Mode, V_CmdDescFlag_None, V_HOTKEY( Button_Enter, .alt = 1 ) ) \
X(toggle_window_topmost, Toggle Window Topmost, V_CmdDescFlag_None, V_HOTKEY( Button_F4 ), ) \ X(toggle_window_topmost, Toggle Window Topmost, V_CmdDescFlag_None, V_HOTKEY( Button_F4 ), ) \
X(spawn, Spawn, V_CmdDescFlag_None, V_HOTKEY( Button_S, .ctrl = 1 ), ) \ X(spawn, Spawn, V_CmdDescFlag_None, V_HOTKEY( Button_S, .ctrl = 1 ), ) \
/* -------------------------------------------------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------------------------------------------------- */
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Theme types //~ Theme types
Struct(V_WidgetTheme) Struct(V_WidgetTheme)
{ {
GC_FontKey font; GC_FontKey font;
f32 font_size; f32 font_size;
f32 window_title_font_size; f32 window_title_font_size;
Vec4 window_background_color; Vec4 window_background_color;
Vec4 window_border_color; Vec4 window_border_color;
Vec4 divider_color; Vec4 divider_color;
f32 window_border; f32 window_border;
f32 window_padding; f32 window_padding;
f32 window_width; f32 window_width;
f32 text_padding_x; f32 text_padding_x;
f32 text_padding_y; f32 text_padding_y;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -41,10 +41,10 @@ Struct(V_WidgetTheme)
#define V_HOTKEY(_button, ...) { .button = _button, __VA_ARGS__ } #define V_HOTKEY(_button, ...) { .button = _button, __VA_ARGS__ }
Struct(V_Hotkey) Struct(V_Hotkey)
{ {
Button button; Button button;
b32 ctrl; b32 ctrl;
b32 alt; b32 alt;
b32 shift; b32 shift;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -52,57 +52,57 @@ Struct(V_Hotkey)
Enum(V_CmdKind) Enum(V_CmdKind)
{ {
#define X(name, ...) V_CmdKind_##name, #define X(name, ...) V_CmdKind_##name,
V_CmdsTableXMacro(X) V_CmdsTableXMacro(X)
#undef X #undef X
V_CmdKind_Count, V_CmdKind_Count,
}; };
Struct(V_Shortcut) Struct(V_Shortcut)
{ {
V_Shortcut *next_in_bin; V_Shortcut *next_in_bin;
V_Shortcut *prev_in_bin; V_Shortcut *prev_in_bin;
u64 hotkey_hash; u64 hotkey_hash;
V_Hotkey hotkey; V_Hotkey hotkey;
String cmd_name; String cmd_name;
}; };
Struct(V_ShortcutBin) Struct(V_ShortcutBin)
{ {
V_Shortcut *first; V_Shortcut *first;
V_Shortcut *last; V_Shortcut *last;
}; };
Enum(V_CmdDescFlag) Enum(V_CmdDescFlag)
{ {
V_CmdDescFlag_None = 0, V_CmdDescFlag_None = 0,
V_CmdDescFlag_HideFromPalette = (1 << 0), V_CmdDescFlag_HideFromPalette = (1 << 0),
}; };
Struct(V_CmdDesc) Struct(V_CmdDesc)
{ {
String name; String name;
String display_name; String display_name;
V_CmdDescFlag flags; V_CmdDescFlag flags;
V_Hotkey default_hotkeys[8]; V_Hotkey default_hotkeys[8];
}; };
Struct(V_Cmd) Struct(V_Cmd)
{ {
String name; String name;
}; };
Struct(V_CmdNode) Struct(V_CmdNode)
{ {
V_CmdNode *next; V_CmdNode *next;
V_Cmd cmd; V_Cmd cmd;
}; };
Global Readonly V_CmdDesc V_cmd_descs[V_CmdKind_Count] = { Global Readonly V_CmdDesc V_cmd_descs[V_CmdKind_Count] = {
#define X(_name, _display_name, _flags, ...) { .name = CompLit(#_name), .display_name = CompLit(#_display_name), .flags = _flags, .default_hotkeys = { __VA_ARGS__ } }, #define X(_name, _display_name, _flags, ...) { .name = CompLit(#_name), .display_name = CompLit(#_display_name), .flags = _flags, .default_hotkeys = { __VA_ARGS__ } },
V_CmdsTableXMacro(X) V_CmdsTableXMacro(X)
#undef X #undef X
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -110,38 +110,38 @@ Global Readonly V_CmdDesc V_cmd_descs[V_CmdKind_Count] = {
Struct(V_CommandsWidgetItemReport) Struct(V_CommandsWidgetItemReport)
{ {
b32 pressed; b32 pressed;
b32 hotkey_changed; b32 hotkey_changed;
UI_Report ui_report; UI_Report ui_report;
V_Hotkey new_hotkeys[8]; V_Hotkey new_hotkeys[8];
}; };
Struct(V_CommandsWidgetItemDesc) Struct(V_CommandsWidgetItemDesc)
{ {
String display_name; String display_name;
V_Hotkey hotkeys[8]; V_Hotkey hotkeys[8];
}; };
Struct(V_CommandsWidgetItem) Struct(V_CommandsWidgetItem)
{ {
V_CommandsWidgetItem *next; V_CommandsWidgetItem *next;
UI_Key key; UI_Key key;
V_CommandsWidgetItemDesc desc; V_CommandsWidgetItemDesc desc;
}; };
Struct(V_CommandsWidget) Struct(V_CommandsWidget)
{ {
/* Persistent state */ /* Persistent state */
Vec2 pos; Vec2 pos;
/* Per-build state */ /* Per-build state */
struct struct
{ {
UI_Checkpoint cp; UI_Checkpoint cp;
V_CommandsWidgetItem *first_item; V_CommandsWidgetItem *first_item;
V_CommandsWidgetItem *last_item; V_CommandsWidgetItem *last_item;
u64 num_items; u64 num_items;
} build; } build;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -151,38 +151,38 @@ Struct(V_CommandsWidget)
Struct(V_Space) Struct(V_Space)
{ {
V_Space *parent; V_Space *parent;
V_Space *next; V_Space *next;
V_Space *prev; V_Space *prev;
V_Space *first; V_Space *first;
V_Space *last; V_Space *last;
i64 panels_count; i64 panels_count;
struct V_Panel *first_panel; struct V_Panel *first_panel;
struct V_Panel *last_panel; struct V_Panel *last_panel;
Axis axis; Axis axis;
}; };
Struct(V_Panel) Struct(V_Panel)
{ {
V_Space *space; V_Space *space;
V_Panel *next_in_space; V_Panel *next_in_space;
V_Panel *prev_in_space; V_Panel *prev_in_space;
i64 active_window_idx; i64 active_window_idx;
i64 windows_count; i64 windows_count;
struct V_Window *first_window; struct V_Window *first_window;
struct V_Window *last_window; struct V_Window *last_window;
}; };
Struct(V_Window) Struct(V_Window)
{ {
V_Panel *panel; V_Panel *panel;
V_Window *next_in_panel; V_Window *next_in_panel;
V_Window *prev_in_panel; V_Window *prev_in_panel;
b32 is_tile_window; b32 is_tile_window;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -190,97 +190,97 @@ Struct(V_Window)
Enum(V_EditMode) Enum(V_EditMode)
{ {
V_EditMode_Tile, V_EditMode_Tile,
}; };
Struct(V_Frame) Struct(V_Frame)
{ {
Arena *arena; Arena *arena;
Arena *dverts_arena; Arena *dverts_arena;
Arena *dvert_idxs_arena; Arena *dvert_idxs_arena;
G_ArenaHandle gpu_arena; G_ArenaHandle gpu_arena;
G_CommandListHandle cl; G_CommandListHandle cl;
i64 tick; i64 tick;
i64 time_ns; i64 time_ns;
i64 dt_ns; i64 dt_ns;
f64 dt; f64 dt;
Button held_buttons[Button_Count]; Button held_buttons[Button_Count];
V_CommandsWidget commands_widget; V_CommandsWidget commands_widget;
String window_restore; String window_restore;
i32 zooms; i32 zooms;
Vec2I32 ui_dims; Vec2I32 ui_dims;
Vec2I32 draw_dims; Vec2I32 draw_dims;
/* Modes */ /* Modes */
b32 is_editing; b32 is_editing;
b32 ui_debug; b32 ui_debug;
b32 show_command_palette; b32 show_command_palette;
b32 show_console; b32 show_console;
/* Editor state */ /* Editor state */
V_EditMode edit_mode; V_EditMode edit_mode;
S_TileKind equipped_tile; S_TileKind equipped_tile;
/* Editor */ /* Editor */
b32 is_selecting; b32 is_selecting;
b32 is_panning; b32 is_panning;
V_SelectionMode selection_mode; V_SelectionMode selection_mode;
Vec2 world_selection_start; Vec2 world_selection_start;
Vec2 edit_camera_pos; Vec2 edit_camera_pos;
f32 edit_camera_zoom; f32 edit_camera_zoom;
/* Camera */ /* Camera */
Vec2 camera_pos; Vec2 camera_pos;
f32 camera_zoom; f32 camera_zoom;
/* World <-> ui */ /* World <-> ui */
Xform world_to_ui_xf; Xform world_to_ui_xf;
Xform ui_to_world_xf; Xform ui_to_world_xf;
/* Draw <-> ui */ /* Draw <-> ui */
Xform draw_to_ui_xf; Xform draw_to_ui_xf;
Xform ui_to_draw_xf; Xform ui_to_draw_xf;
/* World <-> draw */ /* World <-> draw */
Xform world_to_draw_xf; Xform world_to_draw_xf;
Xform draw_to_world_xf; Xform draw_to_world_xf;
/* Cursors */ /* Cursors */
Vec2 ui_cursor; Vec2 ui_cursor;
Vec2 draw_cursor; Vec2 draw_cursor;
Vec2 world_cursor; Vec2 world_cursor;
Rng2 ui_selection; Rng2 ui_selection;
Rng2 draw_selection; Rng2 draw_selection;
Rng2 world_selection; Rng2 world_selection;
/* Control */ /* Control */
Vec2 move; Vec2 move;
Vec2 look; Vec2 look;
/* Sim cmds */ /* Sim cmds */
u64 sim_cmds_count; u64 sim_cmds_count;
S_CmdNode *first_sim_cmd_node; S_CmdNode *first_sim_cmd_node;
S_CmdNode *last_sim_cmd_node; S_CmdNode *last_sim_cmd_node;
}; };
Struct(V_Ctx) Struct(V_Ctx)
{ {
Arena *world_arena; Arena *world_arena;
S_World *world; S_World *world;
S_Lookup lookup; S_Lookup lookup;
S_Key player_key; S_Key player_key;
V_Space *root_space; V_Space *root_space;
Atomic32 shutdown; Atomic32 shutdown;
Fence shutdown_complete; Fence shutdown_complete;
u64 current_frame_idx; u64 current_frame_idx;
V_Frame frames[2]; V_Frame frames[2];
}; };
extern V_Ctx V; extern V_Ctx V;

View File

@ -3,121 +3,121 @@
void V_DrawPoly(Arena *verts_arena, Arena *idxs_arena, Vec2Array points, Vec4 color_lin, V_DrawFlag flags) void V_DrawPoly(Arena *verts_arena, Arena *idxs_arena, Vec2Array points, Vec4 color_lin, V_DrawFlag flags)
{ {
if (flags & V_DrawFlag_Line) if (flags & V_DrawFlag_Line)
{
i32 verts_count = points.count;
if (verts_count >= 2)
{ {
i32 verts_count = points.count; TempArena scratch = BeginScratchNoConflict();
if (verts_count >= 2) {
f32 half_thickness = 1;
i32 lines_count = verts_count == 2 ? 1 : verts_count;
i32 line_verts_count = lines_count * 4;
i32 idx_count = lines_count * 6;
i32 idx_offset = ArenaCount(verts_arena, V_DVert);
/* Push dverts */
V_DVert *dverts = PushStructsNoZero(verts_arena, V_DVert, line_verts_count);
for (i32 line_idx = 0; line_idx < lines_count; ++line_idx)
{ {
TempArena scratch = BeginScratchNoConflict(); i32 a_idx = line_idx;
{ i32 b_idx = line_idx + 1;
f32 half_thickness = 1; if (b_idx >= lines_count)
i32 lines_count = verts_count == 2 ? 1 : verts_count; {
i32 line_verts_count = lines_count * 4; b_idx = 0;
i32 idx_count = lines_count * 6; }
i32 idx_offset = ArenaCount(verts_arena, V_DVert);
/* Push dverts */ Vec2 a = points.points[a_idx];
V_DVert *dverts = PushStructsNoZero(verts_arena, V_DVert, line_verts_count); Vec2 b = points.points[b_idx];
for (i32 line_idx = 0; line_idx < lines_count; ++line_idx)
{
i32 a_idx = line_idx;
i32 b_idx = line_idx + 1;
if (b_idx >= lines_count)
{
b_idx = 0;
}
Vec2 a = points.points[a_idx]; Vec2 a_to_b = SubVec2(b, a);
Vec2 b = points.points[b_idx]; Vec2 perp = Vec2WithLen(PerpVec2(a_to_b), half_thickness);
Vec2 a_to_b = SubVec2(b, a); Vec2 p0 = AddVec2(a, perp);
Vec2 perp = Vec2WithLen(PerpVec2(a_to_b), half_thickness); Vec2 p1 = SubVec2(a, perp);
Vec2 p2 = SubVec2(b, perp);
Vec2 p3 = AddVec2(b, perp);
Vec2 p0 = AddVec2(a, perp); i32 offset = line_idx * 4;
Vec2 p1 = SubVec2(a, perp); dverts[offset + 0] = (V_DVert) { .pos = p0, .color_lin = color_lin };
Vec2 p2 = SubVec2(b, perp); dverts[offset + 1] = (V_DVert) { .pos = p1, .color_lin = color_lin };
Vec2 p3 = AddVec2(b, perp); dverts[offset + 2] = (V_DVert) { .pos = p2, .color_lin = color_lin };
dverts[offset + 3] = (V_DVert) { .pos = p3, .color_lin = color_lin };
i32 offset = line_idx * 4;
dverts[offset + 0] = (V_DVert) { .pos = p0, .color_lin = color_lin };
dverts[offset + 1] = (V_DVert) { .pos = p1, .color_lin = color_lin };
dverts[offset + 2] = (V_DVert) { .pos = p2, .color_lin = color_lin };
dverts[offset + 3] = (V_DVert) { .pos = p3, .color_lin = color_lin };
}
/* Generate indices */
i32 *indices = PushStructsNoZero(idxs_arena, i32, idx_count);
for (i32 line_idx = 0; line_idx < lines_count; ++line_idx)
{
i32 indices_offset = line_idx * 6;
i32 vert_idx_offset = idx_offset + (line_idx * 4);
indices[indices_offset + 0] = vert_idx_offset + 0;
indices[indices_offset + 1] = vert_idx_offset + 1;
indices[indices_offset + 2] = vert_idx_offset + 2;
indices[indices_offset + 3] = vert_idx_offset + 0;
indices[indices_offset + 4] = vert_idx_offset + 2;
indices[indices_offset + 5] = vert_idx_offset + 3;
}
}
EndScratch(scratch);
} }
/* Generate indices */
i32 *indices = PushStructsNoZero(idxs_arena, i32, idx_count);
for (i32 line_idx = 0; line_idx < lines_count; ++line_idx)
{
i32 indices_offset = line_idx * 6;
i32 vert_idx_offset = idx_offset + (line_idx * 4);
indices[indices_offset + 0] = vert_idx_offset + 0;
indices[indices_offset + 1] = vert_idx_offset + 1;
indices[indices_offset + 2] = vert_idx_offset + 2;
indices[indices_offset + 3] = vert_idx_offset + 0;
indices[indices_offset + 4] = vert_idx_offset + 2;
indices[indices_offset + 5] = vert_idx_offset + 3;
}
}
EndScratch(scratch);
} }
else }
else
{
i32 verts_count = points.count;
if (verts_count >= 3)
{ {
i32 verts_count = points.count; i32 idx_offset = ArenaCount(verts_arena, V_DVert);
if (verts_count >= 3) i32 tris_count = verts_count - 2;
{ i32 idx_count = tris_count * 3;
i32 idx_offset = ArenaCount(verts_arena, V_DVert);
i32 tris_count = verts_count - 2;
i32 idx_count = tris_count * 3;
/* Push dverts */ /* Push dverts */
V_DVert *dverts = PushStructsNoZero(verts_arena, V_DVert, verts_count); V_DVert *dverts = PushStructsNoZero(verts_arena, V_DVert, verts_count);
for (i32 point_idx = 0; point_idx < (i32)points.count; ++point_idx) for (i32 point_idx = 0; point_idx < (i32)points.count; ++point_idx)
{ {
V_DVert *dvert = &dverts[point_idx]; V_DVert *dvert = &dverts[point_idx];
dvert->pos = points.points[point_idx]; dvert->pos = points.points[point_idx];
dvert->color_lin = color_lin; dvert->color_lin = color_lin;
} }
/* Generate indices in a fan pattern */ /* Generate indices in a fan pattern */
i32 *indices = PushStructsNoZero(idxs_arena, i32, idx_count); i32 *indices = PushStructsNoZero(idxs_arena, i32, idx_count);
for (i32 i = 0; i < tris_count; ++i) for (i32 i = 0; i < tris_count; ++i)
{ {
i32 tri_offset = i * 3; i32 tri_offset = i * 3;
indices[tri_offset + 0] = idx_offset; indices[tri_offset + 0] = idx_offset;
indices[tri_offset + 1] = idx_offset + i + 1; indices[tri_offset + 1] = idx_offset + i + 1;
indices[tri_offset + 2] = idx_offset + i + 2; indices[tri_offset + 2] = idx_offset + i + 2;
} }
}
} }
}
} }
void V_DrawShape(Arena *verts_arena, Arena *idxs_arena, S_Shape shape, Vec4 color_lin, i32 detail, V_DrawFlag flags) void V_DrawShape(Arena *verts_arena, Arena *idxs_arena, S_Shape shape, Vec4 color_lin, i32 detail, V_DrawFlag flags)
{ {
if (shape.radius == 0) if (shape.radius == 0)
{
Vec2Array draw_points = Zi;
draw_points.points = shape.points;
draw_points.count = shape.points_count;
V_DrawPoly(verts_arena, idxs_arena, draw_points, color_lin, flags);
}
else
{
TempArena scratch = BeginScratchNoConflict();
{ {
Vec2Array draw_points = Zi; Vec2Array draw_points = Zi;
draw_points.points = shape.points; draw_points.points = PushStructsNoZero(scratch.arena, Vec2, detail);
draw_points.count = shape.points_count; draw_points.count = detail;
V_DrawPoly(verts_arena, idxs_arena, draw_points, color_lin, flags); for (i32 i = 0; i < detail; ++i)
} {
else f32 rad = ((f32)i / (f32)detail) * Tau;
{ Vec2 dir = Vec2FromAngle(rad);
TempArena scratch = BeginScratchNoConflict(); Vec2 sp = S_SupportPointFromShape(shape, dir);
{ draw_points.points[i] = sp;
Vec2Array draw_points = Zi; }
draw_points.points = PushStructsNoZero(scratch.arena, Vec2, detail); V_DrawPoly(verts_arena, idxs_arena, draw_points, color_lin, flags);
draw_points.count = detail;
for (i32 i = 0; i < detail; ++i)
{
f32 rad = ((f32)i / (f32)detail) * Tau;
Vec2 dir = Vec2FromAngle(rad);
Vec2 sp = S_SupportPointFromShape(shape, dir);
draw_points.points[i] = sp;
}
V_DrawPoly(verts_arena, idxs_arena, draw_points, color_lin, flags);
}
EndScratch(scratch);
} }
EndScratch(scratch);
}
} }

View File

@ -3,8 +3,8 @@
Enum(V_DrawFlag) Enum(V_DrawFlag)
{ {
V_DrawFlag_None = 0, V_DrawFlag_None = 0,
V_DrawFlag_Line = (1 << 0), V_DrawFlag_Line = (1 << 0),
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////

View File

@ -5,36 +5,36 @@ G_DeclConstant(G_StructuredBufferRef, V_ShaderConst_Params, 0);
Enum(V_SelectionMode) Enum(V_SelectionMode)
{ {
V_SelectionMode_None, V_SelectionMode_None,
V_SelectionMode_Tile, V_SelectionMode_Tile,
}; };
Struct(V_DParams) Struct(V_DParams)
{ {
Vec2I32 target_size; Vec2I32 target_size;
G_Texture2DRef target_ro; G_Texture2DRef target_ro;
G_RWTexture2DRef target_rw; G_RWTexture2DRef target_rw;
Xform world_to_draw_xf; Xform world_to_draw_xf;
Xform draw_to_world_xf; Xform draw_to_world_xf;
V_SelectionMode selection_mode; V_SelectionMode selection_mode;
S_TileKind equipped_tile; S_TileKind equipped_tile;
Vec2 ui_cursor; Vec2 ui_cursor;
Vec2 draw_cursor; Vec2 draw_cursor;
Vec2 world_cursor; Vec2 world_cursor;
Rng2 ui_selection; Rng2 ui_selection;
Rng2 draw_selection; Rng2 draw_selection;
Rng2 world_selection; Rng2 world_selection;
Vec2 camera_pos; Vec2 camera_pos;
f32 camera_zoom; f32 camera_zoom;
f32 world_size; f32 world_size;
G_Texture2DRef tiles; G_Texture2DRef tiles;
G_StructuredBufferRef quads; G_StructuredBufferRef quads;
G_StructuredBufferRef shape_verts; G_StructuredBufferRef shape_verts;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -47,13 +47,13 @@ Struct(V_DParams)
Enum(V_DQuadFlag) Enum(V_DQuadFlag)
{ {
V_DQuadFlag_None = 0, V_DQuadFlag_None = 0,
V_DQuadFlag_DrawGrid = (1 << 0), V_DQuadFlag_DrawGrid = (1 << 0),
}; };
Struct(V_DQuad) Struct(V_DQuad)
{ {
V_DQuadFlag flags; V_DQuadFlag flags;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -61,6 +61,6 @@ Struct(V_DQuad)
Struct(V_DVert) Struct(V_DVert)
{ {
Vec2 pos; Vec2 pos;
Vec4 color_lin; Vec4 color_lin;
}; };

View File

@ -3,124 +3,124 @@
ComputeShader2D(V_BackdropCS, 8, 8) ComputeShader2D(V_BackdropCS, 8, 8)
{ {
V_DParams params = G_Dereference<V_DParams>(V_ShaderConst_Params)[0]; V_DParams params = G_Dereference<V_DParams>(V_ShaderConst_Params)[0];
RWTexture2D<Vec4> target = G_Dereference<Vec4>(params.target_rw); RWTexture2D<Vec4> target = G_Dereference<Vec4>(params.target_rw);
Texture2D<uint> tiles = G_Dereference<uint>(params.tiles); Texture2D<uint> tiles = G_Dereference<uint>(params.tiles);
const Vec4 background_color_a = LinearFromSrgb(Vec4(0.30, 0.30, 0.30, 1)); const Vec4 background_color_a = LinearFromSrgb(Vec4(0.30, 0.30, 0.30, 1));
const Vec4 background_color_b = LinearFromSrgb(Vec4(0.15, 0.15, 0.15, 1)); const Vec4 background_color_b = LinearFromSrgb(Vec4(0.15, 0.15, 0.15, 1));
const Vec4 grid_color = LinearFromSrgb(Vec4(0, 0, 0, 1)); const Vec4 grid_color = LinearFromSrgb(Vec4(0, 0, 0, 1));
const Vec4 x_axis_color = LinearFromSrgb(Vec4(0.75, 0, 0, 1)); const Vec4 x_axis_color = LinearFromSrgb(Vec4(0.75, 0, 0, 1));
const Vec4 y_axis_color = LinearFromSrgb(Vec4(0, 0.75, 0, 1)); const Vec4 y_axis_color = LinearFromSrgb(Vec4(0, 0.75, 0, 1));
const Vec4 bounds_color = LinearFromSrgb(Vec4(0.75, 0.75, 0, 1)); const Vec4 bounds_color = LinearFromSrgb(Vec4(0.75, 0.75, 0, 1));
Vec2 screen_pos = Vec2(SV_DispatchThreadID) + Vec2(0.5, 0.5); Vec2 screen_pos = Vec2(SV_DispatchThreadID) + Vec2(0.5, 0.5);
if (screen_pos.x < params.target_size.x && screen_pos.y < params.target_size.y) if (screen_pos.x < params.target_size.x && screen_pos.y < params.target_size.y)
{
Vec4 result = Vec4(0.025, 0.025, 0.025, 1);
Vec2 world_pos = mul(params.draw_to_world_xf, Vec3(screen_pos, 1));
Vec2I32 tile_pos = S_TilePosFromWorldPos(world_pos);
f32 half_thickness = 1;
f32 half_bounds_size = params.world_size * 0.5;
Vec2 bounds_screen_p0 = mul(params.world_to_draw_xf, Vec3(-half_bounds_size, -half_bounds_size, 1));
Vec2 bounds_screen_p1 = mul(params.world_to_draw_xf, Vec3(half_bounds_size, half_bounds_size, 1));
b32 is_in_bounds = screen_pos.x > (bounds_screen_p0.x - half_thickness) &&
screen_pos.y > (bounds_screen_p0.y - half_thickness) &&
screen_pos.x < (bounds_screen_p1.x + half_thickness) &&
screen_pos.y < (bounds_screen_p1.y + half_thickness);
if (is_in_bounds)
{ {
Vec4 result = Vec4(0.025, 0.025, 0.025, 1); /* Grid checker */
Vec2 world_pos = mul(params.draw_to_world_xf, Vec3(screen_pos, 1)); {
Vec2I32 tile_pos = S_TilePosFromWorldPos(world_pos); i32 color_idx = 0;
Vec4 colors[2] = {
f32 half_thickness = 1; background_color_a,
f32 half_bounds_size = params.world_size * 0.5; background_color_b
Vec2 bounds_screen_p0 = mul(params.world_to_draw_xf, Vec3(-half_bounds_size, -half_bounds_size, 1)); };
Vec2 bounds_screen_p1 = mul(params.world_to_draw_xf, Vec3(half_bounds_size, half_bounds_size, 1)); const f32 checker_size = 0.5;
b32 is_in_bounds = screen_pos.x > (bounds_screen_p0.x - half_thickness) && Vec2 world_pos_modded = fmod(abs(world_pos), Vec2(checker_size * 2, checker_size * 2));
screen_pos.y > (bounds_screen_p0.y - half_thickness) && if (world_pos_modded.x < checker_size)
screen_pos.x < (bounds_screen_p1.x + half_thickness) &&
screen_pos.y < (bounds_screen_p1.y + half_thickness);
if (is_in_bounds)
{ {
/* Grid checker */ color_idx = !color_idx;
{
i32 color_idx = 0;
Vec4 colors[2] = {
background_color_a,
background_color_b
};
const f32 checker_size = 0.5;
Vec2 world_pos_modded = fmod(abs(world_pos), Vec2(checker_size * 2, checker_size * 2));
if (world_pos_modded.x < checker_size)
{
color_idx = !color_idx;
}
if (world_pos_modded.y < checker_size)
{
color_idx = !color_idx;
}
if (world_pos.x < 0)
{
color_idx = !color_idx;
}
if (world_pos.y < 0)
{
color_idx = !color_idx;
}
result = colors[color_idx];
}
/* Grid outline */
{
Vec2 grid_screen_p0 = mul(params.world_to_draw_xf, Vec3(floor(world_pos), 1));
Vec2 grid_screen_p1 = mul(params.world_to_draw_xf, Vec3(ceil(world_pos), 1));
f32 grid_dist = 100000;
grid_dist = min(grid_dist, abs(screen_pos.x - grid_screen_p0.x));
grid_dist = min(grid_dist, abs(screen_pos.x - grid_screen_p1.x));
grid_dist = min(grid_dist, abs(screen_pos.y - grid_screen_p0.y));
grid_dist = min(grid_dist, abs(screen_pos.y - grid_screen_p1.y));
if (grid_dist <= half_thickness)
{
result = grid_color;
}
}
/* Tile */
{
S_TileKind tile = (S_TileKind)tiles.Load(Vec3I32(tile_pos, 0));
switch (tile)
{
default: break;
case S_TileKind_Floor:
{
result = Color_Blue;
} break;
case S_TileKind_Wall:
{
result = Color_Red;
} break;
}
}
/* Axis */
{
Vec2 zero_screen = mul(params.world_to_draw_xf, Vec3(0, 0, 1));
f32 x_dist = abs(screen_pos.x - zero_screen.x);
f32 y_dist = abs(screen_pos.y - zero_screen.y);
if (y_dist <= half_thickness)
{
result = x_axis_color;
}
else if (x_dist <= half_thickness)
{
result = y_axis_color;
}
}
/* World bounds */
{
f32 bounds_dist = 100000;
bounds_dist = min(bounds_dist, abs(screen_pos.x - bounds_screen_p0.x));
bounds_dist = min(bounds_dist, abs(screen_pos.x - bounds_screen_p1.x));
bounds_dist = min(bounds_dist, abs(screen_pos.y - bounds_screen_p0.y));
bounds_dist = min(bounds_dist, abs(screen_pos.y - bounds_screen_p1.y));
if (bounds_dist <= half_thickness)
{
result = bounds_color;
}
}
} }
if (world_pos_modded.y < checker_size)
{
color_idx = !color_idx;
}
if (world_pos.x < 0)
{
color_idx = !color_idx;
}
if (world_pos.y < 0)
{
color_idx = !color_idx;
}
result = colors[color_idx];
}
/* Grid outline */
{
Vec2 grid_screen_p0 = mul(params.world_to_draw_xf, Vec3(floor(world_pos), 1));
Vec2 grid_screen_p1 = mul(params.world_to_draw_xf, Vec3(ceil(world_pos), 1));
f32 grid_dist = 100000;
grid_dist = min(grid_dist, abs(screen_pos.x - grid_screen_p0.x));
grid_dist = min(grid_dist, abs(screen_pos.x - grid_screen_p1.x));
grid_dist = min(grid_dist, abs(screen_pos.y - grid_screen_p0.y));
grid_dist = min(grid_dist, abs(screen_pos.y - grid_screen_p1.y));
if (grid_dist <= half_thickness)
{
result = grid_color;
}
}
/* Tile */
{
S_TileKind tile = (S_TileKind)tiles.Load(Vec3I32(tile_pos, 0));
switch (tile)
{
default: break;
case S_TileKind_Floor:
{
result = Color_Blue;
} break;
target[trunc(screen_pos)] = result; case S_TileKind_Wall:
{
result = Color_Red;
} break;
}
}
/* Axis */
{
Vec2 zero_screen = mul(params.world_to_draw_xf, Vec3(0, 0, 1));
f32 x_dist = abs(screen_pos.x - zero_screen.x);
f32 y_dist = abs(screen_pos.y - zero_screen.y);
if (y_dist <= half_thickness)
{
result = x_axis_color;
}
else if (x_dist <= half_thickness)
{
result = y_axis_color;
}
}
/* World bounds */
{
f32 bounds_dist = 100000;
bounds_dist = min(bounds_dist, abs(screen_pos.x - bounds_screen_p0.x));
bounds_dist = min(bounds_dist, abs(screen_pos.x - bounds_screen_p1.x));
bounds_dist = min(bounds_dist, abs(screen_pos.y - bounds_screen_p0.y));
bounds_dist = min(bounds_dist, abs(screen_pos.y - bounds_screen_p1.y));
if (bounds_dist <= half_thickness)
{
result = bounds_color;
}
}
} }
target[trunc(screen_pos)] = result;
}
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -131,21 +131,21 @@ ComputeShader2D(V_BackdropCS, 8, 8)
VertexShader(V_DQuadVS, V_DQuadPSInput) VertexShader(V_DQuadVS, V_DQuadPSInput)
{ {
V_DParams params = G_Dereference<V_DParams>(V_ShaderConst_Params)[0]; V_DParams params = G_Dereference<V_DParams>(V_ShaderConst_Params)[0];
StructuredBuffer<V_DQuad> quads = G_Dereference<V_DQuad>(params.quads); StructuredBuffer<V_DQuad> quads = G_Dereference<V_DQuad>(params.quads);
RWTexture2D<Vec4> target = G_Dereference<Vec4>(params.target_rw); RWTexture2D<Vec4> target = G_Dereference<Vec4>(params.target_rw);
V_DQuad quad = quads[SV_InstanceID]; V_DQuad quad = quads[SV_InstanceID];
Vec2 rect_uv = RectUvFromVertexId(SV_VertexID); Vec2 rect_uv = RectUvFromVertexId(SV_VertexID);
// Vec2 tex_uv = lerp(quad.tex_uv0, quad.tex_uv1, rect_uv); // Vec2 tex_uv = lerp(quad.tex_uv0, quad.tex_uv1, rect_uv);
// Vec2 target_pos = lerp(quad.p0, quad.p1, rect_uv); // Vec2 target_pos = lerp(quad.p0, quad.p1, rect_uv);
Vec2 target_pos = 0; Vec2 target_pos = 0;
V_DQuadPSInput result; V_DQuadPSInput result;
result.sv_position = Vec4(NdcFromPos(target_pos, countof(target)).xy, 0, 1); result.sv_position = Vec4(NdcFromPos(target_pos, countof(target)).xy, 0, 1);
result.quad_idx = SV_InstanceID; result.quad_idx = SV_InstanceID;
return result; return result;
} }
////////////////////////////// //////////////////////////////
@ -153,15 +153,15 @@ VertexShader(V_DQuadVS, V_DQuadPSInput)
PixelShader(V_DQuadPS, V_DQuadPSOutput, V_DQuadPSInput input) PixelShader(V_DQuadPS, V_DQuadPSOutput, V_DQuadPSInput input)
{ {
V_DParams params = G_Dereference<V_DParams>(V_ShaderConst_Params)[0]; V_DParams params = G_Dereference<V_DParams>(V_ShaderConst_Params)[0];
StructuredBuffer<V_DQuad> quads = G_Dereference<V_DQuad>(params.quads); StructuredBuffer<V_DQuad> quads = G_Dereference<V_DQuad>(params.quads);
V_DQuad quad = quads[input.quad_idx]; V_DQuad quad = quads[input.quad_idx];
Vec4 final_color = 0; Vec4 final_color = 0;
V_DQuadPSOutput output; V_DQuadPSOutput output;
output.sv_target0 = final_color; output.sv_target0 = final_color;
return output; return output;
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -172,18 +172,18 @@ PixelShader(V_DQuadPS, V_DQuadPSOutput, V_DQuadPSInput input)
VertexShader(V_DVertVS, V_DVertPSInput) VertexShader(V_DVertVS, V_DVertPSInput)
{ {
V_DParams params = G_Dereference<V_DParams>(V_ShaderConst_Params)[0]; V_DParams params = G_Dereference<V_DParams>(V_ShaderConst_Params)[0];
StructuredBuffer<V_DVert> verts = G_Dereference<V_DVert>(params.shape_verts); StructuredBuffer<V_DVert> verts = G_Dereference<V_DVert>(params.shape_verts);
RWTexture2D<Vec4> target = G_Dereference<Vec4>(params.target_rw); RWTexture2D<Vec4> target = G_Dereference<Vec4>(params.target_rw);
V_DVert vert = verts[SV_VertexID]; V_DVert vert = verts[SV_VertexID];
Vec2 target_pos = vert.pos; Vec2 target_pos = vert.pos;
V_DVertPSInput result; V_DVertPSInput result;
result.sv_position = Vec4(NdcFromPos(target_pos, countof(target)).xy, 0, 1); result.sv_position = Vec4(NdcFromPos(target_pos, countof(target)).xy, 0, 1);
result.color_lin = vert.color_lin; result.color_lin = vert.color_lin;
return result; return result;
} }
////////////////////////////// //////////////////////////////
@ -191,9 +191,9 @@ VertexShader(V_DVertVS, V_DVertPSInput)
PixelShader(V_DVertPS, V_DVertPSOutput, V_DVertPSInput input) PixelShader(V_DVertPS, V_DVertPSOutput, V_DVertPSInput input)
{ {
V_DVertPSOutput output; V_DVertPSOutput output;
output.sv_target0 = input.color_lin; output.sv_target0 = input.color_lin;
return output; return output;
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -204,10 +204,10 @@ PixelShader(V_DVertPS, V_DVertPSOutput, V_DVertPSInput input)
VertexShader(V_OverlayVS, V_OverlayPSInput) VertexShader(V_OverlayVS, V_OverlayPSInput)
{ {
Vec2 uv = RectUvFromVertexId(SV_VertexID); Vec2 uv = RectUvFromVertexId(SV_VertexID);
V_OverlayPSInput result; V_OverlayPSInput result;
result.sv_position = Vec4(NdcFromUv(uv).xy, 0, 1); result.sv_position = Vec4(NdcFromUv(uv).xy, 0, 1);
return result; return result;
} }
////////////////////////////// //////////////////////////////
@ -215,59 +215,59 @@ VertexShader(V_OverlayVS, V_OverlayPSInput)
PixelShader(V_OverlayPS, V_OverlayPSOutput, V_OverlayPSInput input) PixelShader(V_OverlayPS, V_OverlayPSOutput, V_OverlayPSInput input)
{ {
V_DParams params = G_Dereference<V_DParams>(V_ShaderConst_Params)[0]; V_DParams params = G_Dereference<V_DParams>(V_ShaderConst_Params)[0];
Texture2D<uint> tiles = G_Dereference<uint>(params.tiles); Texture2D<uint> tiles = G_Dereference<uint>(params.tiles);
Vec2 screen_pos = input.sv_position.xy; Vec2 screen_pos = input.sv_position.xy;
Vec4 result = 0; Vec4 result = 0;
Vec2 world_pos = mul(params.draw_to_world_xf, Vec3(screen_pos, 1)); Vec2 world_pos = mul(params.draw_to_world_xf, Vec3(screen_pos, 1));
Vec2I32 tile_pos = S_TilePosFromWorldPos(world_pos); Vec2I32 tile_pos = S_TilePosFromWorldPos(world_pos);
S_TileKind equipped_tile = params.equipped_tile; S_TileKind equipped_tile = params.equipped_tile;
f32 half_thickness = 1; f32 half_thickness = 1;
Vec4 border_color = LinearFromSrgb(Vec4(1, 1, 1, 1)); Vec4 border_color = LinearFromSrgb(Vec4(1, 1, 1, 1));
// Vec4 inner_color = LinearFromSrgb(Vec4(0.4, 0.4, 0.4, 0.25)); // Vec4 inner_color = LinearFromSrgb(Vec4(0.4, 0.4, 0.4, 0.25));
Vec4 inner_color = LinearFromSrgb(Vec4(0.4, 0.8, 0.4, 0.6)); Vec4 inner_color = LinearFromSrgb(Vec4(0.4, 0.8, 0.4, 0.6));
Rng2 screen_selection = params.draw_selection; Rng2 screen_selection = params.draw_selection;
Rng2 world_selection = params.world_selection; Rng2 world_selection = params.world_selection;
Rng2I32 tile_selection; Rng2I32 tile_selection;
tile_selection.p0 = S_TilePosFromWorldPos(world_selection.p0); tile_selection.p0 = S_TilePosFromWorldPos(world_selection.p0);
tile_selection.p1 = S_TilePosFromWorldPos(world_selection.p1); tile_selection.p1 = S_TilePosFromWorldPos(world_selection.p1);
if (params.selection_mode == V_SelectionMode_Tile) if (params.selection_mode == V_SelectionMode_Tile)
{
f32 dist = 100000000;
dist = min(dist, screen_pos.x - screen_selection.p0.x);
dist = min(dist, screen_pos.y - screen_selection.p0.y);
dist = min(dist, screen_selection.p1.x - screen_pos.x);
dist = min(dist, screen_selection.p1.y - screen_pos.y);
dist = -dist;
// if (dist >= -half_thickness && dist <= half_thickness)
// {
// result = border_color;
// }
// else
{ {
f32 dist = 100000000; if (world_pos.x > -(S_WorldSize / 2) &&
dist = min(dist, screen_pos.x - screen_selection.p0.x); world_pos.y > -(S_WorldSize / 2) &&
dist = min(dist, screen_pos.y - screen_selection.p0.y); world_pos.x < (S_WorldSize / 2) &&
dist = min(dist, screen_selection.p1.x - screen_pos.x); world_pos.y < (S_WorldSize / 2) &&
dist = min(dist, screen_selection.p1.y - screen_pos.y); tile_pos.x >= tile_selection.p0.x &&
dist = -dist; tile_pos.x <= tile_selection.p1.x &&
tile_pos.y >= tile_selection.p0.y &&
// if (dist >= -half_thickness && dist <= half_thickness) tile_pos.y <= tile_selection.p1.y)
// { {
// result = border_color; result = inner_color;
// } }
// else
{
if (world_pos.x > -(S_WorldSize / 2) &&
world_pos.y > -(S_WorldSize / 2) &&
world_pos.x < (S_WorldSize / 2) &&
world_pos.y < (S_WorldSize / 2) &&
tile_pos.x >= tile_selection.p0.x &&
tile_pos.x <= tile_selection.p1.x &&
tile_pos.y >= tile_selection.p0.y &&
tile_pos.y <= tile_selection.p1.y)
{
result = inner_color;
}
}
} }
}
V_OverlayPSOutput output; V_OverlayPSOutput output;
output.sv_target0 = result; output.sv_target0 = result;
return output; return output;
} }

View File

@ -3,13 +3,13 @@
Struct(V_DQuadPSInput) Struct(V_DQuadPSInput)
{ {
Semantic(Vec4, sv_position); Semantic(Vec4, sv_position);
Semantic(nointerpolation u32, quad_idx); Semantic(nointerpolation u32, quad_idx);
}; };
Struct(V_DQuadPSOutput) Struct(V_DQuadPSOutput)
{ {
Semantic(Vec4, sv_target0); Semantic(Vec4, sv_target0);
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -18,13 +18,13 @@ Struct(V_DQuadPSOutput)
Struct(V_DVertPSInput) Struct(V_DVertPSInput)
{ {
Semantic(Vec4, sv_position); Semantic(Vec4, sv_position);
Semantic(Vec4, color_lin); Semantic(Vec4, color_lin);
}; };
Struct(V_DVertPSOutput) Struct(V_DVertPSOutput)
{ {
Semantic(Vec4, sv_target0); Semantic(Vec4, sv_target0);
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -33,12 +33,12 @@ Struct(V_DVertPSOutput)
Struct(V_OverlayPSInput) Struct(V_OverlayPSInput)
{ {
Semantic(Vec4, sv_position); Semantic(Vec4, sv_position);
}; };
Struct(V_OverlayPSOutput) Struct(V_OverlayPSOutput)
{ {
Semantic(Vec4, sv_target0); Semantic(Vec4, sv_target0);
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////

File diff suppressed because it is too large Load Diff

View File

@ -4,98 +4,98 @@
//- Bind kinds //- Bind kinds
Enum(PP_BindKind) Enum(PP_BindKind)
{ {
PP_BindKind_None, PP_BindKind_None,
PP_BindKind_MoveUp, PP_BindKind_MoveUp,
PP_BindKind_MoveDown, PP_BindKind_MoveDown,
PP_BindKind_MoveLeft, PP_BindKind_MoveLeft,
PP_BindKind_MoveRight, PP_BindKind_MoveRight,
PP_BindKind_Walk, PP_BindKind_Walk,
PP_BindKind_Fire, PP_BindKind_Fire,
PP_BindKind_AltFire, PP_BindKind_AltFire,
PP_BindKind_TestTile, PP_BindKind_TestTile,
PP_BindKind_DebugClear, PP_BindKind_DebugClear,
PP_BindKind_DebugSpawn1, PP_BindKind_DebugSpawn1,
PP_BindKind_DebugSpawn2, PP_BindKind_DebugSpawn2,
PP_BindKind_DebugSpawn3, PP_BindKind_DebugSpawn3,
PP_BindKind_DebugSpawn4, PP_BindKind_DebugSpawn4,
PP_BindKind_DebugWalls, PP_BindKind_DebugWalls,
PP_BindKind_DebugFollow, PP_BindKind_DebugFollow,
PP_BindKind_DebugDraw, PP_BindKind_DebugDraw,
PP_BindKind_DebugConsole, PP_BindKind_DebugConsole,
PP_BindKind_DebugCamera, PP_BindKind_DebugCamera,
PP_BindKind_DebugLister, PP_BindKind_DebugLister,
PP_BindKind_DebugPause, PP_BindKind_DebugPause,
PP_BindKind_DebugStep, PP_BindKind_DebugStep,
PP_BindKind_DebugDrag, PP_BindKind_DebugDrag,
PP_BindKind_DebugDelete, PP_BindKind_DebugDelete,
PP_BindKind_DebugTeleport, PP_BindKind_DebugTeleport,
PP_BindKind_DebugExplode, PP_BindKind_DebugExplode,
PP_BindKind_DebugToggleTopmost, PP_BindKind_DebugToggleTopmost,
PP_BindKind_DebugUi, PP_BindKind_DebugUi,
PP_BindKind_FullscreenMod, PP_BindKind_FullscreenMod,
PP_BindKind_Fullscreen, PP_BindKind_Fullscreen,
PP_BindKind_ZoomIn, PP_BindKind_ZoomIn,
PP_BindKind_ZoomOut, PP_BindKind_ZoomOut,
PP_BindKind_Pan, PP_BindKind_Pan,
#if IsRtcEnabled #if IsRtcEnabled
/* Debug */ /* Debug */
PP_BindKind_ResetDebugSteps, PP_BindKind_ResetDebugSteps,
PP_BindKind_IncrementDebugSteps, PP_BindKind_IncrementDebugSteps,
PP_BindKind_DecrementDebugSteps, PP_BindKind_DecrementDebugSteps,
#endif #endif
PP_BindKind_Count PP_BindKind_Count
}; };
//- Test bindings //- Test bindings
/* TODO: Remove this */ /* TODO: Remove this */
Global Readonly PP_BindKind g_binds[Btn_Count] = { Global Readonly PP_BindKind g_binds[Btn_Count] = {
[Btn_W] = PP_BindKind_MoveUp, [Btn_W] = PP_BindKind_MoveUp,
[Btn_S] = PP_BindKind_MoveDown, [Btn_S] = PP_BindKind_MoveDown,
[Btn_A] = PP_BindKind_MoveLeft, [Btn_A] = PP_BindKind_MoveLeft,
[Btn_D] = PP_BindKind_MoveRight, [Btn_D] = PP_BindKind_MoveRight,
[Btn_M1] = PP_BindKind_Fire, [Btn_M1] = PP_BindKind_Fire,
[Btn_M2] = PP_BindKind_AltFire, [Btn_M2] = PP_BindKind_AltFire,
#if 0 #if 0
[Btn_Alt] = PP_BindKind_Walk, [Btn_Alt] = PP_BindKind_Walk,
#endif #endif
/* Testing */ /* Testing */
[Btn_Z] = PP_BindKind_TestTile, [Btn_Z] = PP_BindKind_TestTile,
[Btn_M5] = PP_BindKind_DebugDrag, [Btn_M5] = PP_BindKind_DebugDrag,
[Btn_M4] = PP_BindKind_DebugDelete, [Btn_M4] = PP_BindKind_DebugDelete,
[Btn_F] = PP_BindKind_DebugExplode, [Btn_F] = PP_BindKind_DebugExplode,
[Btn_T] = PP_BindKind_DebugTeleport, [Btn_T] = PP_BindKind_DebugTeleport,
[Btn_C] = PP_BindKind_DebugClear, [Btn_C] = PP_BindKind_DebugClear,
[Btn_1] = PP_BindKind_DebugSpawn1, [Btn_1] = PP_BindKind_DebugSpawn1,
[Btn_2] = PP_BindKind_DebugSpawn2, [Btn_2] = PP_BindKind_DebugSpawn2,
[Btn_3] = PP_BindKind_DebugSpawn3, [Btn_3] = PP_BindKind_DebugSpawn3,
[Btn_4] = PP_BindKind_DebugSpawn4, [Btn_4] = PP_BindKind_DebugSpawn4,
[Btn_G] = PP_BindKind_DebugWalls, [Btn_G] = PP_BindKind_DebugWalls,
[Btn_N] = PP_BindKind_DebugStep, [Btn_N] = PP_BindKind_DebugStep,
[Btn_Q] = PP_BindKind_DebugFollow, [Btn_Q] = PP_BindKind_DebugFollow,
[Btn_F1] = PP_BindKind_DebugPause, [Btn_F1] = PP_BindKind_DebugPause,
[Btn_F2] = PP_BindKind_DebugCamera, [Btn_F2] = PP_BindKind_DebugCamera,
[Btn_F3] = PP_BindKind_DebugDraw, [Btn_F3] = PP_BindKind_DebugDraw,
[Btn_Tab] = PP_BindKind_DebugLister, [Btn_Tab] = PP_BindKind_DebugLister,
[Btn_F4] = PP_BindKind_DebugToggleTopmost, [Btn_F4] = PP_BindKind_DebugToggleTopmost,
[Btn_F5] = PP_BindKind_DebugUi, [Btn_F5] = PP_BindKind_DebugUi,
[Btn_GraveAccent] = PP_BindKind_DebugConsole, [Btn_GraveAccent] = PP_BindKind_DebugConsole,
[Btn_Alt] = PP_BindKind_FullscreenMod, [Btn_Alt] = PP_BindKind_FullscreenMod,
[Btn_Enter] = PP_BindKind_Fullscreen, [Btn_Enter] = PP_BindKind_Fullscreen,
[Btn_MWheelUp] = PP_BindKind_ZoomIn, [Btn_MWheelUp] = PP_BindKind_ZoomIn,
[Btn_MWheelDown] = PP_BindKind_ZoomOut, [Btn_MWheelDown] = PP_BindKind_ZoomOut,
[Btn_M3] = PP_BindKind_Pan, [Btn_M3] = PP_BindKind_Pan,
#if IsRtcEnabled #if IsRtcEnabled
[Btn_ForwardSlash] = PP_BindKind_ResetDebugSteps, [Btn_ForwardSlash] = PP_BindKind_ResetDebugSteps,
[Btn_Comma] = PP_BindKind_DecrementDebugSteps, [Btn_Comma] = PP_BindKind_DecrementDebugSteps,
[Btn_Period] = PP_BindKind_IncrementDebugSteps [Btn_Period] = PP_BindKind_IncrementDebugSteps
#endif #endif
}; };
@ -104,9 +104,9 @@ Global Readonly PP_BindKind g_binds[Btn_Count] = {
Struct(PP_SecondsStat) Struct(PP_SecondsStat)
{ {
u64 last_second_start; u64 last_second_start;
u64 last_second_end; u64 last_second_end;
u64 last_second; u64 last_second;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -114,12 +114,12 @@ Struct(PP_SecondsStat)
Struct(PP_ConsoleLog) Struct(PP_ConsoleLog)
{ {
String msg; String msg;
i32 level; i32 level;
i32 color_index; i32 color_index;
DateTime datetime; DateTime datetime;
PP_ConsoleLog *prev; PP_ConsoleLog *prev;
PP_ConsoleLog *next; PP_ConsoleLog *next;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -127,17 +127,17 @@ Struct(PP_ConsoleLog)
Struct(PP_DecodeQueueNode) Struct(PP_DecodeQueueNode)
{ {
PP_Client *client; PP_Client *client;
u64 tick; u64 tick;
u64 base_tick; u64 base_tick;
String tmp_encoded; String tmp_encoded;
PP_DecodeQueueNode *next; PP_DecodeQueueNode *next;
}; };
Struct(PP_DecodeQueue) Struct(PP_DecodeQueue)
{ {
PP_DecodeQueueNode *first; PP_DecodeQueueNode *first;
PP_DecodeQueueNode *last; PP_DecodeQueueNode *last;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -145,137 +145,137 @@ Struct(PP_DecodeQueue)
Struct(PP_BindState) Struct(PP_BindState)
{ {
b32 is_held; /* Is this bind held down this frame */ b32 is_held; /* Is this bind held down this frame */
u32 num_presses; /* How many times was this bind's pressed since last frame */ u32 num_presses; /* How many times was this bind's pressed since last frame */
u32 num_repeats; /* How many times was this bind's key repeated since last frame */ u32 num_repeats; /* How many times was this bind's key repeated since last frame */
u32 num_presses_and_repeats; /* Same as `num_presses` but includes key repeats as well */ u32 num_presses_and_repeats; /* Same as `num_presses` but includes key repeats as well */
u32 num_releases; /* How many times was this bind released since last frame */ u32 num_releases; /* How many times was this bind released since last frame */
}; };
Struct(PP_SharedUserState) Struct(PP_SharedUserState)
{ {
Atomic32 shutdown; Atomic32 shutdown;
Fence shutdown_jobs_fence; Fence shutdown_jobs_fence;
u64 shutdown_jobs_count; u64 shutdown_jobs_count;
Arena *arena; Arena *arena;
String connect_address_str; String connect_address_str;
PP_ClientStore *user_client_store; PP_ClientStore *user_client_store;
PP_Client *user_unblended_client; /* Contains snapshots received from local sim */ PP_Client *user_unblended_client; /* Contains snapshots received from local sim */
PP_Client *user_blended_client; /* Contains single snapshot from result of blending local sim snapshots */ PP_Client *user_blended_client; /* Contains single snapshot from result of blending local sim snapshots */
PP_Snapshot *ss_blended; /* Points to blended snapshot contained in blended client */ PP_Snapshot *ss_blended; /* Points to blended snapshot contained in blended client */
u64 user_tick; u64 user_tick;
u64 window_os_gen; u64 window_os_gen;
//- Usage stats //- Usage stats
i64 last_second_reset_ns; i64 last_second_reset_ns;
PP_SecondsStat net_bytes_read; PP_SecondsStat net_bytes_read;
PP_SecondsStat net_bytes_sent; PP_SecondsStat net_bytes_sent;
//- Renderer gbuffers //- Renderer gbuffers
GPU_Resource *albedo; GPU_Resource *albedo;
GPU_Resource *emittance; GPU_Resource *emittance;
GPU_Resource *emittance_flood_read; GPU_Resource *emittance_flood_read;
GPU_Resource *emittance_flood_target; GPU_Resource *emittance_flood_target;
GPU_Resource *shade_read; GPU_Resource *shade_read;
GPU_Resource *shade_target; GPU_Resource *shade_target;
//- Renderer transient buffers //- Renderer transient buffers
GPU_TransientBuffer material_instances_tbuff; GPU_TransientBuffer material_instances_tbuff;
GPU_TransientBuffer grids_tbuff; GPU_TransientBuffer grids_tbuff;
Arena *material_instances_arena; Arena *material_instances_arena;
Arena *grids_arena; Arena *grids_arena;
//- Renderer state //- Renderer state
RandState frame_rand; RandState frame_rand;
u64 frame_index; u64 frame_index;
i64 gpu_submit_fence_target; i64 gpu_submit_fence_target;
//- Bind state //- Bind state
PP_BindState bind_states[PP_BindKind_Count]; PP_BindState bind_states[PP_BindKind_Count];
//- Window -> user //- Window -> user
Mutex sys_window_events_mutex; Mutex sys_window_events_mutex;
Arena *sys_window_events_arena; Arena *sys_window_events_arena;
//- User -> sim //- User -> sim
Mutex user_sim_cmd_mutex; Mutex user_sim_cmd_mutex;
PP_ControlData user_sim_cmd_control; PP_ControlData user_sim_cmd_control;
PP_EntKey user_hovered_ent; PP_EntKey user_hovered_ent;
u64 last_user_sim_cmd_gen; u64 last_user_sim_cmd_gen;
u64 user_sim_cmd_gen; u64 user_sim_cmd_gen;
Atomic32 user_paused; Atomic32 user_paused;
Atomic32 user_paused_steps; Atomic32 user_paused_steps;
//- Sim -> user //- Sim -> user
Mutex local_to_user_client_mutex; Mutex local_to_user_client_mutex;
PP_ClientStore *local_to_user_client_store; PP_ClientStore *local_to_user_client_store;
PP_Client *local_to_user_client; PP_Client *local_to_user_client;
i64 local_to_user_client_publish_dt_ns; i64 local_to_user_client_publish_dt_ns;
i64 local_to_user_client_publish_time_ns; i64 local_to_user_client_publish_time_ns;
//- Local sim -> user rolling window of publish time deltas //- Local sim -> user rolling window of publish time deltas
i64 last_local_to_user_snapshot_published_at_ns; i64 last_local_to_user_snapshot_published_at_ns;
i64 average_local_to_user_snapshot_publish_dt_ns; i64 average_local_to_user_snapshot_publish_dt_ns;
i64 local_sim_predicted_time_ns; /* Calculated from <last local sim to user pubilsh time> + <time since last local sim to user publish> */ i64 local_sim_predicted_time_ns; /* Calculated from <last local sim to user pubilsh time> + <time since last local sim to user publish> */
i64 render_time_target_ns; /* Claculated from <local_sim_rpedicted_time_ns> - <render interp delay> */ i64 render_time_target_ns; /* Claculated from <local_sim_rpedicted_time_ns> - <render interp delay> */
i64 render_time_ns; /* Incremented at a constant rate based on average local to user publish delta, but snaps to render_time_target_ns if it gets too distant */ i64 render_time_ns; /* Incremented at a constant rate based on average local to user publish delta, but snaps to render_time_target_ns if it gets too distant */
u64 local_sim_last_known_tick; u64 local_sim_last_known_tick;
i64 local_sim_last_known_time_ns; i64 local_sim_last_known_time_ns;
i64 real_dt_ns; i64 real_dt_ns;
i64 real_time_ns; i64 real_time_ns;
//- Window //- Window
String window_restore; String window_restore;
////////////////////////////// //////////////////////////////
//- Persist start //- Persist start
StructRegion(AUTO_PERSIST_START); StructRegion(AUTO_PERSIST_START);
//- Debug ui //- Debug ui
b32 ui_debug; b32 ui_debug;
PP_EntKey debug_following; PP_EntKey debug_following;
Vec2 debug_camera_pan_start; Vec2 debug_camera_pan_start;
b32 debug_camera_panning; b32 debug_camera_panning;
b32 debug_camera; b32 debug_camera;
b32 lister_active; b32 lister_active;
Vec2 lister_pos; Vec2 lister_pos;
b32 debug_draw; b32 debug_draw;
b32 debug_console; b32 debug_console;
//- Per frame //- Per frame
Vec2I32 screen_size; Vec2I32 screen_size;
Vec2 screen_cursor; Vec2 screen_cursor;
Xform ui_to_screen_xf; Xform ui_to_screen_xf;
Vec2I32 ui_size; Vec2I32 ui_size;
Vec2 ui_cursor; Vec2 ui_cursor;
Xform render_to_ui_xf; Xform render_to_ui_xf;
Vec2I32 render_size; Vec2I32 render_size;
Xform world_to_render_xf; Xform world_to_render_xf;
Xform world_to_ui_xf; Xform world_to_ui_xf;
Vec2 world_cursor; Vec2 world_cursor;
Vec2 focus_send; Vec2 focus_send;
StructRegion(AUTO_PERSIST_END); StructRegion(AUTO_PERSIST_END);
//- Persist end //- Persist end
////////////////////////////// //////////////////////////////
} extern PP_shared_user_state; } extern PP_shared_user_state;
@ -284,7 +284,7 @@ Struct(PP_SharedUserState)
Struct(PP_SwappedUserState) Struct(PP_SwappedUserState)
{ {
PP_SharedUserState s; PP_SharedUserState s;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////

View File

@ -3,52 +3,52 @@
Struct(PP_MaterialSig) Struct(PP_MaterialSig)
{ {
/* ----------------------------------------------------- */ /* ----------------------------------------------------- */
Mat4x4 projection; /* 16 consts */ Mat4x4 projection; /* 16 consts */
/* ----------------------------------------------------- */ /* ----------------------------------------------------- */
SamplerStateRid sampler; /* 01 consts */ SamplerStateRid sampler; /* 01 consts */
StructuredBufferRid instances; /* 01 consts */ StructuredBufferRid instances; /* 01 consts */
StructuredBufferRid grids; /* 01 consts */ StructuredBufferRid grids; /* 01 consts */
u32 _pad0; /* 01 consts (padding) */ u32 _pad0; /* 01 consts (padding) */
/* ----------------------------------------------------- */ /* ----------------------------------------------------- */
}; };
AssertRootConst(PP_MaterialSig, 20); AssertRootConst(PP_MaterialSig, 20);
Struct(PP_MaterialInstance) Struct(PP_MaterialInstance)
{ {
Texture2DRid tex; Texture2DRid tex;
u32 grid_id; u32 grid_id;
Xform xf; Xform xf;
Vec2 tex_uv0; Vec2 tex_uv0;
Vec2 tex_uv1; Vec2 tex_uv1;
u32 tint_srgb; u32 tint_srgb;
u32 is_light; u32 is_light;
Vec3 light_emittance_srgb; Vec3 light_emittance_srgb;
}; };
#define PP_DefaultMaterialInstance (PP_MaterialInstance) { \ #define PP_DefaultMaterialInstance (PP_MaterialInstance) { \
.tex = { U32Max }, \ .tex = { U32Max }, \
.grid_id = U32Max, \ .grid_id = U32Max, \
.xf = XformIdentity, \ .xf = XformIdentity, \
.tex_uv1 = VEC2(1, 1), \ .tex_uv1 = VEC2(1, 1), \
.tint_srgb = Color_White, \ .tint_srgb = Color_White, \
} }
Struct(PP_MaterialGrid) Struct(PP_MaterialGrid)
{ {
f32 line_thickness; f32 line_thickness;
f32 line_spacing; f32 line_spacing;
Vec2 offset; Vec2 offset;
u32 bg0_srgb; u32 bg0_srgb;
u32 bg1_srgb; u32 bg1_srgb;
u32 line_srgb; u32 line_srgb;
u32 x_srgb; u32 x_srgb;
u32 y_srgb; u32 y_srgb;
}; };
#define PP_DefaultMaterialGrid (PP_MaterialGrid) { \ #define PP_DefaultMaterialGrid (PP_MaterialGrid) { \
.line_thickness = 1, \ .line_thickness = 1, \
.line_spacing = 1, \ .line_spacing = 1, \
.bg0_srgb = Color_Black, \ .bg0_srgb = Color_Black, \
.bg0_srgb = Color_White \ .bg0_srgb = Color_White \
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -56,17 +56,17 @@ Struct(PP_MaterialGrid)
Struct(PP_FloodSig) Struct(PP_FloodSig)
{ {
/* ----------------------------------------------------- */ /* ----------------------------------------------------- */
i32 step_len; /* 01 consts */ i32 step_len; /* 01 consts */
Texture2DRid emittance; /* 01 consts */ Texture2DRid emittance; /* 01 consts */
RWTexture2DRid read; /* 01 consts */ RWTexture2DRid read; /* 01 consts */
RWTexture2DRid target; /* 01 consts */ RWTexture2DRid target; /* 01 consts */
/* ----------------------------------------------------- */ /* ----------------------------------------------------- */
u32 tex_width; /* 01 consts */ u32 tex_width; /* 01 consts */
u32 tex_height; /* 01 consts */ u32 tex_height; /* 01 consts */
u32 _pad0; /* 01 consts (padding) */ u32 _pad0; /* 01 consts (padding) */
u32 _pad1; /* 01 consts (padding) */ u32 _pad1; /* 01 consts (padding) */
/* ----------------------------------------------------- */ /* ----------------------------------------------------- */
}; };
AssertRootConst(PP_FloodSig, 8); AssertRootConst(PP_FloodSig, 8);
@ -79,27 +79,27 @@ AssertRootConst(PP_FloodSig, 8);
Struct(PP_ShadeSig) Struct(PP_ShadeSig)
{ {
/* ----------------------------------------------------- */ /* ----------------------------------------------------- */
Vec4U32 frame_seed; /* 04 consts */ Vec4U32 frame_seed; /* 04 consts */
/* ----------------------------------------------------- */ /* ----------------------------------------------------- */
u32 flags; /* 01 consts */ u32 flags; /* 01 consts */
u32 tex_width; /* 01 consts */ u32 tex_width; /* 01 consts */
u32 tex_height; /* 01 consts */ u32 tex_height; /* 01 consts */
f32 exposure; /* 01 consts */ f32 exposure; /* 01 consts */
/* ----------------------------------------------------- */ /* ----------------------------------------------------- */
Vec2 camera_offset; /* 02 consts */ Vec2 camera_offset; /* 02 consts */
u32 frame_index; /* 01 consts */ u32 frame_index; /* 01 consts */
Texture2DRid albedo; /* 01 consts */ Texture2DRid albedo; /* 01 consts */
/* ----------------------------------------------------- */ /* ----------------------------------------------------- */
Texture2DRid emittance; /* 01 consts */ Texture2DRid emittance; /* 01 consts */
Texture2DRid emittance_flood; /* 01 consts */ Texture2DRid emittance_flood; /* 01 consts */
Texture2DRid read; /* 01 consts */ Texture2DRid read; /* 01 consts */
RWTexture2DRid target; /* 01 consts */ RWTexture2DRid target; /* 01 consts */
/* ----------------------------------------------------- */ /* ----------------------------------------------------- */
Texture3DRid noise; /* 01 consts */ Texture3DRid noise; /* 01 consts */
u32 noise_tex_width; /* 01 consts */ u32 noise_tex_width; /* 01 consts */
u32 noise_tex_height; /* 01 consts */ u32 noise_tex_height; /* 01 consts */
u32 noise_tex_depth; /* 01 consts */ u32 noise_tex_depth; /* 01 consts */
/* ----------------------------------------------------- */ /* ----------------------------------------------------- */
}; };
AssertRootConst(PP_ShadeSig, 20); AssertRootConst(PP_ShadeSig, 20);

Some files were not shown because too many files have changed in this diff Show More