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
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%
@ -19,48 +19,48 @@ echo build_cmd: %program_build_cmd%
::- Try to activate Visual Studio if devenv not detected
:: Taken from wcap: https://github.com/mmozeiko/wcap/blob/aa25ccb806d7a6e1c0bfdcca863aabcd8e9badfa/build.cmd#L21-L29
if "%PROCESSOR_ARCHITECTURE%" equ "AMD64" (
set HOST_ARCH=x64
set HOST_ARCH=x64
) else if "%PROCESSOR_ARCHITECTURE%" equ "ARM64" (
set HOST_ARCH=arm64
set HOST_ARCH=arm64
)
where /Q cl.exe || (
echo **************************************************************************
echo WARNING: cl.exe not found, attempting to locate Visual Studio installation
echo **************************************************************************
echo WARNING: cl.exe not found, attempting to locate Visual Studio installation
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
if "!VS!" equ "" (
echo ERROR: Visual Studio installation not found
exit /b 1
)
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
echo Visual studio development environment activated
echo **************************************************************************
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
if "!VS!" equ "" (
echo ERROR: Visual Studio installation not found
exit /b 1
)
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
echo Visual studio development environment activated
echo **************************************************************************
)
::- Meta build
:meta_build
if not exist meta.exe (
echo ====== Meta build =====
%meta_build_cmd%
set "rc=!errorlevel!"
if !rc! NEQ 0 (
if exist meta.exe del meta.exe
exit /b !rc!
)
echo ====== Meta build =====
%meta_build_cmd%
set "rc=!errorlevel!"
if !rc! NEQ 0 (
if exist meta.exe del meta.exe
exit /b !rc!
)
)
::- Program build
if not "%--no_program_build%"=="1" (
echo ======== Build ========
%program_build_cmd%
set "rc=!errorlevel!"
if !rc! NEQ 0 (
if !rc! EQU %meta_rebuild_code% (
del meta.exe
goto meta_build
)
exit /b !rc!
echo ======== Build ========
%program_build_cmd%
set "rc=!errorlevel!"
if !rc! NEQ 0 (
if !rc! EQU %meta_rebuild_code% (
del meta.exe
goto meta_build
)
exit /b !rc!
)
)

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

@ -3,70 +3,70 @@
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();
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);
String name = Zi;
for (StringListNode *n = raw.first; n; n = n->next)
{
String s = n->s;
if (StringBeginsWith(s, Lit("--")))
{
String name = Zi;
for (StringListNode *n = raw.first; n; n = n->next)
{
String s = n->s;
if (StringBeginsWith(s, Lit("--")))
{
if (name.len > 0)
{
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;
}
if (name.len > 0)
{
CommandlineArg *arg = &tmp_args[tmp_args_count++];
arg->name = name;
arg->exists = 1;
}
name = TrimLeft(s, Lit("--"));
}
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)
else
{
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;
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;
}
}
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 result = Zi;
if (idx < Base.cmdline.positional_args_count)
{
result = Base.cmdline.positional_args[idx];
}
return result;
String result = Zi;
if (idx < Base.cmdline.positional_args_count)
{
result = Base.cmdline.positional_args[idx];
}
return result;
}
CommandlineArg CommandlineArgFromName(String name)
{
CommandlineArg result = Zi;
u64 hash = HashFnv64(Fnv64Basis, name);
for (CommandlineArgNode *n = Base.cmdline.arg_bins[hash % countof(Base.cmdline.arg_bins)]; n; n = n->next)
CommandlineArg result = Zi;
u64 hash = HashFnv64(Fnv64Basis, name);
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)
{
b32 exists;
String name;
String value;
b32 exists;
String name;
String value;
};
Struct(CommandlineArgNode)
{
CommandlineArgNode *next;
u64 hash;
CommandlineArg arg;
CommandlineArgNode *next;
u64 hash;
CommandlineArg arg;
};
Struct(CmdLineCtx)
{
String *positional_args;
u64 positional_args_count;
CommandlineArgNode *arg_bins[1024];
String *positional_args;
u64 positional_args_count;
CommandlineArgNode *arg_bins[1024];
};
////////////////////////////////////////////////////////////

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -3,23 +3,23 @@
Inline f32 IxSqrtF32(f32 f)
{
__m128 n = _mm_set_ss(f);
n = _mm_sqrt_ss(n);
return _mm_cvtss_f32(n);
__m128 n = _mm_set_ss(f);
n = _mm_sqrt_ss(n);
return _mm_cvtss_f32(n);
}
Inline f64 IxSqrtF64(f64 f)
{
__m128d n = _mm_set_sd(f);
n = _mm_sqrt_sd(_mm_setzero_pd(), n);
return _mm_cvtsd_f64(n);
__m128d n = _mm_set_sd(f);
n = _mm_sqrt_sd(_mm_setzero_pd(), n);
return _mm_cvtsd_f64(n);
}
Inline f32 IxRsqrtF32(f32 f)
{
__m128 n = _mm_set_ss(f);
n = _mm_rsqrt_ss(n);
return _mm_cvtss_f32(n);
__m128 n = _mm_set_ss(f);
n = _mm_rsqrt_ss(n);
return _mm_cvtss_f32(n);
}
////////////////////////////////////////////////////////////
@ -27,22 +27,22 @@ Inline f32 IxRsqrtF32(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)
{
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)
{
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)
{
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)
{
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)
{
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)
{
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)
{
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)
{
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)
{
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)
{
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)
{
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)
{
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)
{
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)
{
u64 id;
u64 level_id;
u64 id;
u64 level_id;
DateTime datetime;
i64 time_ns;
DateTime datetime;
i64 time_ns;
String msg;
i32 level;
String msg;
i32 level;
i32 thread_id;
i32 thread_id;
};
Struct(LogEventsArray)
{
u64 count;
LogEvent *logs;
u64 count;
LogEvent *logs;
};
////////////////////////////////////////////////////////////
@ -28,11 +28,11 @@ Struct(LogEventsArray)
/* Log level configuration */
#ifndef LogLevel_CompTime
# if IsRtcEnabled
# define LogLevel_CompTime LogLevel_Debug
# else
# define LogLevel_CompTime LogLevel_Info
# endif
#if IsRtcEnabled
#define LogLevel_CompTime LogLevel_Debug
#else
#define LogLevel_CompTime LogLevel_Info
#endif
#endif
#define LogLevel_None -1
@ -49,84 +49,84 @@ Struct(LogEventsArray)
Struct(LogLevelSettings)
{
String shorthand;
String shorthand;
};
Global Readonly LogLevelSettings log_settings[LogLevel_Count] = {
[LogLevel_Critical] = {
CompLit("CRITICAL"),
},
[LogLevel_Critical] = {
CompLit("CRITICAL"),
},
[LogLevel_Error] = {
CompLit("ERROR"),
},
[LogLevel_Error] = {
CompLit("ERROR"),
},
[LogLevel_Warning] = {
CompLit("WARNING"),
},
[LogLevel_Warning] = {
CompLit("WARNING"),
},
[LogLevel_Success] = {
CompLit("SUCCESS"),
},
[LogLevel_Success] = {
CompLit("SUCCESS"),
},
[LogLevel_Info] = {
CompLit("INFO"),
},
[LogLevel_Info] = {
CompLit("INFO"),
},
[LogLevel_Debug] = {
CompLit("DEBUG"),
}
[LogLevel_Debug] = {
CompLit("DEBUG"),
}
};
////////////////////////////////////////////////////////////
//~ Compile-time logging macros
#if LogLevel(LogLevel_Critical)
# define LogCritical(msg) Log_(LogLevel_Critical, msg)
# define LogCriticalF(fmt_lit, ...) LogF_(LogLevel_Critical, Lit(fmt_lit) , ## __VA_ARGS__, FmtEnd)
#define LogCritical(msg) Log_(LogLevel_Critical, msg)
#define LogCriticalF(fmt_lit, ...) LogF_(LogLevel_Critical, Lit(fmt_lit) , ## __VA_ARGS__, FmtEnd)
#else
# define LogCritical(msg)
# define LogCriticalF(...)
#define LogCritical(msg)
#define LogCriticalF(...)
#endif
#if LogLevel(LogLevel_Error)
# define LogError(msg) Log_(LogLevel_Error, msg)
# define LogErrorF(fmt_lit, ...) LogF_(LogLevel_Error, Lit(fmt_lit) , ## __VA_ARGS__, FmtEnd)
#define LogError(msg) Log_(LogLevel_Error, msg)
#define LogErrorF(fmt_lit, ...) LogF_(LogLevel_Error, Lit(fmt_lit) , ## __VA_ARGS__, FmtEnd)
#else
# define LogError(msg)
# define LogErrorF(...)
#define LogError(msg)
#define LogErrorF(...)
#endif
#if LogLevel(LogLevel_Warning)
# define LogWarning(msg) Log_(LogLevel_Warning, msg)
# define LogWarningF(fmt_lit, ...) LogF_(LogLevel_Warning, Lit(fmt_lit) , ## __VA_ARGS__, FmtEnd)
#define LogWarning(msg) Log_(LogLevel_Warning, msg)
#define LogWarningF(fmt_lit, ...) LogF_(LogLevel_Warning, Lit(fmt_lit) , ## __VA_ARGS__, FmtEnd)
#else
# define LogWarning(msg)
# define LogWarningF(...)
#define LogWarning(msg)
#define LogWarningF(...)
#endif
#if LogLevel(LogLevel_Success)
# define LogSuccess(msg) Log_(LogLevel_Success, msg)
# define LogSuccessF(fmt_lit, ...) LogF_(LogLevel_Success, Lit(fmt_lit) , ## __VA_ARGS__, FmtEnd)
#define LogSuccess(msg) Log_(LogLevel_Success, msg)
#define LogSuccessF(fmt_lit, ...) LogF_(LogLevel_Success, Lit(fmt_lit) , ## __VA_ARGS__, FmtEnd)
#else
# define LogSuccess(msg)
# define LogSuccessF(...)
#define LogSuccess(msg)
#define LogSuccessF(...)
#endif
#if LogLevel(LogLevel_Info)
# define LogInfo(msg) Log_(LogLevel_Info, msg)
# define LogInfoF(fmt_lit, ...) LogF_(LogLevel_Info, Lit(fmt_lit) , ## __VA_ARGS__, FmtEnd)
#define LogInfo(msg) Log_(LogLevel_Info, msg)
#define LogInfoF(fmt_lit, ...) LogF_(LogLevel_Info, Lit(fmt_lit) , ## __VA_ARGS__, FmtEnd)
#else
# define LogInfo(msg)
# define LogInfoF(...)
#define LogInfo(msg)
#define LogInfoF(...)
#endif
#if LogLevel(LogLevel_Debug)
# define LogDebug(msg) Log_(LogLevel_Debug, msg)
# define LogDebugF(fmt_lit, ...) LogF_(LogLevel_Debug, Lit(fmt_lit) , ## __VA_ARGS__, FmtEnd)
#define LogDebug(msg) Log_(LogLevel_Debug, msg)
#define LogDebugF(fmt_lit, ...) LogF_(LogLevel_Debug, Lit(fmt_lit) , ## __VA_ARGS__, FmtEnd)
#else
# define LogDebug(msg)
# define LogDebugF(...)
#define LogDebug(msg)
#define LogDebugF(...)
#endif
////////////////////////////////////////////////////////////

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

@ -1,17 +1,17 @@
u64 RandU64FromState(RandState *state)
{
u64 seed = state->seed;
if (seed == 0)
{
TrueRand(StringFromStruct(&seed));
state->seed = seed;
}
return seed ^ RandU64FromSeed(++state->counter);
u64 seed = state->seed;
if (seed == 0)
{
TrueRand(StringFromStruct(&seed));
state->seed = seed;
}
return seed ^ RandU64FromSeed(++state->counter);
}
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"
@ -19,19 +19,19 @@ f64 RandF64FromState(RandState *state, f64 range_start, f64 range_end)
*/
u64 RandU64FromSeed(u64 seed)
{
seed = (seed ^ (seed >> 32)) * 0xbea225f9eb34556d;
seed = (seed ^ (seed >> 29)) * 0xbea225f9eb34556d;
seed = (seed ^ (seed >> 32)) * 0xbea225f9eb34556d;
seed = (seed ^ (seed >> 29));
return seed;
seed = (seed ^ (seed >> 32)) * 0xbea225f9eb34556d;
seed = (seed ^ (seed >> 29)) * 0xbea225f9eb34556d;
seed = (seed ^ (seed >> 32)) * 0xbea225f9eb34556d;
seed = (seed ^ (seed >> 29));
return seed;
}
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)
{
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)
{
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 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;
};
/* 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)
{
Arena *perm = PermArena();
for (u64 archive_string_index = 0; archive_string_index < archive_strings_count; ++archive_string_index)
Arena *perm = PermArena();
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];
if (archive.len > 0)
{
BB_Buff bb = BB_BuffFromString(archive);
BB_Reader br = BB_ReaderFromBuff(&bb);
BB_Buff bb = BB_BuffFromString(archive);
BB_Reader br = BB_ReaderFromBuff(&bb);
u64 magic = BB_ReadUBits(&br, 64);
Assert(magic == ResourceEmbeddedMagic);
u64 magic = BB_ReadUBits(&br, 64);
Assert(magic == ResourceEmbeddedMagic);
/* Create & insert entries */
u64 num_entries = BB_ReadUBits(&br, 64);
for (u64 i = 0; i < num_entries; ++i)
{
u64 name_start = BB_ReadUBits(&br, 64);
u64 name_len = BB_ReadUBits(&br, 64);
u64 data_start = BB_ReadUBits(&br, 64);
u64 data_len = BB_ReadUBits(&br, 64);
/* Create & insert entries */
u64 num_entries = BB_ReadUBits(&br, 64);
for (u64 i = 0; i < num_entries; ++i)
{
u64 name_start = BB_ReadUBits(&br, 64);
u64 name_len = BB_ReadUBits(&br, 64);
u64 data_start = BB_ReadUBits(&br, 64);
u64 data_len = BB_ReadUBits(&br, 64);
ResourceEntry *entry = PushStruct(perm, ResourceEntry);
entry->name = STRING(name_len, archive.text + name_start);
entry->data = STRING(data_len, archive.text + data_start);
entry->hash = HashFnv64(Fnv64Basis, entry->name);
ResourceEntry *entry = PushStruct(perm, ResourceEntry);
entry->name = STRING(name_len, archive.text + name_start);
entry->data = STRING(data_len, archive.text + data_start);
entry->hash = HashFnv64(Fnv64Basis, entry->name);
ResourceEntryBin *bin = &Base.resource.bins[entry->hash % countof(Base.resource.bins)];
SllQueuePushN(bin->first, bin->last, entry, next_in_bin);
SllQueuePushN(Base.resource.first_entry, Base.resource.last_entry, entry, next);
}
Base.resource.entries_count += num_entries;
}
ResourceEntryBin *bin = &Base.resource.bins[entry->hash % countof(Base.resource.bins)];
SllQueuePushN(bin->first, bin->last, entry, next_in_bin);
SllQueuePushN(Base.resource.first_entry, Base.resource.last_entry, entry, next);
}
Base.resource.entries_count += num_entries;
}
}
}
@ -44,49 +44,49 @@ void BootstrapResources(u64 archive_strings_count, String *archive_strings)
b32 IsResourceNil(ResourceKey resource)
{
return resource.v == 0;
return resource.v == 0;
}
ResourceKey ResourceKeyFromStore(ResourceStore *store, String name)
{
ResourceKey result = Zi;
result.v = HashFnv64(store->v, name);
return result;
ResourceKey result = Zi;
result.v = HashFnv64(store->v, name);
return result;
}
ResourceEntry *ResourceEntryFromHash(u64 hash)
{
ResourceEntry *result = 0;
ResourceEntryBin *bin = &Base.resource.bins[hash % countof(Base.resource.bins)];
for (ResourceEntry *e = bin->first; e; e = e->next_in_bin)
ResourceEntry *result = 0;
ResourceEntryBin *bin = &Base.resource.bins[hash % countof(Base.resource.bins)];
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 result = Zi;
ResourceEntry *entry = ResourceEntryFromHash(resource.v);
if (entry)
{
result = entry->data;
}
return result;
String result = Zi;
ResourceEntry *entry = ResourceEntryFromHash(resource.v);
if (entry)
{
result = entry->data;
}
return result;
}
String NameFromResource(ResourceKey resource)
{
String result = Zi;
ResourceEntry *entry = ResourceEntryFromHash(resource.v);
if (entry)
{
result = entry->name;
}
return result;
String result = Zi;
ResourceEntry *entry = ResourceEntryFromHash(resource.v);
if (entry)
{
result = entry->name;
}
return result;
}

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -3,108 +3,108 @@
void WaveSyncEx(WaveLaneCtx *lane, u64 spin_count)
{
WaveCtx *wave = lane->wave;
i32 lanes_count = wave->lanes_count;
if (lanes_count > 1)
WaveCtx *wave = lane->wave;
i32 lanes_count = wave->lanes_count;
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);
i32 blocked_count = Atomic32FetchAdd(&wave->sync_count.v, 1) + 1;
if (blocked_count == lanes_count)
Atomic32Set(&wave->sync_count.v, 0);
Atomic64Set(&wave->sync_gen.v, sync_gen + 1);
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);
Atomic64Set(&wave->sync_gen.v, sync_gen + 1);
FutexWakeNeq(&wave->sync_gen.v);
--remaining_spins;
_mm_pause();
}
else
{
u64 remaining_spins = spin_count;
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));
}
}
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)
{
WaveCtx *wave = lane->wave;
i32 lanes_count = wave->lanes_count;
if (lanes_count > 1)
WaveCtx *wave = lane->wave;
i32 lanes_count = wave->lanes_count;
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 */
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);
/* Wait for ack */
{
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);
}
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);
}
}
}
}
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)
{
WaveCtx *wave = lane->wave;
return task_idx % wave->lanes_count;
WaveCtx *wave = lane->wave;
return task_idx % wave->lanes_count;
}
RngU64 WaveIdxRangeFromCount(WaveLaneCtx *lane, u64 tasks_count)
{
u64 lanes_count = lane->wave->lanes_count;
u64 lane_idx = lane->idx;
u64 lanes_count = lane->wave->lanes_count;
u64 lane_idx = lane->idx;
u64 tasks_per_lane = tasks_count / lanes_count;
u64 tasks_overflow = tasks_count % lanes_count;
u64 tasks_per_lane = tasks_count / lanes_count;
u64 tasks_overflow = tasks_count % lanes_count;
u64 start = lane_idx * tasks_per_lane;
u64 end = start + tasks_per_lane;
if (lane_idx < tasks_overflow)
{
start += lane_idx;
end += lane_idx + 1;
}
else
{
start += tasks_overflow;
end += tasks_overflow;
}
u64 start = lane_idx * tasks_per_lane;
u64 end = start + tasks_per_lane;
if (lane_idx < tasks_overflow)
{
start += lane_idx;
end += lane_idx + 1;
}
else
{
start += tasks_overflow;
end += tasks_overflow;
}
return RNGU64(start, end);
return RNGU64(start, end);
}

View File

@ -6,26 +6,26 @@
AlignedStruct(WaveCtx, CachelineSize)
{
i32 lanes_count;
void *udata;
i32 lanes_count;
void *udata;
/* Sync barrier */
Atomic32Padded sync_count;
Atomic64Padded sync_gen;
/* Sync barrier */
Atomic32Padded sync_count;
Atomic64Padded sync_gen;
/* Broadcast barrier */
void *broadcast_data;
Atomic64Padded broadcast_gen;
Atomic32Padded ack_count;
Atomic64Padded ack_gen;
/* Broadcast barrier */
void *broadcast_data;
Atomic64Padded broadcast_gen;
Atomic32Padded ack_count;
Atomic64Padded ack_gen;
};
AlignedStruct(WaveLaneCtx, CachelineSize)
{
i32 idx;
WaveCtx *wave;
u64 default_spin_count;
i64 seen_broadcast_gen;
i32 idx;
WaveCtx *wave;
u64 default_spin_count;
i64 seen_broadcast_gen;
};
typedef void WaveLaneEntryFunc(WaveLaneCtx *lane);
@ -34,14 +34,16 @@ typedef void WaveLaneEntryFunc(WaveLaneCtx *lane);
//~ Wave sync ops
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);
#define WaveSync(lane) \
WaveSyncEx((lane), (lane)->default_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) \
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);

View File

@ -5,34 +5,34 @@ W32_Ctx W32 = Zi;
BOOL W32_FindEmbeddedRcData(HMODULE module, LPCWSTR type, LPWSTR wstr_entry_name, LONG_PTR udata)
{
W32_FindEmbeddedDataCtx *ctx = (W32_FindEmbeddedDataCtx *)udata;
TempArena scratch = BeginScratchNoConflict();
String entry_name = StringFromWstrNoLimit(scratch.arena, (LPWSTR)wstr_entry_name);
String embedded_data_prefix = Lit(Stringize(W32_EmbeddedDataPrefix));
if (StringBeginsWith(entry_name, embedded_data_prefix))
W32_FindEmbeddedDataCtx *ctx = (W32_FindEmbeddedDataCtx *)udata;
TempArena scratch = BeginScratchNoConflict();
String entry_name = StringFromWstrNoLimit(scratch.arena, (LPWSTR)wstr_entry_name);
String embedded_data_prefix = Lit(Stringize(W32_EmbeddedDataPrefix));
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);
if (hres)
HGLOBAL hg = LoadResource(module, hres);
if (hg)
{
if (ctx->embedded_strings_count < countof(ctx->embedded_strings))
{
HGLOBAL hg = LoadResource(module, hres);
if (hg)
{
if (ctx->embedded_strings_count < countof(ctx->embedded_strings))
{
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"));
}
}
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"));
}
}
}
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)
{
return W32.raw_command_line;
return W32.raw_command_line;
}
void Echo(String msg)
{
HANDLE console_handle = GetStdHandle(STD_OUTPUT_HANDLE);
if (console_handle && console_handle != INVALID_HANDLE_VALUE)
{
WriteFile(console_handle, msg.text, msg.len, 0, 0);
}
else if (IsRunningInDebugger())
{
char msg_cstr[16384];
u64 len = MinU64(countof(msg_cstr) - 1, msg.len);
CopyBytes(msg_cstr, msg.text, len);
msg_cstr[len] = 0;
OutputDebugStringA(msg_cstr);
}
HANDLE console_handle = GetStdHandle(STD_OUTPUT_HANDLE);
if (console_handle && console_handle != INVALID_HANDLE_VALUE)
{
WriteFile(console_handle, msg.text, msg.len, 0, 0);
}
else if (IsRunningInDebugger())
{
char msg_cstr[16384];
u64 len = MinU64(countof(msg_cstr) - 1, msg.len);
CopyBytes(msg_cstr, msg.text, len);
msg_cstr[len] = 0;
OutputDebugStringA(msg_cstr);
}
}
b32 Panic(String msg)
{
LogPanic(msg);
char msg_cstr[4096];
CstrFromStringToBuff(StringFromFixedArray(msg_cstr), msg);
{
u32 mb_flags = MB_SETFOREGROUND | MB_ICONERROR;
MessageBoxExA(0, msg_cstr, "Fatal error", mb_flags, 0);
}
HANDLE console_handle = GetStdHandle(STD_ERROR_HANDLE);
if (console_handle != INVALID_HANDLE_VALUE)
{
WriteFile(console_handle, msg.text, msg.len, 0, 0);
}
if (IsRunningInDebugger())
{
Assert(0);
}
else
{
ExitProcess(1);
}
return 0;
LogPanic(msg);
char msg_cstr[4096];
CstrFromStringToBuff(StringFromFixedArray(msg_cstr), msg);
{
u32 mb_flags = MB_SETFOREGROUND | MB_ICONERROR;
MessageBoxExA(0, msg_cstr, "Fatal error", mb_flags, 0);
}
HANDLE console_handle = GetStdHandle(STD_ERROR_HANDLE);
if (console_handle != INVALID_HANDLE_VALUE)
{
WriteFile(console_handle, msg.text, msg.len, 0, 0);
}
if (IsRunningInDebugger())
{
Assert(0);
}
else
{
ExitProcess(1);
}
return 0;
}
b32 IsRunningInDebugger(void)
{
return IsDebuggerPresent();
return IsDebuggerPresent();
}
i64 TimeNs(void)
{
LARGE_INTEGER qpc;
QueryPerformanceCounter(&qpc);
i64 result = (qpc.QuadPart - W32.timer_start_qpc) * W32.ns_per_qpc;
return result;
LARGE_INTEGER qpc;
QueryPerformanceCounter(&qpc);
i64 result = (qpc.QuadPart - W32.timer_start_qpc) * W32.ns_per_qpc;
return result;
}
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)
{
TempArena scratch = BeginScratchNoConflict();
CpuTopologyInfo res = Zi;
TempArena scratch = BeginScratchNoConflict();
CpuTopologyInfo res = Zi;
{
DWORD infos_buff_size = 0;
u8 *infos_buff = 0;
b32 ok = 0;
{
DWORD infos_buff_size = 0;
u8 *infos_buff = 0;
b32 ok = 0;
{
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;
}
}
}
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);
}
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;
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);
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)
{
f64 ms = seconds * 1000.0;
if (ms > 4000000000)
{
Sleep(INFINITE);
}
else
{
Sleep((u32)ms);
}
f64 ms = seconds * 1000.0;
if (ms > 4000000000)
{
Sleep(INFINITE);
}
else
{
Sleep((u32)ms);
}
}
////////////////////////////////////////////////////////////
@ -182,60 +182,60 @@ void SleepSeconds(f64 seconds)
b32 IsSwappedIn(void)
{
return IsHotSwappingEnabled;
return IsHotSwappingEnabled;
}
b32 IsSwappingOut(void)
{
return IsHotSwappingEnabled;
return IsHotSwappingEnabled;
}
String SwappedStateFromName(Arena *arena, String name)
{
TempArena scratch = BeginScratch(arena);
String result = Zi;
String path = StringF(scratch.arena, "ppswap/%F.swp", FmtString(name));
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);
if (handle != INVALID_HANDLE_VALUE)
TempArena scratch = BeginScratch(arena);
String result = Zi;
String path = StringF(scratch.arena, "ppswap/%F.swp", FmtString(name));
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);
if (handle != INVALID_HANDLE_VALUE)
{
u32 chunk_size = Kibi(64);
result.text = ArenaNext(arena, u8);
for (;;)
{
u32 chunk_size = Kibi(64);
result.text = ArenaNext(arena, u8);
for (;;)
{
u8 *chunk = PushStructsNoZero(arena, u8, chunk_size);
u32 chunk_bytes_read = 0;
ReadFile(handle, chunk, chunk_size, (LPDWORD)&chunk_bytes_read, 0);
result.len += chunk_bytes_read;
if (chunk_bytes_read < chunk_size)
{
PopStructsNoCopy(arena, u8, chunk_size - chunk_bytes_read);
break;
}
}
u8 *chunk = PushStructsNoZero(arena, u8, chunk_size);
u32 chunk_bytes_read = 0;
ReadFile(handle, chunk, chunk_size, (LPDWORD)&chunk_bytes_read, 0);
result.len += chunk_bytes_read;
if (chunk_bytes_read < chunk_size)
{
PopStructsNoCopy(arena, u8, chunk_size - chunk_bytes_read);
break;
}
}
CloseHandle(handle);
EndScratch(scratch);
return result;
}
CloseHandle(handle);
EndScratch(scratch);
return result;
}
void WriteSwappedState(String name, String data)
{
TempArena scratch = BeginScratchNoConflict();
/* TODO: Use directory non-relative to executable */
CreateDirectoryW(L"ppswap", 0);
String result = Zi;
String path = StringF(scratch.arena, "ppswap/%F.swp", FmtString(name));
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);
if (handle != INVALID_HANDLE_VALUE)
{
SetFilePointer(handle, 0, 0, FILE_BEGIN);
SetEndOfFile(handle);
WriteFile(handle, data.text, data.len, 0, 0);
}
CloseHandle(handle);
EndScratch(scratch);
TempArena scratch = BeginScratchNoConflict();
/* TODO: Use directory non-relative to executable */
CreateDirectoryW(L"ppswap", 0);
String result = Zi;
String path = StringF(scratch.arena, "ppswap/%F.swp", FmtString(name));
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);
if (handle != INVALID_HANDLE_VALUE)
{
SetFilePointer(handle, 0, 0, FILE_BEGIN);
SetEndOfFile(handle);
WriteFile(handle, data.text, data.len, 0, 0);
}
CloseHandle(handle);
EndScratch(scratch);
}
////////////////////////////////////////////////////////////
@ -243,23 +243,23 @@ void WriteSwappedState(String name, String data)
void OnExit(ExitFunc *func)
{
i32 index = Atomic32FetchAdd(&W32.num_exit_funcs, 1);
if (index >= countof(W32.exit_funcs))
{
Panic(Lit("Maximum on exit functions registered"));
}
W32.exit_funcs[index] = func;
i32 index = Atomic32FetchAdd(&W32.num_exit_funcs, 1);
if (index >= countof(W32.exit_funcs))
{
Panic(Lit("Maximum on exit functions registered"));
}
W32.exit_funcs[index] = func;
}
void SignalExit(i32 code)
{
Atomic32Set(&W32.exit_code, code);
SetEvent(W32.exit_event);
Atomic32Set(&W32.exit_code, code);
SetEvent(W32.exit_event);
}
void ExitNow(i32 code)
{
ExitProcess(code);
ExitProcess(code);
}
////////////////////////////////////////////////////////////
@ -267,88 +267,88 @@ void ExitNow(i32 code)
void W32_BootstrapLogs(String logfile_path)
{
W32.logs_arena = AcquireArena(Gibi(64));
W32.log_msgs_arena = AcquireArena(Gibi(64));
W32.readable_log_events = ArenaNext(W32.logs_arena, LogEvent);
if (logfile_path.len > 0)
W32.logs_arena = AcquireArena(Gibi(64));
W32.log_msgs_arena = AcquireArena(Gibi(64));
W32.readable_log_events = ArenaNext(W32.logs_arena, LogEvent);
if (logfile_path.len > 0)
{
TempArena scratch = BeginScratchNoConflict();
{
TempArena scratch = BeginScratchNoConflict();
{
wchar_t *path_wstr = WstrFromString(scratch.arena, logfile_path);
W32.logfile = CreateFileW(
path_wstr,
FILE_APPEND_DATA,
FILE_SHARE_READ | FILE_SHARE_WRITE,
0,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
0
);
}
EndScratch(scratch);
wchar_t *path_wstr = WstrFromString(scratch.arena, logfile_path);
W32.logfile = CreateFileW(
path_wstr,
FILE_APPEND_DATA,
FILE_SHARE_READ | FILE_SHARE_WRITE,
0,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
0
);
}
Atomic32Set(&W32.logs_initialized, 1);
EndScratch(scratch);
}
Atomic32Set(&W32.logs_initialized, 1);
}
void W32_Log(i32 level, String msg)
{
TempArena scratch = BeginScratchNoConflict();
if (Atomic32Fetch(&W32.logs_initialized))
TempArena scratch = BeginScratchNoConflict();
if (Atomic32Fetch(&W32.logs_initialized))
{
LogLevelSettings settings = log_settings[level];
if (level < 0 || level >= LogLevel_Count)
{
LogLevelSettings settings = log_settings[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);
Panic(Lit("Invalid log level"));
}
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. */
void LogPanic(String msg)
{
if (Atomic32Fetch(&W32.logs_initialized))
{
String beg = Lit("******** PANICKING ********\n");
String end = Lit("\n***************************\n");
WriteFile(W32.logfile, beg.text, beg.len, 0, 0);
WriteFile(W32.logfile, msg.text, msg.len, 0, 0);
WriteFile(W32.logfile, end.text, end.len, 0, 0);
}
if (Atomic32Fetch(&W32.logs_initialized))
{
String beg = Lit("******** PANICKING ********\n");
String end = Lit("\n***************************\n");
WriteFile(W32.logfile, beg.text, beg.len, 0, 0);
WriteFile(W32.logfile, msg.text, msg.len, 0, 0);
WriteFile(W32.logfile, end.text, end.len, 0, 0);
}
}
void Log_(i32 level, String msg)
{
W32_Log(level, msg);
W32_Log(level, msg);
}
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();
va_list args;
va_start(args, fmt);
{
String msg = FormatString(scratch.arena, fmt, FmtArgsFromVaList(scratch.arena, args));
W32_Log(level, msg);
}
va_end(args);
EndScratch(scratch);
String msg = FormatString(scratch.arena, fmt, FmtArgsFromVaList(scratch.arena, args));
W32_Log(level, msg);
}
va_end(args);
EndScratch(scratch);
}
}
LogEventsArray GetLogEvents(void)
{
LogEventsArray result = Zi;
result.count = Atomic64Fetch(&W32.readable_logs_count);
if (result.count > 0)
{
result.logs = W32.readable_log_events;
}
return result;
LogEventsArray result = Zi;
result.count = Atomic64Fetch(&W32.readable_logs_count);
if (result.count > 0)
{
result.logs = W32.readable_log_events;
}
return result;
}
////////////////////////////////////////////////////////////
@ -405,150 +405,148 @@ LogEventsArray GetLogEvents(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;
QueryPerformanceFrequency(&qpf);
W32.ns_per_qpc = 1000000000 / qpf.QuadPart;
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)
{
LARGE_INTEGER qpc;
QueryPerformanceCounter(&qpc);
W32.timer_start_qpc = qpc.QuadPart;
ExitFunc *func = W32.exit_funcs[idx];
func();
}
}
/* 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;
{
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);
/* 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
#if IsCrtlibEnabled
# if IsConsoleApp
int main(char **argc, int argv)
{
return W32_Main();
}
# else
int CALLBACK wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev_instance, _In_ LPWSTR cmdline_wstr, _In_ int show_code)
{
return W32_Main();
}
# endif /* IsConsoleApp */
#if IsConsoleApp
int main(char **argc, int argv)
{
return W32_Main();
}
#else
int CALLBACK wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev_instance, _In_ LPWSTR cmdline_wstr, _In_ int show_code)
{
return W32_Main();
}
#endif /* IsConsoleApp */
#endif /* IsCrtlibEnabled */
////////////////////////////////////////////////////////////
//~ Crt stub
#if !IsCrtlibEnabled
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wmissing-variable-declarations"
#pragma clang diagnostic ignored "-Wmissing-prototypes"
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wmissing-variable-declarations"
#pragma clang diagnostic ignored "-Wmissing-prototypes"
/* Enable floating point */
__attribute((used))
int _fltused;
/* Enable floating point */
__attribute((used))
int _fltused;
__attribute((used))
void __stdcall wWinMainCRTStartup(void)
{
__attribute((used))
void __stdcall wWinMainCRTStartup(void)
{
i32 result = W32_Main();
ExitProcess(result);
}
#pragma clang diagnostic pop
}
#pragma clang diagnostic pop
#endif /* !IsCrtlibEnabled */

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

@ -5,9 +5,9 @@ D_SharedState D_shared_state = ZI;
void D_Bootstrap(void)
{
D_SharedState *g = &D_shared_state;
u32 pixel_white = 0xFFFFFFFF;
g->solid_white_texture = GPU_AcquireTexture(GP_TEXTURE_FORMAT_R8G8B8A8_UNORM, 0, VEC2I32(1, 1), &pixel_white);
D_SharedState *g = &D_shared_state;
u32 pixel_white = 0xFFFFFFFF;
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)
{
GPU_RenderCmdDesc cmd = ZI;
cmd.kind = GP_RENDER_CMD_KIND_DRAW_MATERIAL;
cmd.material.xf = params.xf;
cmd.material.texture = params.texture;
cmd.material.clip = params.clip;
cmd.material.tint = params.tint;
cmd.material.is_light = params.is_light;
cmd.material.light_emittance = params.light_emittance;
GPU_PushRenderCmd(sig, &cmd);
GPU_RenderCmdDesc cmd = ZI;
cmd.kind = GP_RENDER_CMD_KIND_DRAW_MATERIAL;
cmd.material.xf = params.xf;
cmd.material.texture = params.texture;
cmd.material.clip = params.clip;
cmd.material.tint = params.tint;
cmd.material.is_light = params.is_light;
cmd.material.light_emittance = params.light_emittance;
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)
{
GPU_RenderCmdDesc cmd = ZI;
cmd.kind = GP_RENDER_CMD_KIND_DRAW_UI_SHAPE;
cmd.ui_shape.vertices = vertices;
cmd.ui_shape.indices = indices;
cmd.ui_shape.color = color;
GPU_PushRenderCmd(sig, &cmd);
GPU_RenderCmdDesc cmd = ZI;
cmd.kind = GP_RENDER_CMD_KIND_DRAW_UI_SHAPE;
cmd.ui_shape.vertices = vertices;
cmd.ui_shape.indices = indices;
cmd.ui_shape.color = color;
GPU_PushRenderCmd(sig, &cmd);
}
/* Draws a filled polygon using triangles in a fan pattern */
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 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)
{
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);
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);
}
}
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);
for (u32 i = 0; i < detail; ++i)
{
f32 angle = ((f32)i / (f32)detail) * Tau;
Vec2 p = VEC2(
radius * CosF32(angle),
radius * SinF32(angle)
);
points[i] = AddVec2(pos, p);
}
Vec2 *points = PushStructsNoZero(scratch.arena, Vec2, detail);
for (u32 i = 0; i < detail; ++i)
{
f32 angle = ((f32)i / (f32)detail) * Tau;
Vec2 p = VEC2(
radius * CosF32(angle),
radius * SinF32(angle)
);
points[i] = AddVec2(pos, p);
}
Vec2Array vertices = {
.points = points,
.count = detail
};
D_DrawPoly(sig, vertices, color);
Vec2Array vertices = {
.points = points,
.count = detail
};
D_DrawPoly(sig, vertices, color);
EndScratch(scratch);
EndScratch(scratch);
}
void D_DrawQuad(GPU_RenderSig *sig, Quad quad, u32 color)
{
PERSIST const u32 indices_array[6] = {
0, 1, 2,
0, 2, 3
};
Vec2Array vertices = { .count = 4, .points = quad.e };
GPU_Indices indices = { .count = 6, .indices = indices_array };
D_DrawPolyEx(sig, vertices, indices, color);
PERSIST const u32 indices_array[6] = {
0, 1, 2,
0, 2, 3
};
Vec2Array vertices = { .count = 4, .points = quad.e };
GPU_Indices indices = { .count = 6, .indices = indices_array };
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)
{
#if 0
D_SharedState *g = &D_shared_state;
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_SharedState *g = &D_shared_state;
Quad quad = QuadFromLine(start, end, thickness);
D_DrawMaterial(sig, D_MATERIALPARAMS(.texture = g->solid_white_texture, .tint0 = start_color, .tint1 = end_color, .quad = quad));
#else
/* Placeholder */
Quad quad = QuadFromLine(start, end, thickness);
D_DrawQuad(sig, quad, start_color);
/* Placeholder */
Quad quad = QuadFromLine(start, end, thickness);
D_DrawQuad(sig, quad, start_color);
#endif
}
void D_DrawLine(GPU_RenderSig *sig, Vec2 start, Vec2 end, f32 thickness, u32 color)
{
Quad quad = QuadFromLine(start, end, thickness);
D_DrawQuad(sig, quad, color);
Quad quad = QuadFromLine(start, end, thickness);
D_DrawQuad(sig, quad, color);
}
void D_DrawRay(GPU_RenderSig *sig, Vec2 pos, Vec2 rel, f32 thickness, u32 color)
{
Quad quad = QuadFromRay(pos, rel, thickness);
D_DrawQuad(sig, quad, color);
Quad quad = QuadFromRay(pos, rel, thickness);
D_DrawQuad(sig, quad, 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];
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);
}
Vec2 p1 = points.points[i - 1];
Vec2 p2 = points.points[i];
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)
{
TempArena scratch = BeginScratchNoConflict();
TempArena scratch = BeginScratchNoConflict();
Vec2 *points = PushStructsNoZero(scratch.arena, Vec2, detail);
for (u32 i = 0; i < detail; ++i)
{
f32 angle = ((f32)i / (f32)detail) * Tau;
Vec2 p = VEC2(
radius * CosF32(angle),
radius * SinF32(angle)
);
points[i] = AddVec2(pos, p);
}
Vec2 *points = PushStructsNoZero(scratch.arena, Vec2, detail);
for (u32 i = 0; i < detail; ++i)
{
f32 angle = ((f32)i / (f32)detail) * Tau;
Vec2 p = VEC2(
radius * CosF32(angle),
radius * SinF32(angle)
);
points[i] = AddVec2(pos, p);
}
Vec2Array a = {
.points = points,
.count = detail
};
D_DrawPolyLine(sig, a, 1, thickness, color);
Vec2Array a = {
.points = points,
.count = detail
};
D_DrawPolyLine(sig, a, 1, thickness, color);
EndScratch(scratch);
EndScratch(scratch);
}
void D_DrawQuadLine(GPU_RenderSig *sig, Quad quad, f32 thickness, u32 color)
{
Vec2 points[] = { quad.p0, quad.p1, quad.p2, quad.p3 };
Vec2Array a = { .points = points, .count = countof(points) };
D_DrawPolyLine(sig, a, 1, thickness, color);
Vec2 points[] = { quad.p0, quad.p1, quad.p2, quad.p3 };
Vec2Array a = { .points = points, .count = countof(points) };
D_DrawPolyLine(sig, a, 1, thickness, 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 */
arrowhead_height = MinF32(arrowhead_height, Vec2Len(SubVec2(end, start)) * max_height_to_line_ratio);
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);
Vec2 head_start_dir = SubVec2(start, end);
head_start_dir = NormVec2(head_start_dir);
head_start_dir = MulVec2(head_start_dir, arrowhead_height);
Vec2 head_start_dir = SubVec2(start, end);
head_start_dir = NormVec2(head_start_dir);
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_p2_dir = NegVec2(head_p1_dir);
Vec2 head_p1_dir = MulPerpVec2(head_start_dir, head_width_ratio);
Vec2 head_p2_dir = NegVec2(head_p1_dir);
Vec2 head_p1 = AddVec2(head_start, head_p1_dir);
Vec2 head_p2 = AddVec2(head_start, head_p2_dir);
Vec2 head_p1 = AddVec2(head_start, head_p1_dir);
Vec2 head_p2 = AddVec2(head_start, head_p2_dir);
Vec2 head_points[] = { end, head_p1, head_p2 };
Vec2Array head_points_v2_array = {
.points = head_points,
.count = countof(head_points)
};
D_DrawPoly(sig, head_points_v2_array, color);
Vec2 head_points[] = { end, head_p1, head_p2 };
Vec2Array head_points_v2_array = {
.points = head_points,
.count = countof(head_points)
};
D_DrawPoly(sig, head_points_v2_array, color);
Quad line_quad = QuadFromLine(start, head_start, thickness);
D_DrawQuad(sig, line_quad, color);
Quad line_quad = QuadFromLine(start, head_start, thickness);
D_DrawQuad(sig, line_quad, color);
}
void D_DrawArrowRay(GPU_RenderSig *sig, Vec2 pos, Vec2 rel, f32 thickness, f32 arrowhead_height, u32 color)
{
Vec2 end = AddVec2(pos, rel);
D_DrawArrowLine(sig, pos, end, thickness, arrowhead_height, color);
Vec2 end = AddVec2(pos, rel);
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)
{
TempArena scratch = BeginScratchNoConflict();
Vec2Array poly = ZI;
if (shape.radius == 0)
TempArena scratch = BeginScratchNoConflict();
Vec2Array poly = ZI;
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;
poly.points = PushStructsNoZero(scratch.arena, Vec2, shape.count);
for (u32 i = 0; i < shape.count; ++i)
{
Vec2 p = MulXformV2(shape_xf, shape.points[i]);
poly.points[i] = p;
}
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;
poly.points = PushStructsNoZero(scratch.arena, Vec2, detail);
for (u32 i = 0; i < detail; ++i)
{
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;
}
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)
{
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);
}
i32 grid_id = 0;
{
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);
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;
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)
{
GPU_RenderCmdDesc cmd = ZI;
cmd.kind = GP_RENDER_CMD_KIND_DRAW_UI_RECT;
cmd.ui_rect.xf = params.xf;
cmd.ui_rect.texture = params.texture;
cmd.ui_rect.clip = params.clip;
cmd.ui_rect.tint = params.tint;
GPU_PushRenderCmd(sig, &cmd);
GPU_RenderCmdDesc cmd = ZI;
cmd.kind = GP_RENDER_CMD_KIND_DRAW_UI_RECT;
cmd.ui_rect.xf = params.xf;
cmd.ui_rect.texture = params.texture;
cmd.ui_rect.clip = params.clip;
cmd.ui_rect.tint = params.tint;
GPU_PushRenderCmd(sig, &cmd);
}
////////////////////////////////////////////////////////////
//~ Text
/* Returns the rect of the text area */
/* Returns the rect of the text area */
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_height = 1.0 / (f32)params.font->image_height;
f32 line_spacing = params.font->point_size * 1.5f * params.scale;
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 line_spacing = params.font->point_size * 1.5f * params.scale;
//- Build line glyphs
//- Build line glyphs
u64 num_lines = 0;
f32 widest_line = 0;
u64 num_lines = 0;
f32 widest_line = 0;
D_TextLine *first_line = 0;
D_TextLine *last_line = 0;
f32 first_line_top_offset = 0;
f32 last_line_bottom_offset = 0;
D_TextLine *first_line = 0;
D_TextLine *last_line = 0;
f32 first_line_top_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;
CodepointIter iter = BeginCodepointIter(params.str);
while (!string_done)
f32 line_width = 0;
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)
{
f32 line_width = 0;
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;
line_done = 1;
}
EndCodepointIter(&iter);
}
//- 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:
else
{
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;
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);
}
}
}
/* Draw glyphs in line */
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 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);
}
}
++line_number;
//- 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;
} 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);
return bounds;
/* Draw glyphs in line */
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)
{
Xform xf;
GPU_Resource *texture;
ClipRect clip;
u32 tint;
b32 is_light;
Vec3 light_emittance;
Xform xf;
GPU_Resource *texture;
ClipRect clip;
u32 tint;
b32 is_light;
Vec3 light_emittance;
};
#define D_MATERIALPARAMS(...) ((D_MaterialParams) { \
.tint = Color_White, \
.clip = AllClipped, \
__VA_ARGS__ \
.tint = Color_White, \
.clip = AllClipped, \
__VA_ARGS__ \
})
////////////////////////////////////////////////////////////
@ -21,15 +21,15 @@ Struct(D_MaterialParams)
Struct(D_UiRectParams)
{
Xform xf;
GPU_Resource *texture;
ClipRect clip;
u32 tint;
Xform xf;
GPU_Resource *texture;
ClipRect clip;
u32 tint;
};
#define D_UIRECTPARAMS(...) ((D_UiRectParams) { \
.tint = Color_White, \
.clip = AllClipped, \
__VA_ARGS__ \
.tint = Color_White, \
.clip = AllClipped, \
__VA_ARGS__ \
})
////////////////////////////////////////////////////////////
@ -38,9 +38,9 @@ Struct(D_UiRectParams)
/* How is text aligned within its area */
Enum(D_TextAlignment)
{
DRAW_TEXT_ALIGNMENT_LEFT, /* Default */
DRAW_TEXT_ALIGNMENT_CENTER,
DRAW_TEXT_ALIGNMENT_RIGHT
DRAW_TEXT_ALIGNMENT_LEFT, /* Default */
DRAW_TEXT_ALIGNMENT_CENTER,
DRAW_TEXT_ALIGNMENT_RIGHT
};
/* How does the specified text position relate to the text area.
@ -48,54 +48,54 @@ Enum(D_TextAlignment)
* the specified position. */
Enum(D_TextOffsetX)
{
DRAW_TEXT_OFFSET_X_LEFT, /* Default */
DRAW_TEXT_OFFSET_X_CENTER,
DRAW_TEXT_OFFSET_X_RIGHT
DRAW_TEXT_OFFSET_X_LEFT, /* Default */
DRAW_TEXT_OFFSET_X_CENTER,
DRAW_TEXT_OFFSET_X_RIGHT
};
Enum(D_TextOffsetY)
{
DRAW_TEXT_OFFSET_Y_TOP, /* Default */
DRAW_TEXT_OFFSET_Y_CENTER,
DRAW_TEXT_OFFSET_Y_BOTTOM
DRAW_TEXT_OFFSET_Y_TOP, /* Default */
DRAW_TEXT_OFFSET_Y_CENTER,
DRAW_TEXT_OFFSET_Y_BOTTOM
};
Struct(D_TextGlyph)
{
f32 off_x;
f32 off_y;
f32 width;
f32 height;
f32 advance;
ClipRect clip;
f32 off_x;
f32 off_y;
f32 width;
f32 height;
f32 advance;
ClipRect clip;
};
Struct(D_TextLine)
{
f32 line_width;
u32 num_glyphs;
D_TextGlyph *glyphs;
D_TextLine *next;
f32 line_width;
u32 num_glyphs;
D_TextGlyph *glyphs;
D_TextLine *next;
};
Struct(D_TextParams)
{
F_Font *font;
Vec2 pos;
f32 scale;
u32 color;
D_TextAlignment alignment;
D_TextOffsetX offset_x;
D_TextOffsetY offset_y;
String str;
F_Font *font;
Vec2 pos;
f32 scale;
u32 color;
D_TextAlignment alignment;
D_TextOffsetX offset_x;
D_TextOffsetY offset_y;
String str;
};
#define D_TEXTPARAMS(...) ((D_TextParams) { \
.scale = 1.0, \
.alignment = DRAW_TEXT_ALIGNMENT_LEFT, \
.offset_x = DRAW_TEXT_OFFSET_X_LEFT, \
.offset_y = DRAW_TEXT_OFFSET_Y_TOP, \
.color = Color_White, \
__VA_ARGS__ \
.scale = 1.0, \
.alignment = DRAW_TEXT_ALIGNMENT_LEFT, \
.offset_x = DRAW_TEXT_OFFSET_X_LEFT, \
.offset_y = DRAW_TEXT_OFFSET_Y_TOP, \
.color = Color_White, \
__VA_ARGS__ \
})
////////////////////////////////////////////////////////////
@ -103,7 +103,7 @@ Struct(D_TextParams)
Struct(D_SharedState)
{
GPU_Resource *solid_white_texture;
GPU_Resource *solid_white_texture;
} extern D_shared_state;
////////////////////////////////////////////////////////////

View File

@ -5,7 +5,7 @@ GC_Ctx GC = Zi;
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 result = Zi;
result.r = resource;
return result;
GC_FontKey result = Zi;
result.r = resource;
return result;
}
u64 GC_HashFromGlyphDesc(GC_GlyphDesc desc)
{
/* 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);
/* 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);
}
////////////////////////////////////////////////////////////
@ -30,189 +30,189 @@ u64 GC_HashFromGlyphDesc(GC_GlyphDesc desc)
/* TODO: Thread-local cache */
GC_Run GC_RunFromString(Arena *arena, String str, GC_FontKey font, f32 font_size)
{
GC_Run result = Zi;
TempArena scratch = BeginScratch(arena);
Arena *perm = PermArena();
GC_Run result = Zi;
TempArena scratch = BeginScratch(arena);
Arena *perm = PermArena();
u64 codepoints_count = 0;
u32 *codepoints = 0;
u64 codepoints_count = 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);
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)
Lock lock = LockS(&GC.glyphs_mutex);
{
i64 completion = G_CompletionValueFromQueue(G_QueueKind_AsyncCopy);
for (u64 codepoint_idx = 0; codepoint_idx < codepoints_count; ++codepoint_idx)
{
Lock lock = LockS(&GC.glyphs_mutex);
{
i64 completion = G_CompletionValueFromQueue(G_QueueKind_AsyncCopy);
for (u64 codepoint_idx = 0; codepoint_idx < codepoints_count; ++codepoint_idx)
{
u32 codepoint = codepoints[codepoint_idx];
u32 codepoint = codepoints[codepoint_idx];
GC_GlyphDesc desc = Zi;
desc.font = font;
desc.font_size = font_size;
desc.codepoint = codepoint;
GC_GlyphDesc desc = Zi;
desc.font = font;
desc.font_size = font_size;
desc.codepoint = codepoint;
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;
}
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)
{
uncached_codepoints[uncached_codepoints_count] = codepoint;
uncached_codepoints_count += 1;
}
else if (completion < Atomic64Fetch(&glyph->async_copy_completion_target))
{
pending_glyphs_count += 1;
}
else
{
ready_glyphs[ready_glyphs_count] = glyph;
ready_glyphs_count += 1;
}
}
}
Unlock(&lock);
if (glyph == 0)
{
uncached_codepoints[uncached_codepoints_count] = codepoint;
uncached_codepoints_count += 1;
}
else if (completion < Atomic64Fetch(&glyph->async_copy_completion_target))
{
pending_glyphs_count += 1;
}
else
{
ready_glyphs[ready_glyphs_count] = glyph;
ready_glyphs_count += 1;
}
}
}
Unlock(&lock);
}
}
//////////////////////////////
//- Create cache entries
//////////////////////////////
//- Create cache entries
u64 submit_cmds_count = 0;
GC_Cmd *submit_cmds = PushStructsNoZero(scratch.arena, GC_Cmd, uncached_codepoints_count);
if (uncached_codepoints_count > 0)
u64 submit_cmds_count = 0;
GC_Cmd *submit_cmds = PushStructsNoZero(scratch.arena, GC_Cmd, uncached_codepoints_count);
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)
{
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);
if (glyph->hash == hash) break;
}
baseline_pos += rect->advance;
result.baseline_length = MaxF32(result.baseline_length, baseline_pos);
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);
}
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];
result.font_size = glyph->font_size;
result.font_ascent = glyph->font_ascent;
result.font_descent = glyph->font_descent;
result.font_cap = glyph->font_cap;
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);
}
// result.ready = uncached_codepoints_count == 0 && pending_glyphs_count == 0;
result.ready = 1;
baseline_pos += rect->advance;
result.baseline_length = MaxF32(result.baseline_length, baseline_pos);
}
EndScratch(scratch);
return result;
if (ready_glyphs_count > 0)
{
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)
{
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);
Lock lock = LockE(&GC.submit.mutex);
{
/* Pop cmds from submission queue */
async->cmds.count = GC.submit.count;
async->cmds.v = PushStructsNoZero(tick->arena, GC_Cmd, GC.submit.count);
u64 cmd_idx = 0;
for (GC_CmdNode *n = GC.submit.first; n; n = n->next)
{
async->cmds.v[cmd_idx] = n->cmd;
++cmd_idx;
}
/* Reset submission queue */
GC.submit.first_free = GC.submit.first;
GC.submit.count = 0;
GC.submit.first = 0;
GC.submit.last = 0;
}
Unlock(&lock);
/* Pop cmds from submission queue */
async->cmds.count = GC.submit.count;
async->cmds.v = PushStructsNoZero(tick->arena, GC_Cmd, GC.submit.count);
u64 cmd_idx = 0;
for (GC_CmdNode *n = GC.submit.first; n; n = n->next)
{
async->cmds.v[cmd_idx] = n->cmd;
++cmd_idx;
}
/* Reset submission queue */
GC.submit.first_free = GC.submit.first;
GC.submit.count = 0;
GC.submit.first = 0;
GC.submit.last = 0;
}
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);
if (async->cmds.count > 0)
////////////////////////////
//- Allocate atlas slices
if (lane->idx == 0)
{
//////////////////////////////
//- Rasterize glyphs
G_CommandListHandle cl = G_PrepareCommandList(G_QueueKind_AsyncCopy);
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);
for (u64 cmd_idx = cmd_idxs.min; cmd_idx < cmd_idxs.max; ++cmd_idx)
/* Create atlas */
if (!atlas)
{
Arena *perm = PermArena();
atlas = PushStruct(perm, GC_Atlas);
atlas->dims = VEC2I32(1024, 1024);
{
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;
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;
}
}
/* 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);
////////////////////////////
//- Allocate atlas slices
if (lane->idx == 0)
/* Copy to atlas */
u32 *image_pixels = ttf_result.image_pixels;
if (image_dims.x > 0 && image_dims.y > 0)
{
G_CommandListHandle cl = G_PrepareCommandList(G_QueueKind_AsyncCopy);
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;
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);
}
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);
}
}
}
}

View File

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

View File

@ -6,57 +6,57 @@ ThreadLocal G_ArenaHandle G_t_perm_arena = Zi;
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 };
quad_indices = G_PushBuffer(gpu_perm, cl, u16, countof(quad_data));
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_ResourceHandle quad_indices = Zi;
u16 quad_data[6] = { 0, 1, 2, 0, 2, 3 };
quad_indices = G_PushBuffer(gpu_perm, cl, u16, countof(quad_data));
G_CopyCpuToBuffer(cl, quad_indices, 0, quad_data, RNGU64(0, sizeof(quad_data)));
g->quad_indices = G_IdxBuff16(quad_indices);
}
G_CommitCommandList(cl);
/* Barrier all queues until direct queue finishes initializing resources */
G_Sync(G_QueueMask_Direct, G_QueueMask_All);
/* 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 */
G_Sync(G_QueueMask_Direct, G_QueueMask_All);
}
////////////////////////////////////////////////////////////
@ -66,56 +66,56 @@ void G_BootstrapCommon(void)
G_ArenaHandle G_PermArena(void)
{
G_ArenaHandle perm = G_t_perm_arena;
if (G_IsArenaNil(perm))
{
G_t_perm_arena = G_AcquireArena();
perm = G_t_perm_arena;
}
return perm;
G_ArenaHandle perm = G_t_perm_arena;
if (G_IsArenaNil(perm))
{
G_t_perm_arena = G_AcquireArena();
perm = G_t_perm_arena;
}
return perm;
}
//- Cpu -> Gpu upload
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_CopyCpuToBuffer(cl, buffer, 0, src.text, RNGU64(0, src.len));
G_MemorySync(
cl, buffer,
G_Stage_Copy, G_Access_CopyWrite,
G_Stage_All, G_Access_All
);
return buffer;
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_MemorySync(
cl, buffer,
G_Stage_Copy, G_Access_CopyWrite,
G_Stage_All, G_Access_All
);
return buffer;
}
//- Viewport / scissor
Rng3 G_ViewportFromTexture(G_ResourceHandle texture)
{
Vec2I32 dims = G_Count2D(texture);
return RNG3(VEC3(0, 0, 0), VEC3(dims.x, dims.y, 1));
Vec2I32 dims = G_Count2D(texture);
return RNG3(VEC3(0, 0, 0), VEC3(dims.x, dims.y, 1));
}
Rng2 G_ScissorFromTexture(G_ResourceHandle texture)
{
Vec2I32 dims = G_Count2D(texture);
return RNG2(VEC2(0, 0), VEC2(dims.x, dims.y));
Vec2I32 dims = G_Count2D(texture);
return RNG2(VEC2(0, 0), VEC2(dims.x, dims.y));
}
//- Shared resources
G_IndexBufferDesc G_QuadIndices(void)
{
return G_shared_util_state.quad_indices;
return G_shared_util_state.quad_indices;
}
G_SamplerStateRef G_BasicSampler(void)
{
return G_shared_util_state.basic_sampler;
return G_shared_util_state.basic_sampler;
}
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)
{
/* Common shared resources */
G_IndexBufferDesc quad_indices;
G_SamplerStateRef basic_sampler;
G_Texture3DRef basic_noise;
/* Common shared resources */
G_IndexBufferDesc quad_indices;
G_SamplerStateRef basic_sampler;
G_Texture3DRef basic_noise;
} extern G_shared_util_state;
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);
#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

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

View File

@ -3,17 +3,17 @@
Enum(G_RefKind)
{
G_RefKind_StructuredBuffer,
G_RefKind_RWStructuredBuffer,
G_RefKind_ByteAddressBuffer,
G_RefKind_RWByteAddressBuffer,
G_RefKind_Texture1D,
G_RefKind_RWTexture1D,
G_RefKind_Texture2D,
G_RefKind_RWTexture2D,
G_RefKind_Texture3D,
G_RefKind_RWTexture3D,
G_RefKind_SamplerState,
G_RefKind_StructuredBuffer,
G_RefKind_RWStructuredBuffer,
G_RefKind_ByteAddressBuffer,
G_RefKind_RWByteAddressBuffer,
G_RefKind_Texture1D,
G_RefKind_RWTexture1D,
G_RefKind_Texture2D,
G_RefKind_RWTexture2D,
G_RefKind_Texture3D,
G_RefKind_RWTexture3D,
G_RefKind_SamplerState,
};
Struct(G_StructuredBufferRef) { u32 v; };
@ -43,56 +43,56 @@ Struct(G_SamplerStateRef) { u32 v; };
#define G_NumConstants (G_NumGeneralPurposeConstants + G_NumReservedConstants)
#if IsLanguageC
#define G_ForceDeclConstant(type, name, slot) \
Enum(name##__shaderconstantenum) { name = slot }; \
Struct(name##__shaderconstanttype) { type v; }
#define G_DeclConstant(type, name, slot) \
StaticAssert(sizeof(type) <= 4); \
StaticAssert(slot < G_NumGeneralPurposeConstants); \
G_ForceDeclConstant(type, name, slot)
#define G_ForceDeclConstant(type, name, slot) \
Enum(name##__shaderconstantenum) { name = slot }; \
Struct(name##__shaderconstanttype) { type v; }
#define G_DeclConstant(type, name, slot) \
StaticAssert(sizeof(type) <= 4); \
StaticAssert(slot < G_NumGeneralPurposeConstants); \
G_ForceDeclConstant(type, name, slot)
#elif IsLanguageG
#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_ForceDeclConstant(type, name, slot) cbuffer name : register(b##slot) { type name; }
#define G_DeclConstant(type, name, slot) G_ForceDeclConstant(type, name, slot)
#endif
////////////////////////////////////////////////////////////
//~ Resource dereference
#if IsLanguageG
/* TODO: Non-uniform resource access currently is assumed as the default
* behavior. We may want to add explicit "uniform" variants for
* optimization on amd in the future. */
/* TODO: Non-uniform resource access currently is assumed as the default
* behavior. We may want to add explicit "uniform" variants for
* optimization on amd in the future. */
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> 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)]; }
ByteAddressBuffer G_Dereference(G_ByteAddressBufferRef r) { return ResourceDescriptorHeap[NonUniformResourceIndex(r.v)]; }
RWByteAddressBuffer G_Dereference(G_RWByteAddressBufferRef 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)]; }
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> 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> 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> 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> 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> 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)]; }
SamplerState G_Dereference(G_SamplerStateRef r) { return SamplerDescriptorHeap[NonUniformResourceIndex(r.v)]; }
SamplerState G_Dereference(G_SamplerStateRef r) { return SamplerDescriptorHeap[NonUniformResourceIndex(r.v)]; }
#endif
////////////////////////////////////////////////////////////
//~ Size helpers
#if IsLanguageG
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; }
u32 countof(ByteAddressBuffer 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; }
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; }
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; }
template<typename T> Vec3U32 countof(RWTexture3D<T> tex) { Vec3U32 result; tex.GetDimensions(result.x, result.y, result.z); 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; }
u32 countof(ByteAddressBuffer 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; }
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; }
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; }
template<typename T> Vec3U32 countof(RWTexture3D<T> tex) { Vec3U32 result; tex.GetDimensions(result.x, result.y, result.z); return result; }
#endif
////////////////////////////////////////////////////////////
@ -111,196 +111,196 @@ G_ForceDeclConstant(G_RWByteAddressBufferRef, G_ShaderConst_PrintBufferRef, 8)
Enum(G_FmtArgKind)
{
G_FmtArgKind_None,
G_FmtArgKind_End,
G_FmtArgKind_None,
G_FmtArgKind_End,
G_FmtArgKind_BEGINSIZE1,
G_FmtArgKind_BEGINSIZE1,
G_FmtArgKind_Uint,
G_FmtArgKind_Sint,
G_FmtArgKind_Float,
G_FmtArgKind_Uint,
G_FmtArgKind_Sint,
G_FmtArgKind_Float,
G_FmtArgKind_BEGINSIZE2,
G_FmtArgKind_BEGINSIZE2,
G_FmtArgKind_Uint2,
G_FmtArgKind_Sint2,
G_FmtArgKind_Float2,
G_FmtArgKind_Uint2,
G_FmtArgKind_Sint2,
G_FmtArgKind_Float2,
G_FmtArgKind_BEGINSIZE3,
G_FmtArgKind_BEGINSIZE3,
G_FmtArgKind_Uint3,
G_FmtArgKind_Sint3,
G_FmtArgKind_Float3,
G_FmtArgKind_Uint3,
G_FmtArgKind_Sint3,
G_FmtArgKind_Float3,
G_FmtArgKind_BEGINSIZE4,
G_FmtArgKind_BEGINSIZE4,
G_FmtArgKind_Uint4,
G_FmtArgKind_Sint4,
G_FmtArgKind_Float4,
G_FmtArgKind_Uint4,
G_FmtArgKind_Sint4,
G_FmtArgKind_Float4,
};
Struct(G_FmtArg)
{
G_FmtArgKind kind;
Vec4U32 v;
G_FmtArgKind kind;
Vec4U32 v;
};
#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(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(Vec4U32 v) { G_FmtArg result; result.kind = G_FmtArgKind_Uint4; result.v.xyzw = v.xyzw; 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(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(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(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(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(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(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(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(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(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_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_chunks[64];
u32 bytes_count;
u32 chars_count;
u32 args_count;
b32 overflowed;
};
void G_PushPrintByte(inout G_TempPrintBuffer buff, u32 v)
u32 byte_idx_in_chunk = buff.bytes_count & 0x03;
if (byte_idx_in_chunk == 0)
{
/* Since buff is not zero initialized, we set the chunk on first write here */
buff.byte_chunks[chunk_idx] = v & 0xFF;
}
else
{
buff.byte_chunks[chunk_idx] |= (v & 0xFF) << (byte_idx_in_chunk * 8);
}
buff.bytes_count += 1;
}
else
{
u32 chunk_idx = buff.bytes_count / 4;
if (chunk_idx < countof(buff.byte_chunks))
{
u32 byte_idx_in_chunk = buff.bytes_count & 0x03;
if (byte_idx_in_chunk == 0)
{
/* Since buff is not zero initialized, we set the chunk on first write here */
buff.byte_chunks[chunk_idx] = v & 0xFF;
}
else
{
buff.byte_chunks[chunk_idx] |= (v & 0xFF) << (byte_idx_in_chunk * 8);
}
buff.bytes_count += 1;
}
else
{
buff.overflowed = 1;
}
buff.overflowed = 1;
}
}
void G_CommitPrint(G_TempPrintBuffer buff)
{
RWByteAddressBuffer rw = G_Dereference(G_ShaderConst_PrintBufferRef);
if (buff.overflowed)
{
buff.bytes_count = 0;
buff.chars_count = 0;
buff.args_count = 0;
}
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)
{
buff.bytes_count = 0;
buff.chars_count = 0;
buff.args_count = 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;
}
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))
{
/* 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);
}
/* 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);
}
}
#define G_PrintF_(fmt, ...) do { \
G_TempPrintBuffer __tmp; \
__tmp.bytes_count = 0; \
__tmp.overflowed = 0; \
u32 __char_idx = 0; \
while (U32FromChar(fmt[__char_idx]) != 0) \
{ \
G_PushPrintByte(__tmp, U32FromChar(fmt[__char_idx])); \
++__char_idx; \
} \
G_FmtArg __args[] = { __VA_ARGS__ }; \
__tmp.chars_count = __char_idx; \
__tmp.args_count = (countof(__args) - 1); \
for (u32 __arg_idx = 0; __arg_idx < __tmp.args_count; ++__arg_idx) \
{ \
G_FmtArg __arg = __args[__arg_idx]; \
G_PushPrintByte(__tmp, __arg.kind); \
if (__arg.kind > G_FmtArgKind_BEGINSIZE1) \
{ \
G_PushPrintByte(__tmp, __arg.v.x >> 0); \
G_PushPrintByte(__tmp, __arg.v.x >> 8); \
G_PushPrintByte(__tmp, __arg.v.x >> 16); \
G_PushPrintByte(__tmp, __arg.v.x >> 24); \
} \
if (__arg.kind > G_FmtArgKind_BEGINSIZE2) \
{ \
G_PushPrintByte(__tmp, __arg.v.y >> 0); \
G_PushPrintByte(__tmp, __arg.v.y >> 8); \
G_PushPrintByte(__tmp, __arg.v.y >> 16); \
G_PushPrintByte(__tmp, __arg.v.y >> 24); \
} \
if (__arg.kind > G_FmtArgKind_BEGINSIZE3) \
{ \
G_PushPrintByte(__tmp, __arg.v.z >> 0); \
G_PushPrintByte(__tmp, __arg.v.z >> 8); \
G_PushPrintByte(__tmp, __arg.v.z >> 16); \
G_PushPrintByte(__tmp, __arg.v.z >> 24); \
} \
if (__arg.kind > G_FmtArgKind_BEGINSIZE4) \
{ \
G_PushPrintByte(__tmp, __arg.v.w >> 0); \
G_PushPrintByte(__tmp, __arg.v.w >> 8); \
G_PushPrintByte(__tmp, __arg.v.w >> 16); \
G_PushPrintByte(__tmp, __arg.v.w >> 24); \
} \
} \
G_CommitPrint(__tmp); \
} while (0)
#define G_PrintF_(fmt, ...) do { \
G_TempPrintBuffer __tmp; \
__tmp.bytes_count = 0; \
__tmp.overflowed = 0; \
u32 __char_idx = 0; \
while (U32FromChar(fmt[__char_idx]) != 0) \
{ \
G_PushPrintByte(__tmp, U32FromChar(fmt[__char_idx])); \
++__char_idx; \
} \
G_FmtArg __args[] = { __VA_ARGS__ }; \
__tmp.chars_count = __char_idx; \
__tmp.args_count = (countof(__args) - 1); \
for (u32 __arg_idx = 0; __arg_idx < __tmp.args_count; ++__arg_idx) \
{ \
G_FmtArg __arg = __args[__arg_idx]; \
G_PushPrintByte(__tmp, __arg.kind); \
if (__arg.kind > G_FmtArgKind_BEGINSIZE1) \
{ \
G_PushPrintByte(__tmp, __arg.v.x >> 0); \
G_PushPrintByte(__tmp, __arg.v.x >> 8); \
G_PushPrintByte(__tmp, __arg.v.x >> 16); \
G_PushPrintByte(__tmp, __arg.v.x >> 24); \
} \
if (__arg.kind > G_FmtArgKind_BEGINSIZE2) \
{ \
G_PushPrintByte(__tmp, __arg.v.y >> 0); \
G_PushPrintByte(__tmp, __arg.v.y >> 8); \
G_PushPrintByte(__tmp, __arg.v.y >> 16); \
G_PushPrintByte(__tmp, __arg.v.y >> 24); \
} \
if (__arg.kind > G_FmtArgKind_BEGINSIZE3) \
{ \
G_PushPrintByte(__tmp, __arg.v.z >> 0); \
G_PushPrintByte(__tmp, __arg.v.z >> 8); \
G_PushPrintByte(__tmp, __arg.v.z >> 16); \
G_PushPrintByte(__tmp, __arg.v.z >> 24); \
} \
if (__arg.kind > G_FmtArgKind_BEGINSIZE4) \
{ \
G_PushPrintByte(__tmp, __arg.v.w >> 0); \
G_PushPrintByte(__tmp, __arg.v.w >> 8); \
G_PushPrintByte(__tmp, __arg.v.w >> 16); \
G_PushPrintByte(__tmp, __arg.v.w >> 24); \
} \
} \
G_CommitPrint(__tmp); \
} 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
#define G_PrintF(fmt)
#define G_PrintF(fmt)
#endif

File diff suppressed because it is too large Load Diff

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -3,82 +3,82 @@
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 result = OS_GetFullPath(arena, path);
for (u64 i = 0; i < result.len; ++i)
String result = OS_GetFullPath(arena, path);
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 result = path;
u64 start = path.len;
for (u64 i = path.len; i-- > 0;)
String result = path;
u64 start = path.len;
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)
{
result.text = &path.text[start];
result.len = path.len - start;
}
if (start < path.len)
{
result.text = &path.text[start];
result.len = path.len - start;
}
return result;
}
return result;
}
String F_GetParentDir(String path)
{
String result = Zi;
result.text = path.text;
u64 end = path.len;
for (u64 i = path.len; i-- > 0;)
String result = Zi;
result.text = path.text;
u64 end = path.len;
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)
{
result.len = end;
}
return result;
}
if (end < path.len)
{
result.len = end;
}
return result;
}
String F_ExtensionFromFile(String path)
{
String result = Zi;
u64 start = path.len;
for (u64 i = path.len; i-- > 0;)
String result = Zi;
u64 start = path.len;
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)
{
result.text = &path.text[start];
result.len = path.len - start;
}
if (start < path.len)
{
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 result = Zi;
OS_File file = OS_OpenFile(path, OS_FileFlag_Read, I64Max);
result = OS_ReadEntireFile(arena, file);
OS_CloseFile(file);
return result;
String result = Zi;
OS_File file = OS_OpenFile(path, OS_FileFlag_Read, I64Max);
result = OS_ReadEntireFile(arena, file);
OS_CloseFile(file);
return result;
}
////////////////////////////////////////////////////////////
@ -98,9 +98,9 @@ String F_DataFromFile(Arena *arena, String path)
void F_ClearWrite(String path, String data)
{
OS_File file = OS_OpenFile(path, OS_FileFlag_Write | OS_FileFlag_Create, I64Max);
OS_ClearWriteFile(file, data);
OS_CloseFile(file);
OS_File file = OS_OpenFile(path, OS_FileFlag_Write | OS_FileFlag_Create, I64Max);
OS_ClearWriteFile(file, data);
OS_CloseFile(file);
}
////////////////////////////////////////////////////////////
@ -108,12 +108,12 @@ void F_ClearWrite(String path, String data)
b32 F_IsFile(String path)
{
return OS_FileExists(path);
return OS_FileExists(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)
{
TempArena scratch = BeginScratch(arena);
StringList tmp = Zi;
String dir_full_path = F_GetFull(scratch.arena, dir);
OS_DirContentsFromFullPath(scratch.arena, &tmp, dir_full_path);
for (StringListNode *n = tmp.first; n; n = n->next)
TempArena scratch = BeginScratch(arena);
StringList tmp = Zi;
String dir_full_path = F_GetFull(scratch.arena, dir);
OS_DirContentsFromFullPath(scratch.arena, &tmp, dir_full_path);
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));
PushStringToList(arena, list, file_joined_path);
if (flags & F_IterFlag_Recurse && F_IsDir(file_joined_path))
{
F_FilesFromDir(arena, list, file_joined_path, flags);
}
F_FilesFromDir(arena, list, file_joined_path, flags);
}
EndScratch(scratch);
}
EndScratch(scratch);
}

View File

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

View File

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

View File

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

View File

@ -3,27 +3,27 @@
String W32_StringFromError(Arena *arena, DWORD err)
{
String result = Zi;
char *msg_cstr = 0;
i64 len = FormatMessageA(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
0,
err,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPSTR)&msg_cstr,
0,
0
);
if (len > 0)
{
result = PushString(arena, TrimWhitespace(StringFromCstr(msg_cstr, len)));
LocalFree(msg_cstr);
}
else
{
result = StringF(arena, "Unknown win32 error - %F", FmtHex(err));
}
return result;
String result = Zi;
char *msg_cstr = 0;
i64 len = FormatMessageA(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
0,
err,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPSTR)&msg_cstr,
0,
0
);
if (len > 0)
{
result = PushString(arena, TrimWhitespace(StringFromCstr(msg_cstr, len)));
LocalFree(msg_cstr);
}
else
{
result = StringF(arena, "Unknown win32 error - %F", FmtHex(err));
}
return result;
}
////////////////////////////////////////////////////////////
@ -38,117 +38,117 @@ void OS_Bootstrap(void)
OS_File OS_OpenFile(String path, OS_FileFlag flags, i64 timeout_ns)
{
TempArena scratch = BeginScratchNoConflict();
OS_File result = Zi;
wchar_t *path_wstr = WstrFromString(scratch.arena, path);
u32 share_mode = FILE_SHARE_READ;
u32 create_mode = OPEN_EXISTING;
u32 access_flags = 0;
if (flags & OS_FileFlag_Read) access_flags |= GENERIC_READ;
if (flags & OS_FileFlag_Write) access_flags |= GENERIC_WRITE;
if (flags & OS_FileFlag_Create) create_mode = OPEN_ALWAYS;
i32 timeout_ms = timeout_ns / 1000000;
i32 elapsed_ms = 0;
i32 delay_ms = 1;
HANDLE handle = INVALID_HANDLE_VALUE;
for (;;)
TempArena scratch = BeginScratchNoConflict();
OS_File result = Zi;
wchar_t *path_wstr = WstrFromString(scratch.arena, path);
u32 share_mode = FILE_SHARE_READ;
u32 create_mode = OPEN_EXISTING;
u32 access_flags = 0;
if (flags & OS_FileFlag_Read) access_flags |= GENERIC_READ;
if (flags & OS_FileFlag_Write) access_flags |= GENERIC_WRITE;
if (flags & OS_FileFlag_Create) create_mode = OPEN_ALWAYS;
i32 timeout_ms = timeout_ns / 1000000;
i32 elapsed_ms = 0;
i32 delay_ms = 1;
HANDLE handle = INVALID_HANDLE_VALUE;
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);
if (handle == INVALID_HANDLE_VALUE && elapsed_ms < timeout_ms && GetLastError() == ERROR_SHARING_VIOLATION)
{
Sleep(delay_ms);
elapsed_ms += delay_ms;
delay_ms = MinI32(delay_ms * 2, 1024);
}
else
{
break;
}
Sleep(delay_ms);
elapsed_ms += delay_ms;
delay_ms = MinI32(delay_ms * 2, 1024);
}
EndScratch(scratch);
result.handle = (u64)handle;
return result;
else
{
break;
}
}
EndScratch(scratch);
result.handle = (u64)handle;
return result;
}
void OS_CloseFile(OS_File file)
{
HANDLE handle = (HANDLE)file.handle;
CloseHandle(handle);
HANDLE handle = (HANDLE)file.handle;
CloseHandle(handle);
}
String OS_ReadEntireFile(Arena *arena, OS_File file)
{
String result = Zi;
HANDLE handle = (HANDLE)file.handle;
u32 chunk_size = Kibi(64);
result.text = ArenaNext(arena, u8);
for (;;)
String result = Zi;
HANDLE handle = (HANDLE)file.handle;
u32 chunk_size = Kibi(64);
result.text = ArenaNext(arena, u8);
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);
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)
{
PopStructsNoCopy(arena, u8, chunk_size - chunk_bytes_read);
break;
}
PopStructsNoCopy(arena, u8, chunk_size - chunk_bytes_read);
break;
}
return result;
}
return result;
}
void OS_ClearWriteFile(OS_File file, String data)
{
HANDLE handle = (HANDLE)file.handle;
SetFilePointer(handle, 0, 0, FILE_BEGIN);
SetEndOfFile(handle);
WriteFile(handle, data.text, data.len, 0, 0);
HANDLE handle = (HANDLE)file.handle;
SetFilePointer(handle, 0, 0, FILE_BEGIN);
SetEndOfFile(handle);
WriteFile(handle, data.text, data.len, 0, 0);
}
void OS_DirContentsFromFullPath(Arena *arena, StringList *list, String path)
{
TempArena scratch = BeginScratch(arena);
WIN32_FIND_DATAW find_data = Zi;
String filter = StringF(scratch.arena, "%F\\*", FmtString(path));
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);
b32 found = find_handle && find_handle != INVALID_HANDLE_VALUE;
while (found)
TempArena scratch = BeginScratch(arena);
WIN32_FIND_DATAW find_data = Zi;
String filter = StringF(scratch.arena, "%F\\*", FmtString(path));
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);
b32 found = find_handle && find_handle != INVALID_HANDLE_VALUE;
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);
if (!MatchString(file_name, Lit(".")) && !MatchString(file_name, Lit("..")))
{
PushStringToList(arena, list, file_name);
}
found = FindNextFileW(find_handle, &find_data);
PushStringToList(arena, list, file_name);
}
EndScratch(scratch);
found = FindNextFileW(find_handle, &find_data);
}
EndScratch(scratch);
}
String OS_GetFullPath(Arena *arena, String path)
{
TempArena scratch = BeginScratch(arena);
wchar_t *rel_path_wstr = WstrFromString(scratch.arena, path);
wchar_t full_path_wstr_buff[4096];
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));
EndScratch(scratch);
return res;
TempArena scratch = BeginScratch(arena);
wchar_t *rel_path_wstr = WstrFromString(scratch.arena, path);
wchar_t full_path_wstr_buff[4096];
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));
EndScratch(scratch);
return res;
}
u64 OS_LastWriteTimestampFromPath(String path)
{
TempArena scratch = BeginScratchNoConflict();
u64 result = 0;
WIN32_FILE_ATTRIBUTE_DATA a = Zi;
wchar_t *path_wstr = WstrFromString(scratch.arena, path);
if (GetFileAttributesExW(path_wstr, GetFileExInfoStandard, &a))
{
result = ((ULONGLONG)a.ftLastWriteTime.dwHighDateTime << 32) |
(ULONGLONG)a.ftLastWriteTime.dwLowDateTime;
}
EndScratch(scratch);
return result;
TempArena scratch = BeginScratchNoConflict();
u64 result = 0;
WIN32_FILE_ATTRIBUTE_DATA a = Zi;
wchar_t *path_wstr = WstrFromString(scratch.arena, path);
if (GetFileAttributesExW(path_wstr, GetFileExInfoStandard, &a))
{
result = ((ULONGLONG)a.ftLastWriteTime.dwHighDateTime << 32) |
(ULONGLONG)a.ftLastWriteTime.dwLowDateTime;
}
EndScratch(scratch);
return result;
}
////////////////////////////////////////////////////////////
@ -156,45 +156,45 @@ u64 OS_LastWriteTimestampFromPath(String path)
b32 OS_FileOrDirExists(String path)
{
TempArena scratch = BeginScratchNoConflict();
wchar_t *path_wstr = WstrFromString(scratch.arena, path);
DWORD attributes = GetFileAttributesW(path_wstr);
EndScratch(scratch);
return attributes != INVALID_FILE_ATTRIBUTES;
TempArena scratch = BeginScratchNoConflict();
wchar_t *path_wstr = WstrFromString(scratch.arena, path);
DWORD attributes = GetFileAttributesW(path_wstr);
EndScratch(scratch);
return attributes != INVALID_FILE_ATTRIBUTES;
}
b32 OS_FileExists(String path)
{
TempArena scratch = BeginScratchNoConflict();
wchar_t *path_wstr = WstrFromString(scratch.arena, path);
DWORD attributes = GetFileAttributesW(path_wstr);
EndScratch(scratch);
return attributes != INVALID_FILE_ATTRIBUTES && !(attributes & FILE_ATTRIBUTE_DIRECTORY);
TempArena scratch = BeginScratchNoConflict();
wchar_t *path_wstr = WstrFromString(scratch.arena, path);
DWORD attributes = GetFileAttributesW(path_wstr);
EndScratch(scratch);
return attributes != INVALID_FILE_ATTRIBUTES && !(attributes & FILE_ATTRIBUTE_DIRECTORY);
}
b32 OS_DirExists(String path)
{
TempArena scratch = BeginScratchNoConflict();
wchar_t *path_wstr = WstrFromString(scratch.arena, path);
DWORD attributes = GetFileAttributesW(path_wstr);
EndScratch(scratch);
return attributes != INVALID_FILE_ATTRIBUTES && (attributes & FILE_ATTRIBUTE_DIRECTORY);
TempArena scratch = BeginScratchNoConflict();
wchar_t *path_wstr = WstrFromString(scratch.arena, path);
DWORD attributes = GetFileAttributesW(path_wstr);
EndScratch(scratch);
return attributes != INVALID_FILE_ATTRIBUTES && (attributes & FILE_ATTRIBUTE_DIRECTORY);
}
void OS_Mkdir(String path)
{
TempArena scratch = BeginScratchNoConflict();
wchar_t *path_wstr = WstrFromString(scratch.arena, path);
CreateDirectoryW(path_wstr, 0);
EndScratch(scratch);
TempArena scratch = BeginScratchNoConflict();
wchar_t *path_wstr = WstrFromString(scratch.arena, path);
CreateDirectoryW(path_wstr, 0);
EndScratch(scratch);
}
void OS_Rm(String path)
{
TempArena scratch = BeginScratchNoConflict();
wchar_t *path_wstr = WstrFromString(scratch.arena, path);
DeleteFile(path_wstr);
EndScratch(scratch);
TempArena scratch = BeginScratchNoConflict();
wchar_t *path_wstr = WstrFromString(scratch.arena, path);
DeleteFile(path_wstr);
EndScratch(scratch);
}
////////////////////////////////////////////////////////////
@ -202,150 +202,150 @@ void OS_Rm(String path)
OS_CommandResult OS_RunCommand(Arena *arena, String cmd)
{
TempArena scratch = BeginScratch(arena);
OS_CommandResult result = Zi;
b32 ok = 1;
TempArena scratch = BeginScratch(arena);
OS_CommandResult result = Zi;
b32 ok = 1;
wchar_t *cmd_wstr = WstrFromString(scratch.arena, cmd);
wchar_t *cmd_wstr = WstrFromString(scratch.arena, cmd);
SECURITY_ATTRIBUTES sa = Zi;
sa.nLength = sizeof(sa);
sa.bInheritHandle = 0;
SECURITY_ATTRIBUTES sa = Zi;
sa.nLength = sizeof(sa);
sa.bInheritHandle = 0;
/* Create pipe */
HANDLE pipe_read = 0;
HANDLE pipe_write = 0;
/* Create pipe */
HANDLE pipe_read = 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)
{
ok = CreatePipe(&pipe_read, &pipe_write, &sa, 0) != 0;
if (!ok)
{
result.output = Lit("Failed to create pipe");
pipe_read = 0;
pipe_write = 0;
}
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");
}
}
/* Duplicate pipe for child process */
HANDLE child_pipe_write = 0;
/* 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;
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)
{
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;
}
process = pi.hProcess;
process_thread = pi.hThread;
}
/* Initialize attrs list */
LPPROC_THREAD_ATTRIBUTE_LIST attrs = Zi;
if (ok)
else
{
u64 attrs_size = 0;
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");
}
result.output = W32_StringFromError(arena, GetLastError());
}
/* 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)
/* Close write pipe handles */
{
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)
CloseHandle(child_pipe_write);
CloseHandle(pipe_write);
child_pipe_write = 0;
pipe_write = 0;
}
}
/* Read process output */
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;
process_thread = pi.hThread;
GetExitCodeProcess(process, &exit_code);
exit_code_valid = 1;
}
else
{
result.output = W32_StringFromError(arena, GetLastError());
}
/* Close write pipe handles */
{
CloseHandle(child_pipe_write);
CloseHandle(pipe_write);
child_pipe_write = 0;
pipe_write = 0;
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;
}
/* Read process output */
if (ok)
if (exit_code_valid)
{
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)
{
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;
}
result.code = exit_code;
}
}
/* Close handles */
if (attrs) DeleteProcThreadAttributeList(attrs);
if (process_thread) CloseHandle(process_thread);
if (process) CloseHandle(process);
if (child_pipe_write) CloseHandle(child_pipe_write);
if (pipe_read) CloseHandle(pipe_read);
if (pipe_write) CloseHandle(pipe_write);
/* Close handles */
if (attrs) DeleteProcThreadAttributeList(attrs);
if (process_thread) CloseHandle(process_thread);
if (process) CloseHandle(process);
if (child_pipe_write) CloseHandle(child_pipe_write);
if (pipe_read) CloseHandle(pipe_read);
if (pipe_write) CloseHandle(pipe_write);
if (!ok && result.code == 0)
{
result.code = -1;
}
if (!ok && result.code == 0)
{
result.code = -1;
}
EndScratch(scratch);
return result;
EndScratch(scratch);
return result;
}

View File

@ -21,10 +21,10 @@ MIX_SharedState M_shared_state = ZI;
void MIX_Bootstrap(void)
{
MIX_SharedState *g = &M_shared_state;
g->track_arena = AcquireArena(Gibi(64));
g->listener_pos = VEC2(0, 0);
g->listener_dir = VEC2(0, -1);
MIX_SharedState *g = &M_shared_state;
g->track_arena = AcquireArena(Gibi(64));
g->listener_pos = VEC2(0, 0);
g->listener_dir = VEC2(0, -1);
}
////////////////////////////////////////////////////////////
@ -32,187 +32,187 @@ void MIX_Bootstrap(void)
MIX_Handle MIX_HandleFromTrack(MIX_Track *track)
{
MIX_Handle result = ZI;
result.gen = track->gen;
result.data = track;
return result;
MIX_Handle result = ZI;
result.gen = track->gen;
result.data = track;
return result;
}
MIX_Track *MIX_TrackFromHandle(MIX_Handle handle)
{
MIX_Track *track = (MIX_Track *)handle.data;
if (track && track->gen == handle.gen)
{
return track;
}
else
{
return 0;
}
MIX_Track *track = (MIX_Track *)handle.data;
if (track && track->gen == handle.gen)
{
return track;
}
else
{
return 0;
}
}
MIX_Track *MIX_AcquireTrackLocked(Lock *lock, SND_Sound *sound)
{
MIX_SharedState *g = &M_shared_state;
AssertLockedE(lock, &g->mutex);
MIX_SharedState *g = &M_shared_state;
AssertLockedE(lock, &g->mutex);
MIX_Track *track = 0;
if (g->track_first_free)
MIX_Track *track = 0;
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 */
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;
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->sound = sound;
track->mix.source = sound;
track->mix.track_handle = MIX_HandleFromTrack(track);
track->sound = sound;
track->mix.source = sound;
track->mix.track_handle = MIX_HandleFromTrack(track);
/* Append to playing list */
MIX_Track *prev = g->track_last_playing;
if (prev)
{
prev->next = track;
}
else
{
g->track_first_playing = track;
}
g->track_last_playing = track;
track->prev = prev;
++g->track_playing_count;
/* Append to playing list */
MIX_Track *prev = g->track_last_playing;
if (prev)
{
prev->next = track;
}
else
{
g->track_first_playing = track;
}
g->track_last_playing = track;
track->prev = prev;
++g->track_playing_count;
return track;
return track;
}
void MIX_ReleaseTrackLocked(Lock *lock, MIX_Track *track)
{
MIX_SharedState *g = &M_shared_state;
AssertLockedE(lock, &g->mutex);
MIX_SharedState *g = &M_shared_state;
AssertLockedE(lock, &g->mutex);
/* Remove from playing list */
MIX_Track *prev = track->prev;
MIX_Track *next = track->next;
if (prev)
{
prev->next = next;
}
else
{
/* Track was first in list */
g->track_first_playing = next;
}
if (next)
{
next->prev = prev;
}
else
{
/* Track was last in list */
g->track_last_playing = prev;
}
--g->track_playing_count;
++track->gen;
/* Remove from playing list */
MIX_Track *prev = track->prev;
MIX_Track *next = track->next;
if (prev)
{
prev->next = next;
}
else
{
/* Track was first in list */
g->track_first_playing = next;
}
if (next)
{
next->prev = prev;
}
else
{
/* Track was last in list */
g->track_last_playing = prev;
}
--g->track_playing_count;
++track->gen;
/* Add to free list */
track->prev = 0;
track->next = g->track_first_free;
if (g->track_first_free)
{
g->track_first_free->prev = track;
}
g->track_first_free = track;
/* Add to free list */
track->prev = 0;
track->next = g->track_first_free;
if (g->track_first_free)
{
g->track_first_free->prev = track;
}
g->track_first_free = track;
}
/* TODO: Rework interface to be command based instead of directly modifying tracks. */
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_SharedState *g = &M_shared_state;
MIX_Track *track;
MIX_SharedState *g = &M_shared_state;
MIX_Track *track;
{
Lock lock = LockE(&g->mutex);
{
Lock lock = LockE(&g->mutex);
{
track = MIX_AcquireTrackLocked(&lock, sound);
track->desc = desc;
}
Unlock(&lock);
track = MIX_AcquireTrackLocked(&lock, sound);
track->desc = desc;
}
return MIX_HandleFromTrack(track);
Unlock(&lock);
}
return MIX_HandleFromTrack(track);
}
/* NOTE: This is quite inefficient. */
MIX_TrackDesc MIX_TrackDescFromHandle(MIX_Handle handle)
{
MIX_SharedState *g = &M_shared_state;
MIX_TrackDesc result = ZI;
MIX_SharedState *g = &M_shared_state;
MIX_TrackDesc result = ZI;
MIX_Track *track = MIX_TrackFromHandle(handle);
if (track)
MIX_Track *track = MIX_TrackFromHandle(handle);
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 */
Lock lock = LockE(&g->mutex);
{
/* Confirm handle is still valid now that we're locked */
track = MIX_TrackFromHandle(handle);
if (track)
{
result = track->desc;
}
}
Unlock(&lock);
/* Confirm handle is still valid now that we're locked */
track = MIX_TrackFromHandle(handle);
if (track)
{
result = track->desc;
}
}
Unlock(&lock);
}
return result;
return result;
}
/* NOTE: This is quite inefficient. */
void MIX_UpdateTrack(MIX_Handle handle, MIX_TrackDesc desc)
{
MIX_SharedState *g = &M_shared_state;
MIX_Track *track = MIX_TrackFromHandle(handle);
if (track)
MIX_SharedState *g = &M_shared_state;
MIX_Track *track = MIX_TrackFromHandle(handle);
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 */
Lock lock = LockE(&g->mutex);
{
/* Confirm handle is still valid now that we're locked */
track = MIX_TrackFromHandle(handle);
if (track)
{
track->desc = desc;
}
}
Unlock(&lock);
/* Confirm handle is still valid now that we're locked */
track = MIX_TrackFromHandle(handle);
if (track)
{
track->desc = desc;
}
}
Unlock(&lock);
}
}
void MIX_UpdateListener(Vec2 pos, Vec2 dir)
{
MIX_SharedState *g = &M_shared_state;
Lock lock = LockE(&g->mutex);
{
g->listener_pos = pos;
g->listener_dir = NormVec2(dir);
}
Unlock(&lock);
MIX_SharedState *g = &M_shared_state;
Lock lock = LockE(&g->mutex);
{
g->listener_pos = pos;
g->listener_dir = NormVec2(dir);
}
Unlock(&lock);
}
////////////////////////////////////////////////////////////
@ -220,250 +220,250 @@ void MIX_UpdateListener(Vec2 pos, Vec2 dir)
i16 MIX_SampleSound(SND_Sound *sound, u64 sample_pos, b32 wrap)
{
if (wrap)
{
return sound->samples[sample_pos % sound->samples_count];
}
else if (sample_pos < sound->samples_count)
{
return sound->samples[sample_pos];
}
else
{
return 0;
}
if (wrap)
{
return sound->samples[sample_pos % sound->samples_count];
}
else if (sample_pos < sound->samples_count)
{
return sound->samples[sample_pos];
}
else
{
return 0;
}
}
/* To be called once per audio playback interval */
MIX_PcmF32 MIX_MixAllTracks(Arena *arena, u64 frame_count)
{
TempArena scratch = BeginScratch(arena);
MIX_SharedState *g = &M_shared_state;
TempArena scratch = BeginScratch(arena);
MIX_SharedState *g = &M_shared_state;
MIX_PcmF32 result = ZI;
result.count = frame_count * 2;
result.samples = PushStructs(arena, f32, result.count);
MIX_PcmF32 result = ZI;
result.count = frame_count * 2;
result.samples = PushStructs(arena, f32, result.count);
Vec2 listener_pos = VEC2(0, 0);
Vec2 listener_dir = VEC2(0, 0);
Vec2 listener_pos = VEC2(0, 0);
Vec2 listener_dir = VEC2(0, 0);
//- Create temp mix array
//- Create temp mix array
MIX_MixData **mixes = 0;
u64 mixes_count = 0;
MIX_MixData **mixes = 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);
/* 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)
{
MIX_MixData *mix = &track->mix;
mix->desc = track->desc;
mixes[mixes_count++] = mix;
}
Unlock(&lock);
MIX_MixData *mix = &track->mix;
mix->desc = track->desc;
mixes[mixes_count++] = mix;
}
//- 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];
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;
}
/* Skip empty sounds */
continue;
}
//- 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);
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);
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);
}
EndScratch(scratch);
return result;
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
{
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)
{
MIX_TrackFlag_None = 0,
MIX_TrackFlag_Spatialize = (1 << 0)
MIX_TrackFlag_None = 0,
MIX_TrackFlag_Spatialize = (1 << 0)
};
Struct(MIX_Handle)
{
u64 gen;
void *data;
u64 gen;
void *data;
};
Struct(MIX_TrackDesc)
{
MIX_TrackFlag flags;
f32 volume; /* 0 -> 1.0+ */
f32 speed; /* 0 -> 1.0+ */
b32 looping;
MIX_TrackFlag flags;
f32 volume; /* 0 -> 1.0+ */
f32 speed; /* 0 -> 1.0+ */
b32 looping;
/* MIX_TrackFlag_Spatialize */
Vec2 pos;
/* MIX_TrackFlag_Spatialize */
Vec2 pos;
};
#define M_TRACKDESC(...) ((MIX_TrackDesc) { \
.flags = 0, \
.volume = 1.0, \
.speed = 1.0, \
.looping = 0, \
.pos = VEC2(0, 0), \
__VA_ARGS__ \
.flags = 0, \
.volume = 1.0, \
.speed = 1.0, \
.looping = 0, \
.pos = VEC2(0, 0), \
__VA_ARGS__ \
})
////////////////////////////////////////////////////////////
@ -38,40 +38,40 @@ Struct(MIX_TrackDesc)
/* Stereo mix of 32 bit float samples */
Struct(MIX_PcmF32)
{
u64 count;
f32 *samples;
u64 count;
f32 *samples;
};
Struct(MIX_EffectData)
{
/* Spatialization */
f32 spatial_volume;
f32 spatial_pan;
/* Spatialization */
f32 spatial_volume;
f32 spatial_pan;
};
Struct(MIX_MixData)
{
MIX_Handle track_handle;
b32 track_finished;
MIX_Handle track_handle;
b32 track_finished;
MIX_TrackDesc desc;
MIX_EffectData effect_data;
SND_Sound *source;
u64 source_pos;
MIX_TrackDesc desc;
MIX_EffectData effect_data;
SND_Sound *source;
u64 source_pos;
};
Struct(MIX_Track){
u64 gen;
u64 gen;
/* Controlled via interface */
SND_Sound *sound;
MIX_TrackDesc desc;
/* Controlled via interface */
SND_Sound *sound;
MIX_TrackDesc desc;
/* Internal */
MIX_MixData mix;
/* Internal */
MIX_MixData mix;
MIX_Track *next;
MIX_Track *prev;
MIX_Track *next;
MIX_Track *prev;
};
////////////////////////////////////////////////////////////
@ -79,18 +79,18 @@ Struct(MIX_Track){
Struct(MIX_SharedState)
{
Mutex mutex;
Mutex mutex;
/* Listener */
Vec2 listener_pos;
Vec2 listener_dir;
/* Listener */
Vec2 listener_pos;
Vec2 listener_dir;
/* Track list */
Arena *track_arena;
MIX_Track *track_first_playing;
MIX_Track *track_last_playing;
u64 track_playing_count;
MIX_Track *track_first_free;
/* Track list */
Arena *track_arena;
MIX_Track *track_first_playing;
MIX_Track *track_last_playing;
u64 track_playing_count;
MIX_Track *track_first_free;
} extern M_shared_state;
////////////////////////////////////////////////////////////

View File

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

View File

@ -3,114 +3,114 @@
MP3_Result MP3_Decode(Arena *arena, String encoded, u32 sample_rate, MP3_DecodeFlag flags)
{
MP3_Result result = ZI;
u64 bytes_per_sample = 2;
MP3_Result result = ZI;
u64 bytes_per_sample = 2;
u64 channel_count;
u32 channel_mask;
if (flags & MP3_DecodeFlag_Stereo)
u64 channel_count;
u32 channel_mask;
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;
channel_mask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
}
else
{
channel_count = 1;
channel_mask = SPEAKER_FRONT_CENTER;
break;
}
//- 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 (;;)
/* Check if done */
if (sample_flags & MF_SOURCE_READERF_ENDOFSTREAM)
{
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))
{
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);
result.ok = 1;
break;
}
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);
IMFByteStream_Close(byte_stream);
/* FIXME: Enable this */
//IStream_Release(i_stream);
MFShutdown();
IMediaBuffer_Release(buffer);
IMFSample_Release(sample);
}
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
#pragma warning(push, 0)
# include <mfapi.h>
# include <mfidl.h>
# include <mfreadwrite.h>
# include <Shlwapi.h>
# include <objidl.h>
#include <mfapi.h>
#include <mfidl.h>
#include <mfreadwrite.h>
#include <Shlwapi.h>
#include <objidl.h>
#pragma warning(pop)
#pragma comment(lib, "mfplat")

File diff suppressed because it is too large Load Diff

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -11,12 +11,12 @@ PB_WSP_SharedState PB_WSP_shared_state = ZI;
void PB_Bootstrap(void)
{
PB_WSP_SharedState *g = &PB_WSP_shared_state;
PB_WSP_InitializeWasapi();
/* Start playback job */
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);
OnExit(&PB_WSP_Shutdown);
PB_WSP_SharedState *g = &PB_WSP_shared_state;
PB_WSP_InitializeWasapi();
/* Start playback job */
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);
OnExit(&PB_WSP_Shutdown);
}
////////////////////////////////////////////////////////////
@ -24,102 +24,102 @@ void PB_Bootstrap(void)
ExitFuncDef(PB_WSP_Shutdown)
{
PB_WSP_SharedState *g = &PB_WSP_shared_state;
Atomic32Set(&g->shutdown, 1);
YieldOnFence(&g->shutdown_jobs_fence, g->shutdown_jobs_count);
PB_WSP_SharedState *g = &PB_WSP_shared_state;
Atomic32Set(&g->shutdown, 1);
YieldOnFence(&g->shutdown_jobs_fence, g->shutdown_jobs_count);
}
void PB_WSP_InitializeWasapi(void)
{
PB_WSP_SharedState *g = &PB_WSP_shared_state;
u64 sample_rate = PB_SampleRate;
u64 channel_count = 2;
u32 channel_mask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
PB_WSP_SharedState *g = &PB_WSP_shared_state;
u64 sample_rate = PB_SampleRate;
u64 channel_count = 2;
u32 channel_mask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
/* Create enumerator to get audio device */
IMMDeviceEnumerator *enumerator;
CoCreateInstance(&CLSID_MMDeviceEnumerator, 0, CLSCTX_ALL, &IID_IMMDeviceEnumerator, (LPVOID *)&enumerator);
/* Create enumerator to get audio device */
IMMDeviceEnumerator *enumerator;
CoCreateInstance(&CLSID_MMDeviceEnumerator, 0, CLSCTX_ALL, &IID_IMMDeviceEnumerator, (LPVOID *)&enumerator);
/* Get default playback device */
IMMDevice *device;
IMMDeviceEnumerator_GetDefaultAudioEndpoint(enumerator, eRender, eConsole, &device);
IMMDeviceEnumerator_Release(enumerator);
/* Get default playback device */
IMMDevice *device;
IMMDeviceEnumerator_GetDefaultAudioEndpoint(enumerator, eRender, eConsole, &device);
IMMDeviceEnumerator_Release(enumerator);
/* Create audio client for device */
IMMDevice_Activate(device, &IID_IAudioClient, CLSCTX_ALL, 0, (LPVOID *)&g->client);
IMMDevice_Release(device);
/* Create audio client for device */
IMMDevice_Activate(device, &IID_IAudioClient, CLSCTX_ALL, 0, (LPVOID *)&g->client);
IMMDevice_Release(device);
WAVEFORMATEXTENSIBLE format_ex = {
.Format = {
.wFormatTag = WAVE_FORMAT_EXTENSIBLE,
.nChannels = (WORD)channel_count,
.nSamplesPerSec = (WORD)sample_rate,
.nAvgBytesPerSec = (DWORD)(sample_rate * channel_count * sizeof(f32)),
.nBlockAlign = (WORD)(channel_count * sizeof(f32)),
.wBitsPerSample = (WORD)(8 * sizeof(f32)),
.cbSize = sizeof(format_ex) - sizeof(format_ex.Format),
},
.Samples.wValidBitsPerSample = 8 * sizeof(f32),
.dwChannelMask = channel_mask,
.SubFormat = MEDIASUBTYPE_IEEE_FLOAT,
};
WAVEFORMATEX *wfx = &format_ex.Format;
WAVEFORMATEXTENSIBLE format_ex = {
.Format = {
.wFormatTag = WAVE_FORMAT_EXTENSIBLE,
.nChannels = (WORD)channel_count,
.nSamplesPerSec = (WORD)sample_rate,
.nAvgBytesPerSec = (DWORD)(sample_rate * channel_count * sizeof(f32)),
.nBlockAlign = (WORD)(channel_count * sizeof(f32)),
.wBitsPerSample = (WORD)(8 * sizeof(f32)),
.cbSize = sizeof(format_ex) - sizeof(format_ex.Format),
},
.Samples.wValidBitsPerSample = 8 * sizeof(f32),
.dwChannelMask = channel_mask,
.SubFormat = MEDIASUBTYPE_IEEE_FLOAT,
};
WAVEFORMATEX *wfx = &format_ex.Format;
#if 0
b32 client_initialized = 0;
IAudioClient3 *client3;
if (SUCCEEDED(IAudioClient_QueryInterface(g->client, &IID_IAudioClient3, (LPVOID *)&client3)))
#if 0
b32 client_initialized = 0;
IAudioClient3 *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)
* 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);
client_initialized = 1;
}
IAudioClient_GetMixFormat(g->client, &g->buffer_format);
IAudioClient3_Release(client3);
}
#else
b32 client_initialized = 0;
#endif
/* Set up event handler to wait on */
g->event = CreateEventW(0, 0, 0, 0);
IAudioClient_SetEventHandle(g->client, g->event);
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);
/* Get playback client */
IAudioClient_GetService(g->client, &IID_IAudioRenderClient, (LPVOID *)&g->playback);
/* 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);
}
/* Start the playback */
IAudioClient_Start(g->client);
IAudioClient_GetMixFormat(g->client, &g->buffer_format);
/* Get audio buffer size in samples */
IAudioClient_GetBufferSize(g->client, &g->buffer_frames);
/* Set up event handler to wait on */
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_SharedState *g = &PB_WSP_shared_state;
PB_WSP_Buff wspbuf = ZI;
PB_WSP_SharedState *g = &PB_WSP_shared_state;
PB_WSP_Buff wspbuf = ZI;
/* Get padding frames */
u32 padding_frames;
IAudioClient_GetCurrentPadding(g->client, &padding_frames);
/* Get padding frames */
u32 padding_frames;
IAudioClient_GetCurrentPadding(g->client, &padding_frames);
/* Get output buffer from WASAPI */
wspbuf.frames_count = 0;
if (padding_frames <= g->buffer_frames)
{
wspbuf.frames_count = g->buffer_frames - padding_frames;
}
IAudioRenderClient_GetBuffer(g->playback, wspbuf.frames_count, &wspbuf.frames);
/* Get output buffer from WASAPI */
wspbuf.frames_count = 0;
if (padding_frames <= g->buffer_frames)
{
wspbuf.frames_count = g->buffer_frames - padding_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)
{
PB_WSP_SharedState *g = &PB_WSP_shared_state;
u32 frames_in_source = src.count / 2;
u32 frames_in_output = wspbuf->frames_count;
PB_WSP_SharedState *g = &PB_WSP_shared_state;
u32 frames_in_source = src.count / 2;
u32 frames_in_output = wspbuf->frames_count;
u32 flags = 0;
if (frames_in_source == frames_in_output)
{
/* Copy bytes to output */
u32 bytes_per_sample = g->buffer_format->nBlockAlign / g->buffer_format->nChannels;
u32 write_size = frames_in_source * 2 * bytes_per_sample;
CopyBytes(wspbuf->frames, src.samples, write_size);
}
else
{
/* Submit silence if not enough samples */
flags = AUDCLNT_BUFFERFLAGS_SILENT;
u32 flags = 0;
if (frames_in_source == frames_in_output)
{
/* Copy bytes to output */
u32 bytes_per_sample = g->buffer_format->nBlockAlign / g->buffer_format->nChannels;
u32 write_size = frames_in_source * 2 * bytes_per_sample;
CopyBytes(wspbuf->frames, src.samples, write_size);
}
else
{
/* Submit silence if not enough samples */
flags |= AUDCLNT_BUFFERFLAGS_SILENT;
/* This shouldn't occur, mixer should be generating samples equivilent
* to value returned from `PB_WSP_BeginUpdate`. */
Assert(0);
}
/* This shouldn't occur, mixer should be generating samples equivilent
* to value returned from `PB_WSP_BeginUpdate`. */
Assert(0);
}
#if !AUDIO_ENABLED
flags = AUDCLNT_BUFFERFLAGS_SILENT;
#endif
if (!AUDIO_ENABLED)
{
flags |= AUDCLNT_BUFFERFLAGS_SILENT;
}
/* Submit output buffer to WASAPI */
IAudioRenderClient_ReleaseBuffer(g->playback, frames_in_source, flags);
/* Submit output buffer to WASAPI */
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)
{
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
* 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 */
while (!Atomic32Fetch(&g->shutdown))
/* FIXME: If playback fails at any point and mixer stops advancing, we
* 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 */
while (!Atomic32Fetch(&g->shutdown))
{
TempArena scratch = BeginScratchNoConflict();
{
TempArena scratch = BeginScratchNoConflict();
{
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);
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);
}
}

View File

@ -2,8 +2,8 @@
//~ Win32 libs
#pragma warning(push, 0)
# include <Audioclient.h>
# include <mmdeviceapi.h>
#include <Audioclient.h>
#include <mmdeviceapi.h>
#pragma warning(pop)
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)
{
u32 frames_count;
u8 *frames;
u32 frames_count;
u8 *frames;
};
////////////////////////////////////////////////////////////
@ -26,14 +26,14 @@ Struct(PB_WSP_Buff)
Struct(PB_WSP_SharedState)
{
Atomic32 shutdown;
IAudioClient *client;
HANDLE event;
IAudioRenderClient *playback;
WAVEFORMATEX *buffer_format;
u32 buffer_frames;
Fence shutdown_jobs_fence;
u32 shutdown_jobs_count;
Atomic32 shutdown;
IAudioClient *client;
HANDLE event;
IAudioRenderClient *playback;
WAVEFORMATEX *buffer_format;
u32 buffer_frames;
Fence shutdown_jobs_fence;
u32 shutdown_jobs_count;
} extern PB_WSP_shared_state;
////////////////////////////////////////////////////////////

View File

@ -1,9 +1,9 @@
S_Ctx S = Zi;
Readonly S_ReadonlyCtx S_ro = {
.nil_ent = {
.xf = CompXformIdentity
}
.nil_ent = {
.xf = CompXformIdentity
}
};
////////////////////////////////////////////////////////////
@ -11,26 +11,26 @@ Readonly S_ReadonlyCtx S_ro = {
void S_Bootstrap(void)
{
/* Initialize shared state */
for (u64 i = 0; i < countof(S.input_states); ++i)
{
S_InputState *input = &S.input_states[i];
input->arena = AcquireArena(Gibi(64));
}
for (u64 i = 0; i < countof(S.output_states); ++i)
{
S_OutputState *output = &S.output_states[i];
output->arena = AcquireArena(Gibi(64));
}
/* Initialize shared state */
for (u64 i = 0; i < countof(S.input_states); ++i)
{
S_InputState *input = &S.input_states[i];
input->arena = AcquireArena(Gibi(64));
}
for (u64 i = 0; i < countof(S.output_states); ++i)
{
S_OutputState *output = &S.output_states[i];
output->arena = AcquireArena(Gibi(64));
}
/* Dispatch sim wave */
DispatchWave(Lit("Sim"), 1, S_TickForever, 0);
/* Dispatch sim wave */
DispatchWave(Lit("Sim"), 1, S_TickForever, 0);
}
void S_Shutdown(void)
{
Atomic32Set(&S.shutdown, 1);
YieldOnFence(&S.worker_completion_fence, S.workers_count);
Atomic32Set(&S.shutdown, 1);
YieldOnFence(&S.worker_completion_fence, S.workers_count);
}
////////////////////////////////////////////////////////////
@ -38,17 +38,17 @@ void S_Shutdown(void)
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)
{
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)
{
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)
{
/* TODO: Don't use true randomness for entity keys. It's overkill & non-deterministic. */
S_Key result = Zi;
TrueRand(StringFromStruct(&result));
return result;
/* TODO: Don't use true randomness for entity keys. It's overkill & non-deterministic. */
S_Key result = Zi;
TrueRand(StringFromStruct(&result));
return result;
}
////////////////////////////////////////////////////////////
@ -67,26 +67,26 @@ S_Key S_RandKey(void)
Rng2I32 S_UpdateTilesInPlaceFromPlacement(u8 *tiles, S_TilePlacement placement)
{
Rng2I32 dirty_rect = Zi;
switch (placement.placement_kind)
Rng2I32 dirty_rect = Zi;
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;
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)
{
Vec2I32 tile_pos = VEC2I32(tile_x, tile_y);
i32 tile_idx = S_TileIdxFromTilePos(tile_pos);
tiles[tile_idx] = (u8)tile;
}
}
dirty_rect = range;
} break;
}
return dirty_rect;
Vec2I32 tile_pos = VEC2I32(tile_x, tile_y);
i32 tile_idx = S_TileIdxFromTilePos(tile_pos);
tiles[tile_idx] = (u8)tile;
}
}
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)
{
desc.count = MaxI32(desc.count, 1);
S_Shape result = Zi;
desc.count = MaxI32(desc.count, 1);
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;
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;
accum = AddVec2(accum, result.points[p_idx]);
}
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 result = shape;
for (i32 i = 0; i < shape.points_count; ++i)
{
result.points[i] = MulXformV2(xf, shape.points[i]);
}
Vec2 scale = ScaleFromXform(xf);
result.radius *= MaxF32(scale.x, scale.y);
return result;
S_Shape result = shape;
for (i32 i = 0; i < shape.points_count; ++i)
{
result.points[i] = MulXformV2(xf, shape.points[i]);
}
Vec2 scale = ScaleFromXform(xf);
result.radius *= MaxF32(scale.x, scale.y);
return result;
}
Vec2 S_SupportPointFromShape(S_Shape shape, Vec2 dir)
{
Vec2 result = Zi;
f32 max_dot = -F32Infinity;
for (i32 i = 0; i < shape.points_count; ++i)
Vec2 result = Zi;
f32 max_dot = -F32Infinity;
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];
f32 dot = DotVec2(p, dir);
if (dot > max_dot)
{
max_dot = dot;
result = p;
}
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 lookup = Zi;
S_Lookup lookup = Zi;
lookup.bins_count = 4096;
lookup.bins = PushStructs(arena, S_LookupEntNode *, lookup.bins_count);
for (i64 ent_idx = 0; ent_idx < world->ents_count; ++ent_idx)
lookup.bins_count = 4096;
lookup.bins = PushStructs(arena, S_LookupEntNode *, lookup.bins_count);
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];
if (ent->active)
{
S_Key key = ent->key;
S_LookupEntNode *n = PushStruct(arena, S_LookupEntNode);
n->ent = ent;
S_LookupEntNode **bin = &lookup.bins[ent->key.v.lo % lookup.bins_count];
SllStackPush(*bin, n);
}
S_Key key = ent->key;
S_LookupEntNode *n = PushStruct(arena, S_LookupEntNode);
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 *result = &S_ro.nil_ent;
if (!S_IsKeyNil(key))
S_Ent *result = &S_ro.nil_ent;
if (!S_IsKeyNil(key))
{
i64 bins_count = lookup->bins_count;
if (bins_count > 0)
{
i64 bins_count = lookup->bins_count;
if (bins_count > 0)
S_LookupEntNode *n = lookup->bins[key.v.lo % bins_count];
for (; n; n = n->next)
{
if (S_MatchKey(n->ent->key, key))
{
S_LookupEntNode *n = lookup->bins[key.v.lo % bins_count];
for (; n; n = n->next)
{
if (S_MatchKey(n->ent->key, key))
{
result = n->ent;
break;
}
}
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)
{
ZeroStruct(iter);
iter->world = world;
return S_NextEnt(iter);
ZeroStruct(iter);
iter->world = world;
return S_NextEnt(iter);
}
S_Ent *S_NextEnt(S_Iter *iter)
{
S_World *world = iter->world;
S_Ent *result = &S_ro.nil_ent;
S_World *world = iter->world;
S_Ent *result = &S_ro.nil_ent;
i64 ent_idx = iter->cur_idx;
for (; ent_idx < world->ents_count; ++ent_idx)
i64 ent_idx = iter->cur_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];
if (ent->active)
{
result = ent;
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 *world = PushStruct(arena, S_World);
S_World *world = PushStruct(arena, S_World);
/* Copy ents */
world->ents = PushStructsNoZero(arena, S_Ent, snapshot->ents_count);
CopyStructs(world->ents, snapshot->ents, snapshot->ents_count);
world->ents_count = snapshot->ents_count;
world->tick = snapshot->tick;
/* Copy ents */
world->ents = PushStructsNoZero(arena, S_Ent, snapshot->ents_count);
CopyStructs(world->ents, snapshot->ents, snapshot->ents_count);
world->ents_count = snapshot->ents_count;
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, _)
{
S_Ent *a = *(S_Ent **)arg_a;
S_Ent *b = *(S_Ent **)arg_b;
S_Key a_key = a->key;
S_Key b_key = b->key;
i32 result = 0;
if (result == 0)
{
result = ((a_key.v.lo < b_key.v.lo) - (a_key.v.lo > b_key.v.lo));
}
if (result == 0)
{
result = ((a_key.v.hi < b_key.v.hi) - (a_key.v.hi > b_key.v.hi));
}
return result;
S_Ent *a = *(S_Ent **)arg_a;
S_Ent *b = *(S_Ent **)arg_b;
S_Key a_key = a->key;
S_Key b_key = b->key;
i32 result = 0;
if (result == 0)
{
result = ((a_key.v.lo < b_key.v.lo) - (a_key.v.lo > b_key.v.lo));
}
if (result == 0)
{
result = ((a_key.v.hi < b_key.v.hi) - (a_key.v.hi > b_key.v.hi));
}
return result;
}
////////////////////////////////////////////////////////////
@ -261,204 +261,204 @@ MergesortCompareFuncDef(S_SortEntsByKeyCmp, arg_a, arg_b, _)
void S_TickForever(WaveLaneCtx *lane)
{
Arena *frame_arena = AcquireArena(Gibi(64));
Arena *perm = PermArena();
Arena *frame_arena = AcquireArena(Gibi(64));
Arena *perm = PermArena();
const i32 world_size = S_WorldSize;
const i32 world_size = S_WorldSize;
//- World data
Arena *ents_arena = AcquireArena(Gibi(64));
S_World *world = PushStruct(perm, S_World);
world->ents = ArenaFirst(ents_arena, S_Ent);
i64 first_free_ent_num = 0;
i64 sim_time_ns = 0;
//- World data
Arena *ents_arena = AcquireArena(Gibi(64));
S_World *world = PushStruct(perm, S_World);
world->ents = ArenaFirst(ents_arena, S_Ent);
i64 first_free_ent_num = 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;
while (!shutdown)
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);
{
ResetArena(frame_arena);
S_Iter iter = Zi;
S_Lookup lookup = Zi;
//////////////////////////////
//- 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);
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);
}
}

View File

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

View File

@ -3,14 +3,14 @@
Vec2I32 S_TilePosFromWorldPos(Vec2 p)
{
Vec2I32 result;
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);
return result;
Vec2I32 result;
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);
return result;
}
i32 S_TileIdxFromTilePos(Vec2I32 p)
{
i32 result = ClampI32(p.x + (p.y * S_WorldSize * 2), 0, S_WorldSize * S_WorldSize * 4);
return result;
i32 result = ClampI32(p.x + (p.y * S_WorldSize * 2), 0, S_WorldSize * S_WorldSize * 4);
return result;
}

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -1,38 +1,38 @@
////////////////////////////////////////////////////////////
//~ Command table
#define V_CmdsTableXMacro(X) \
X(nop, NOP, V_CmdDescFlag_HideFromPalette, V_HOTKEY(0), ) \
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(zoom_in, Zoom In, V_CmdDescFlag_HideFromPalette, V_HOTKEY( Button_MWheelUp ), ) \
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_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_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(spawn, Spawn, V_CmdDescFlag_None, V_HOTKEY( Button_S, .ctrl = 1 ), ) \
/* -------------------------------------------------------------------------------------------------------------------- */
#define V_CmdsTableXMacro(X) \
X(nop, NOP, V_CmdDescFlag_HideFromPalette, V_HOTKEY(0), ) \
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(zoom_in, Zoom In, V_CmdDescFlag_HideFromPalette, V_HOTKEY( Button_MWheelUp ), ) \
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_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_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(spawn, Spawn, V_CmdDescFlag_None, V_HOTKEY( Button_S, .ctrl = 1 ), ) \
/* -------------------------------------------------------------------------------------------------------------------- */
////////////////////////////////////////////////////////////
//~ Theme types
Struct(V_WidgetTheme)
{
GC_FontKey font;
f32 font_size;
f32 window_title_font_size;
GC_FontKey font;
f32 font_size;
f32 window_title_font_size;
Vec4 window_background_color;
Vec4 window_border_color;
Vec4 divider_color;
f32 window_border;
f32 window_padding;
f32 window_width;
Vec4 window_background_color;
Vec4 window_border_color;
Vec4 divider_color;
f32 window_border;
f32 window_padding;
f32 window_width;
f32 text_padding_x;
f32 text_padding_y;
f32 text_padding_x;
f32 text_padding_y;
};
////////////////////////////////////////////////////////////
@ -41,10 +41,10 @@ Struct(V_WidgetTheme)
#define V_HOTKEY(_button, ...) { .button = _button, __VA_ARGS__ }
Struct(V_Hotkey)
{
Button button;
b32 ctrl;
b32 alt;
b32 shift;
Button button;
b32 ctrl;
b32 alt;
b32 shift;
};
////////////////////////////////////////////////////////////
@ -52,57 +52,57 @@ Struct(V_Hotkey)
Enum(V_CmdKind)
{
#define X(name, ...) V_CmdKind_##name,
V_CmdsTableXMacro(X)
#undef X
#define X(name, ...) V_CmdKind_##name,
V_CmdsTableXMacro(X)
#undef X
V_CmdKind_Count,
V_CmdKind_Count,
};
Struct(V_Shortcut)
{
V_Shortcut *next_in_bin;
V_Shortcut *prev_in_bin;
u64 hotkey_hash;
V_Hotkey hotkey;
String cmd_name;
V_Shortcut *next_in_bin;
V_Shortcut *prev_in_bin;
u64 hotkey_hash;
V_Hotkey hotkey;
String cmd_name;
};
Struct(V_ShortcutBin)
{
V_Shortcut *first;
V_Shortcut *last;
V_Shortcut *first;
V_Shortcut *last;
};
Enum(V_CmdDescFlag)
{
V_CmdDescFlag_None = 0,
V_CmdDescFlag_HideFromPalette = (1 << 0),
V_CmdDescFlag_None = 0,
V_CmdDescFlag_HideFromPalette = (1 << 0),
};
Struct(V_CmdDesc)
{
String name;
String display_name;
V_CmdDescFlag flags;
V_Hotkey default_hotkeys[8];
String name;
String display_name;
V_CmdDescFlag flags;
V_Hotkey default_hotkeys[8];
};
Struct(V_Cmd)
{
String name;
String name;
};
Struct(V_CmdNode)
{
V_CmdNode *next;
V_Cmd cmd;
V_CmdNode *next;
V_Cmd cmd;
};
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__ } },
V_CmdsTableXMacro(X)
#undef X
#define X(_name, _display_name, _flags, ...) { .name = CompLit(#_name), .display_name = CompLit(#_display_name), .flags = _flags, .default_hotkeys = { __VA_ARGS__ } },
V_CmdsTableXMacro(X)
#undef X
};
////////////////////////////////////////////////////////////
@ -110,38 +110,38 @@ Global Readonly V_CmdDesc V_cmd_descs[V_CmdKind_Count] = {
Struct(V_CommandsWidgetItemReport)
{
b32 pressed;
b32 hotkey_changed;
UI_Report ui_report;
V_Hotkey new_hotkeys[8];
b32 pressed;
b32 hotkey_changed;
UI_Report ui_report;
V_Hotkey new_hotkeys[8];
};
Struct(V_CommandsWidgetItemDesc)
{
String display_name;
V_Hotkey hotkeys[8];
String display_name;
V_Hotkey hotkeys[8];
};
Struct(V_CommandsWidgetItem)
{
V_CommandsWidgetItem *next;
UI_Key key;
V_CommandsWidgetItemDesc desc;
V_CommandsWidgetItem *next;
UI_Key key;
V_CommandsWidgetItemDesc desc;
};
Struct(V_CommandsWidget)
{
/* Persistent state */
Vec2 pos;
/* Persistent state */
Vec2 pos;
/* Per-build state */
struct
{
UI_Checkpoint cp;
V_CommandsWidgetItem *first_item;
V_CommandsWidgetItem *last_item;
u64 num_items;
} build;
/* Per-build state */
struct
{
UI_Checkpoint cp;
V_CommandsWidgetItem *first_item;
V_CommandsWidgetItem *last_item;
u64 num_items;
} build;
};
////////////////////////////////////////////////////////////
@ -151,38 +151,38 @@ Struct(V_CommandsWidget)
Struct(V_Space)
{
V_Space *parent;
V_Space *next;
V_Space *prev;
V_Space *first;
V_Space *last;
V_Space *parent;
V_Space *next;
V_Space *prev;
V_Space *first;
V_Space *last;
i64 panels_count;
struct V_Panel *first_panel;
struct V_Panel *last_panel;
i64 panels_count;
struct V_Panel *first_panel;
struct V_Panel *last_panel;
Axis axis;
Axis axis;
};
Struct(V_Panel)
{
V_Space *space;
V_Panel *next_in_space;
V_Panel *prev_in_space;
V_Space *space;
V_Panel *next_in_space;
V_Panel *prev_in_space;
i64 active_window_idx;
i64 windows_count;
struct V_Window *first_window;
struct V_Window *last_window;
i64 active_window_idx;
i64 windows_count;
struct V_Window *first_window;
struct V_Window *last_window;
};
Struct(V_Window)
{
V_Panel *panel;
V_Window *next_in_panel;
V_Window *prev_in_panel;
V_Panel *panel;
V_Window *next_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)
{
V_EditMode_Tile,
V_EditMode_Tile,
};
Struct(V_Frame)
{
Arena *arena;
Arena *dverts_arena;
Arena *dvert_idxs_arena;
G_ArenaHandle gpu_arena;
G_CommandListHandle cl;
Arena *arena;
Arena *dverts_arena;
Arena *dvert_idxs_arena;
G_ArenaHandle gpu_arena;
G_CommandListHandle cl;
i64 tick;
i64 time_ns;
i64 dt_ns;
f64 dt;
i64 tick;
i64 time_ns;
i64 dt_ns;
f64 dt;
Button held_buttons[Button_Count];
V_CommandsWidget commands_widget;
Button held_buttons[Button_Count];
V_CommandsWidget commands_widget;
String window_restore;
i32 zooms;
String window_restore;
i32 zooms;
Vec2I32 ui_dims;
Vec2I32 draw_dims;
Vec2I32 ui_dims;
Vec2I32 draw_dims;
/* Modes */
b32 is_editing;
b32 ui_debug;
b32 show_command_palette;
b32 show_console;
/* Modes */
b32 is_editing;
b32 ui_debug;
b32 show_command_palette;
b32 show_console;
/* Editor state */
V_EditMode edit_mode;
S_TileKind equipped_tile;
/* Editor state */
V_EditMode edit_mode;
S_TileKind equipped_tile;
/* Editor */
b32 is_selecting;
b32 is_panning;
V_SelectionMode selection_mode;
Vec2 world_selection_start;
Vec2 edit_camera_pos;
f32 edit_camera_zoom;
/* Editor */
b32 is_selecting;
b32 is_panning;
V_SelectionMode selection_mode;
Vec2 world_selection_start;
Vec2 edit_camera_pos;
f32 edit_camera_zoom;
/* Camera */
Vec2 camera_pos;
f32 camera_zoom;
/* Camera */
Vec2 camera_pos;
f32 camera_zoom;
/* World <-> ui */
Xform world_to_ui_xf;
Xform ui_to_world_xf;
/* World <-> ui */
Xform world_to_ui_xf;
Xform ui_to_world_xf;
/* Draw <-> ui */
Xform draw_to_ui_xf;
Xform ui_to_draw_xf;
/* Draw <-> ui */
Xform draw_to_ui_xf;
Xform ui_to_draw_xf;
/* World <-> draw */
Xform world_to_draw_xf;
Xform draw_to_world_xf;
/* World <-> draw */
Xform world_to_draw_xf;
Xform draw_to_world_xf;
/* Cursors */
Vec2 ui_cursor;
Vec2 draw_cursor;
Vec2 world_cursor;
Rng2 ui_selection;
Rng2 draw_selection;
Rng2 world_selection;
/* Cursors */
Vec2 ui_cursor;
Vec2 draw_cursor;
Vec2 world_cursor;
Rng2 ui_selection;
Rng2 draw_selection;
Rng2 world_selection;
/* Control */
Vec2 move;
Vec2 look;
/* Control */
Vec2 move;
Vec2 look;
/* Sim cmds */
u64 sim_cmds_count;
S_CmdNode *first_sim_cmd_node;
S_CmdNode *last_sim_cmd_node;
/* Sim cmds */
u64 sim_cmds_count;
S_CmdNode *first_sim_cmd_node;
S_CmdNode *last_sim_cmd_node;
};
Struct(V_Ctx)
{
Arena *world_arena;
S_World *world;
S_Lookup lookup;
S_Key player_key;
Arena *world_arena;
S_World *world;
S_Lookup lookup;
S_Key player_key;
V_Space *root_space;
V_Space *root_space;
Atomic32 shutdown;
Fence shutdown_complete;
Atomic32 shutdown;
Fence shutdown_complete;
u64 current_frame_idx;
V_Frame frames[2];
u64 current_frame_idx;
V_Frame frames[2];
};
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)
{
if (flags & V_DrawFlag_Line)
if (flags & V_DrawFlag_Line)
{
i32 verts_count = points.count;
if (verts_count >= 2)
{
i32 verts_count = points.count;
if (verts_count >= 2)
TempArena scratch = BeginScratchNoConflict();
{
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();
{
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);
i32 a_idx = line_idx;
i32 b_idx = line_idx + 1;
if (b_idx >= lines_count)
{
b_idx = 0;
}
/* Push dverts */
V_DVert *dverts = PushStructsNoZero(verts_arena, V_DVert, line_verts_count);
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 b = points.points[b_idx];
Vec2 a = points.points[a_idx];
Vec2 b = points.points[b_idx];
Vec2 a_to_b = SubVec2(b, a);
Vec2 perp = Vec2WithLen(PerpVec2(a_to_b), half_thickness);
Vec2 a_to_b = SubVec2(b, a);
Vec2 perp = Vec2WithLen(PerpVec2(a_to_b), half_thickness);
Vec2 p0 = AddVec2(a, perp);
Vec2 p1 = SubVec2(a, perp);
Vec2 p2 = SubVec2(b, perp);
Vec2 p3 = AddVec2(b, perp);
Vec2 p0 = AddVec2(a, perp);
Vec2 p1 = SubVec2(a, perp);
Vec2 p2 = SubVec2(b, perp);
Vec2 p3 = AddVec2(b, perp);
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);
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);
}
else
}
else
{
i32 verts_count = points.count;
if (verts_count >= 3)
{
i32 verts_count = points.count;
if (verts_count >= 3)
{
i32 idx_offset = ArenaCount(verts_arena, V_DVert);
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 */
V_DVert *dverts = PushStructsNoZero(verts_arena, V_DVert, verts_count);
for (i32 point_idx = 0; point_idx < (i32)points.count; ++point_idx)
{
V_DVert *dvert = &dverts[point_idx];
dvert->pos = points.points[point_idx];
dvert->color_lin = color_lin;
}
/* Push dverts */
V_DVert *dverts = PushStructsNoZero(verts_arena, V_DVert, verts_count);
for (i32 point_idx = 0; point_idx < (i32)points.count; ++point_idx)
{
V_DVert *dvert = &dverts[point_idx];
dvert->pos = points.points[point_idx];
dvert->color_lin = color_lin;
}
/* Generate indices in a fan pattern */
i32 *indices = PushStructsNoZero(idxs_arena, i32, idx_count);
for (i32 i = 0; i < tris_count; ++i)
{
i32 tri_offset = i * 3;
indices[tri_offset + 0] = idx_offset;
indices[tri_offset + 1] = idx_offset + i + 1;
indices[tri_offset + 2] = idx_offset + i + 2;
}
}
/* Generate indices in a fan pattern */
i32 *indices = PushStructsNoZero(idxs_arena, i32, idx_count);
for (i32 i = 0; i < tris_count; ++i)
{
i32 tri_offset = i * 3;
indices[tri_offset + 0] = idx_offset;
indices[tri_offset + 1] = idx_offset + i + 1;
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)
{
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;
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;
draw_points.points = PushStructsNoZero(scratch.arena, Vec2, detail);
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);
Vec2Array draw_points = Zi;
draw_points.points = PushStructsNoZero(scratch.arena, Vec2, detail);
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);
}
}

View File

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

View File

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

View File

@ -3,124 +3,124 @@
ComputeShader2D(V_BackdropCS, 8, 8)
{
V_DParams params = G_Dereference<V_DParams>(V_ShaderConst_Params)[0];
RWTexture2D<Vec4> target = G_Dereference<Vec4>(params.target_rw);
Texture2D<uint> tiles = G_Dereference<uint>(params.tiles);
V_DParams params = G_Dereference<V_DParams>(V_ShaderConst_Params)[0];
RWTexture2D<Vec4> target = G_Dereference<Vec4>(params.target_rw);
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_b = LinearFromSrgb(Vec4(0.15, 0.15, 0.15, 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 y_axis_color = LinearFromSrgb(Vec4(0, 0.75, 0, 1));
const Vec4 bounds_color = LinearFromSrgb(Vec4(0.75, 0.75, 0, 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 grid_color = LinearFromSrgb(Vec4(0, 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 bounds_color = LinearFromSrgb(Vec4(0.75, 0.75, 0, 1));
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)
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)
{
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);
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)
/* Grid checker */
{
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)
{
/* Grid checker */
{
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;
}
}
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;
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)
{
V_DParams params = G_Dereference<V_DParams>(V_ShaderConst_Params)[0];
StructuredBuffer<V_DQuad> quads = G_Dereference<V_DQuad>(params.quads);
RWTexture2D<Vec4> target = G_Dereference<Vec4>(params.target_rw);
V_DParams params = G_Dereference<V_DParams>(V_ShaderConst_Params)[0];
StructuredBuffer<V_DQuad> quads = G_Dereference<V_DQuad>(params.quads);
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 tex_uv = lerp(quad.tex_uv0, quad.tex_uv1, rect_uv);
// Vec2 target_pos = lerp(quad.p0, quad.p1, rect_uv);
Vec2 target_pos = 0;
Vec2 rect_uv = RectUvFromVertexId(SV_VertexID);
// 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 = 0;
V_DQuadPSInput result;
result.sv_position = Vec4(NdcFromPos(target_pos, countof(target)).xy, 0, 1);
result.quad_idx = SV_InstanceID;
return result;
V_DQuadPSInput result;
result.sv_position = Vec4(NdcFromPos(target_pos, countof(target)).xy, 0, 1);
result.quad_idx = SV_InstanceID;
return result;
}
//////////////////////////////
@ -153,15 +153,15 @@ VertexShader(V_DQuadVS, V_DQuadPSInput)
PixelShader(V_DQuadPS, V_DQuadPSOutput, V_DQuadPSInput input)
{
V_DParams params = G_Dereference<V_DParams>(V_ShaderConst_Params)[0];
StructuredBuffer<V_DQuad> quads = G_Dereference<V_DQuad>(params.quads);
V_DQuad quad = quads[input.quad_idx];
V_DParams params = G_Dereference<V_DParams>(V_ShaderConst_Params)[0];
StructuredBuffer<V_DQuad> quads = G_Dereference<V_DQuad>(params.quads);
V_DQuad quad = quads[input.quad_idx];
Vec4 final_color = 0;
Vec4 final_color = 0;
V_DQuadPSOutput output;
output.sv_target0 = final_color;
return output;
V_DQuadPSOutput output;
output.sv_target0 = final_color;
return output;
}
////////////////////////////////////////////////////////////
@ -172,18 +172,18 @@ PixelShader(V_DQuadPS, V_DQuadPSOutput, V_DQuadPSInput input)
VertexShader(V_DVertVS, V_DVertPSInput)
{
V_DParams params = G_Dereference<V_DParams>(V_ShaderConst_Params)[0];
StructuredBuffer<V_DVert> verts = G_Dereference<V_DVert>(params.shape_verts);
RWTexture2D<Vec4> target = G_Dereference<Vec4>(params.target_rw);
V_DParams params = G_Dereference<V_DParams>(V_ShaderConst_Params)[0];
StructuredBuffer<V_DVert> verts = G_Dereference<V_DVert>(params.shape_verts);
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;
result.sv_position = Vec4(NdcFromPos(target_pos, countof(target)).xy, 0, 1);
result.color_lin = vert.color_lin;
return result;
V_DVertPSInput result;
result.sv_position = Vec4(NdcFromPos(target_pos, countof(target)).xy, 0, 1);
result.color_lin = vert.color_lin;
return result;
}
//////////////////////////////
@ -191,9 +191,9 @@ VertexShader(V_DVertVS, V_DVertPSInput)
PixelShader(V_DVertPS, V_DVertPSOutput, V_DVertPSInput input)
{
V_DVertPSOutput output;
output.sv_target0 = input.color_lin;
return output;
V_DVertPSOutput output;
output.sv_target0 = input.color_lin;
return output;
}
////////////////////////////////////////////////////////////
@ -204,10 +204,10 @@ PixelShader(V_DVertPS, V_DVertPSOutput, V_DVertPSInput input)
VertexShader(V_OverlayVS, V_OverlayPSInput)
{
Vec2 uv = RectUvFromVertexId(SV_VertexID);
V_OverlayPSInput result;
result.sv_position = Vec4(NdcFromUv(uv).xy, 0, 1);
return result;
Vec2 uv = RectUvFromVertexId(SV_VertexID);
V_OverlayPSInput result;
result.sv_position = Vec4(NdcFromUv(uv).xy, 0, 1);
return result;
}
//////////////////////////////
@ -215,59 +215,59 @@ VertexShader(V_OverlayVS, V_OverlayPSInput)
PixelShader(V_OverlayPS, V_OverlayPSOutput, V_OverlayPSInput input)
{
V_DParams params = G_Dereference<V_DParams>(V_ShaderConst_Params)[0];
Texture2D<uint> tiles = G_Dereference<uint>(params.tiles);
Vec2 screen_pos = input.sv_position.xy;
Vec4 result = 0;
V_DParams params = G_Dereference<V_DParams>(V_ShaderConst_Params)[0];
Texture2D<uint> tiles = G_Dereference<uint>(params.tiles);
Vec2 screen_pos = input.sv_position.xy;
Vec4 result = 0;
Vec2 world_pos = mul(params.draw_to_world_xf, Vec3(screen_pos, 1));
Vec2I32 tile_pos = S_TilePosFromWorldPos(world_pos);
S_TileKind equipped_tile = params.equipped_tile;
Vec2 world_pos = mul(params.draw_to_world_xf, Vec3(screen_pos, 1));
Vec2I32 tile_pos = S_TilePosFromWorldPos(world_pos);
S_TileKind equipped_tile = params.equipped_tile;
f32 half_thickness = 1;
Vec4 border_color = LinearFromSrgb(Vec4(1, 1, 1, 1));
// Vec4 inner_color = LinearFromSrgb(Vec4(0.4, 0.4, 0.4, 0.25));
f32 half_thickness = 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.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 world_selection = params.world_selection;
Rng2 screen_selection = params.draw_selection;
Rng2 world_selection = params.world_selection;
Rng2I32 tile_selection;
tile_selection.p0 = S_TilePosFromWorldPos(world_selection.p0);
tile_selection.p1 = S_TilePosFromWorldPos(world_selection.p1);
Rng2I32 tile_selection;
tile_selection.p0 = S_TilePosFromWorldPos(world_selection.p0);
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;
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
{
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;
}
}
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;
output.sv_target0 = result;
return output;
V_OverlayPSOutput output;
output.sv_target0 = result;
return output;
}

View File

@ -3,13 +3,13 @@
Struct(V_DQuadPSInput)
{
Semantic(Vec4, sv_position);
Semantic(nointerpolation u32, quad_idx);
Semantic(Vec4, sv_position);
Semantic(nointerpolation u32, quad_idx);
};
Struct(V_DQuadPSOutput)
{
Semantic(Vec4, sv_target0);
Semantic(Vec4, sv_target0);
};
////////////////////////////////////////////////////////////
@ -18,13 +18,13 @@ Struct(V_DQuadPSOutput)
Struct(V_DVertPSInput)
{
Semantic(Vec4, sv_position);
Semantic(Vec4, color_lin);
Semantic(Vec4, sv_position);
Semantic(Vec4, color_lin);
};
Struct(V_DVertPSOutput)
{
Semantic(Vec4, sv_target0);
Semantic(Vec4, sv_target0);
};
////////////////////////////////////////////////////////////
@ -33,12 +33,12 @@ Struct(V_DVertPSOutput)
Struct(V_OverlayPSInput)
{
Semantic(Vec4, sv_position);
Semantic(Vec4, sv_position);
};
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
Enum(PP_BindKind)
{
PP_BindKind_None,
PP_BindKind_None,
PP_BindKind_MoveUp,
PP_BindKind_MoveDown,
PP_BindKind_MoveLeft,
PP_BindKind_MoveRight,
PP_BindKind_Walk,
PP_BindKind_Fire,
PP_BindKind_AltFire,
PP_BindKind_MoveUp,
PP_BindKind_MoveDown,
PP_BindKind_MoveLeft,
PP_BindKind_MoveRight,
PP_BindKind_Walk,
PP_BindKind_Fire,
PP_BindKind_AltFire,
PP_BindKind_TestTile,
PP_BindKind_DebugClear,
PP_BindKind_DebugSpawn1,
PP_BindKind_DebugSpawn2,
PP_BindKind_DebugSpawn3,
PP_BindKind_DebugSpawn4,
PP_BindKind_DebugWalls,
PP_BindKind_DebugFollow,
PP_BindKind_DebugDraw,
PP_BindKind_DebugConsole,
PP_BindKind_DebugCamera,
PP_BindKind_DebugLister,
PP_BindKind_DebugPause,
PP_BindKind_DebugStep,
PP_BindKind_DebugDrag,
PP_BindKind_DebugDelete,
PP_BindKind_DebugTeleport,
PP_BindKind_DebugExplode,
PP_BindKind_DebugToggleTopmost,
PP_BindKind_DebugUi,
PP_BindKind_FullscreenMod,
PP_BindKind_Fullscreen,
PP_BindKind_ZoomIn,
PP_BindKind_ZoomOut,
PP_BindKind_Pan,
PP_BindKind_TestTile,
PP_BindKind_DebugClear,
PP_BindKind_DebugSpawn1,
PP_BindKind_DebugSpawn2,
PP_BindKind_DebugSpawn3,
PP_BindKind_DebugSpawn4,
PP_BindKind_DebugWalls,
PP_BindKind_DebugFollow,
PP_BindKind_DebugDraw,
PP_BindKind_DebugConsole,
PP_BindKind_DebugCamera,
PP_BindKind_DebugLister,
PP_BindKind_DebugPause,
PP_BindKind_DebugStep,
PP_BindKind_DebugDrag,
PP_BindKind_DebugDelete,
PP_BindKind_DebugTeleport,
PP_BindKind_DebugExplode,
PP_BindKind_DebugToggleTopmost,
PP_BindKind_DebugUi,
PP_BindKind_FullscreenMod,
PP_BindKind_Fullscreen,
PP_BindKind_ZoomIn,
PP_BindKind_ZoomOut,
PP_BindKind_Pan,
#if IsRtcEnabled
/* Debug */
/* Debug */
PP_BindKind_ResetDebugSteps,
PP_BindKind_IncrementDebugSteps,
PP_BindKind_DecrementDebugSteps,
PP_BindKind_ResetDebugSteps,
PP_BindKind_IncrementDebugSteps,
PP_BindKind_DecrementDebugSteps,
#endif
PP_BindKind_Count
PP_BindKind_Count
};
//- Test bindings
/* TODO: Remove this */
Global Readonly PP_BindKind g_binds[Btn_Count] = {
[Btn_W] = PP_BindKind_MoveUp,
[Btn_S] = PP_BindKind_MoveDown,
[Btn_A] = PP_BindKind_MoveLeft,
[Btn_D] = PP_BindKind_MoveRight,
[Btn_M1] = PP_BindKind_Fire,
[Btn_M2] = PP_BindKind_AltFire,
[Btn_W] = PP_BindKind_MoveUp,
[Btn_S] = PP_BindKind_MoveDown,
[Btn_A] = PP_BindKind_MoveLeft,
[Btn_D] = PP_BindKind_MoveRight,
[Btn_M1] = PP_BindKind_Fire,
[Btn_M2] = PP_BindKind_AltFire,
#if 0
[Btn_Alt] = PP_BindKind_Walk,
[Btn_Alt] = PP_BindKind_Walk,
#endif
/* Testing */
[Btn_Z] = PP_BindKind_TestTile,
[Btn_M5] = PP_BindKind_DebugDrag,
[Btn_M4] = PP_BindKind_DebugDelete,
[Btn_F] = PP_BindKind_DebugExplode,
[Btn_T] = PP_BindKind_DebugTeleport,
[Btn_C] = PP_BindKind_DebugClear,
[Btn_1] = PP_BindKind_DebugSpawn1,
[Btn_2] = PP_BindKind_DebugSpawn2,
[Btn_3] = PP_BindKind_DebugSpawn3,
[Btn_4] = PP_BindKind_DebugSpawn4,
[Btn_G] = PP_BindKind_DebugWalls,
[Btn_N] = PP_BindKind_DebugStep,
[Btn_Q] = PP_BindKind_DebugFollow,
[Btn_F1] = PP_BindKind_DebugPause,
[Btn_F2] = PP_BindKind_DebugCamera,
[Btn_F3] = PP_BindKind_DebugDraw,
[Btn_Tab] = PP_BindKind_DebugLister,
[Btn_F4] = PP_BindKind_DebugToggleTopmost,
[Btn_F5] = PP_BindKind_DebugUi,
[Btn_GraveAccent] = PP_BindKind_DebugConsole,
[Btn_Alt] = PP_BindKind_FullscreenMod,
[Btn_Enter] = PP_BindKind_Fullscreen,
[Btn_MWheelUp] = PP_BindKind_ZoomIn,
[Btn_MWheelDown] = PP_BindKind_ZoomOut,
[Btn_M3] = PP_BindKind_Pan,
/* Testing */
[Btn_Z] = PP_BindKind_TestTile,
[Btn_M5] = PP_BindKind_DebugDrag,
[Btn_M4] = PP_BindKind_DebugDelete,
[Btn_F] = PP_BindKind_DebugExplode,
[Btn_T] = PP_BindKind_DebugTeleport,
[Btn_C] = PP_BindKind_DebugClear,
[Btn_1] = PP_BindKind_DebugSpawn1,
[Btn_2] = PP_BindKind_DebugSpawn2,
[Btn_3] = PP_BindKind_DebugSpawn3,
[Btn_4] = PP_BindKind_DebugSpawn4,
[Btn_G] = PP_BindKind_DebugWalls,
[Btn_N] = PP_BindKind_DebugStep,
[Btn_Q] = PP_BindKind_DebugFollow,
[Btn_F1] = PP_BindKind_DebugPause,
[Btn_F2] = PP_BindKind_DebugCamera,
[Btn_F3] = PP_BindKind_DebugDraw,
[Btn_Tab] = PP_BindKind_DebugLister,
[Btn_F4] = PP_BindKind_DebugToggleTopmost,
[Btn_F5] = PP_BindKind_DebugUi,
[Btn_GraveAccent] = PP_BindKind_DebugConsole,
[Btn_Alt] = PP_BindKind_FullscreenMod,
[Btn_Enter] = PP_BindKind_Fullscreen,
[Btn_MWheelUp] = PP_BindKind_ZoomIn,
[Btn_MWheelDown] = PP_BindKind_ZoomOut,
[Btn_M3] = PP_BindKind_Pan,
#if IsRtcEnabled
[Btn_ForwardSlash] = PP_BindKind_ResetDebugSteps,
[Btn_Comma] = PP_BindKind_DecrementDebugSteps,
[Btn_Period] = PP_BindKind_IncrementDebugSteps
[Btn_ForwardSlash] = PP_BindKind_ResetDebugSteps,
[Btn_Comma] = PP_BindKind_DecrementDebugSteps,
[Btn_Period] = PP_BindKind_IncrementDebugSteps
#endif
};
@ -104,9 +104,9 @@ Global Readonly PP_BindKind g_binds[Btn_Count] = {
Struct(PP_SecondsStat)
{
u64 last_second_start;
u64 last_second_end;
u64 last_second;
u64 last_second_start;
u64 last_second_end;
u64 last_second;
};
////////////////////////////////////////////////////////////
@ -114,12 +114,12 @@ Struct(PP_SecondsStat)
Struct(PP_ConsoleLog)
{
String msg;
i32 level;
i32 color_index;
DateTime datetime;
PP_ConsoleLog *prev;
PP_ConsoleLog *next;
String msg;
i32 level;
i32 color_index;
DateTime datetime;
PP_ConsoleLog *prev;
PP_ConsoleLog *next;
};
////////////////////////////////////////////////////////////
@ -127,17 +127,17 @@ Struct(PP_ConsoleLog)
Struct(PP_DecodeQueueNode)
{
PP_Client *client;
u64 tick;
u64 base_tick;
String tmp_encoded;
PP_DecodeQueueNode *next;
PP_Client *client;
u64 tick;
u64 base_tick;
String tmp_encoded;
PP_DecodeQueueNode *next;
};
Struct(PP_DecodeQueue)
{
PP_DecodeQueueNode *first;
PP_DecodeQueueNode *last;
PP_DecodeQueueNode *first;
PP_DecodeQueueNode *last;
};
////////////////////////////////////////////////////////////
@ -145,137 +145,137 @@ Struct(PP_DecodeQueue)
Struct(PP_BindState)
{
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_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_releases; /* How many times was this bind released since last 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_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_releases; /* How many times was this bind released since last frame */
};
Struct(PP_SharedUserState)
{
Atomic32 shutdown;
Atomic32 shutdown;
Fence shutdown_jobs_fence;
u64 shutdown_jobs_count;
Fence shutdown_jobs_fence;
u64 shutdown_jobs_count;
Arena *arena;
String connect_address_str;
Arena *arena;
String connect_address_str;
PP_ClientStore *user_client_store;
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_Snapshot *ss_blended; /* Points to blended snapshot contained in blended client */
PP_ClientStore *user_client_store;
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_Snapshot *ss_blended; /* Points to blended snapshot contained in blended client */
u64 user_tick;
u64 window_os_gen;
u64 user_tick;
u64 window_os_gen;
//- Usage stats
i64 last_second_reset_ns;
PP_SecondsStat net_bytes_read;
PP_SecondsStat net_bytes_sent;
//- Usage stats
i64 last_second_reset_ns;
PP_SecondsStat net_bytes_read;
PP_SecondsStat net_bytes_sent;
//- Renderer gbuffers
GPU_Resource *albedo;
GPU_Resource *emittance;
GPU_Resource *emittance_flood_read;
GPU_Resource *emittance_flood_target;
GPU_Resource *shade_read;
GPU_Resource *shade_target;
//- Renderer gbuffers
GPU_Resource *albedo;
GPU_Resource *emittance;
GPU_Resource *emittance_flood_read;
GPU_Resource *emittance_flood_target;
GPU_Resource *shade_read;
GPU_Resource *shade_target;
//- Renderer transient buffers
GPU_TransientBuffer material_instances_tbuff;
GPU_TransientBuffer grids_tbuff;
Arena *material_instances_arena;
Arena *grids_arena;
//- Renderer transient buffers
GPU_TransientBuffer material_instances_tbuff;
GPU_TransientBuffer grids_tbuff;
Arena *material_instances_arena;
Arena *grids_arena;
//- Renderer state
RandState frame_rand;
u64 frame_index;
i64 gpu_submit_fence_target;
//- Renderer state
RandState frame_rand;
u64 frame_index;
i64 gpu_submit_fence_target;
//- Bind state
PP_BindState bind_states[PP_BindKind_Count];
//- Bind state
PP_BindState bind_states[PP_BindKind_Count];
//- Window -> user
Mutex sys_window_events_mutex;
Arena *sys_window_events_arena;
//- Window -> user
Mutex sys_window_events_mutex;
Arena *sys_window_events_arena;
//- User -> sim
Mutex user_sim_cmd_mutex;
PP_ControlData user_sim_cmd_control;
PP_EntKey user_hovered_ent;
u64 last_user_sim_cmd_gen;
u64 user_sim_cmd_gen;
//- User -> sim
Mutex user_sim_cmd_mutex;
PP_ControlData user_sim_cmd_control;
PP_EntKey user_hovered_ent;
u64 last_user_sim_cmd_gen;
u64 user_sim_cmd_gen;
Atomic32 user_paused;
Atomic32 user_paused_steps;
Atomic32 user_paused;
Atomic32 user_paused_steps;
//- Sim -> user
Mutex local_to_user_client_mutex;
PP_ClientStore *local_to_user_client_store;
PP_Client *local_to_user_client;
i64 local_to_user_client_publish_dt_ns;
i64 local_to_user_client_publish_time_ns;
//- Sim -> user
Mutex local_to_user_client_mutex;
PP_ClientStore *local_to_user_client_store;
PP_Client *local_to_user_client;
i64 local_to_user_client_publish_dt_ns;
i64 local_to_user_client_publish_time_ns;
//- Local sim -> user rolling window of publish time deltas
i64 last_local_to_user_snapshot_published_at_ns;
i64 average_local_to_user_snapshot_publish_dt_ns;
//- Local sim -> user rolling window of publish time deltas
i64 last_local_to_user_snapshot_published_at_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 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 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_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;
i64 local_sim_last_known_time_ns;
u64 local_sim_last_known_tick;
i64 local_sim_last_known_time_ns;
i64 real_dt_ns;
i64 real_time_ns;
i64 real_dt_ns;
i64 real_time_ns;
//- Window
//- Window
String window_restore;
String window_restore;
//////////////////////////////
//- Persist start
StructRegion(AUTO_PERSIST_START);
//////////////////////////////
//- Persist start
StructRegion(AUTO_PERSIST_START);
//- Debug ui
//- Debug ui
b32 ui_debug;
b32 ui_debug;
PP_EntKey debug_following;
Vec2 debug_camera_pan_start;
b32 debug_camera_panning;
b32 debug_camera;
PP_EntKey debug_following;
Vec2 debug_camera_pan_start;
b32 debug_camera_panning;
b32 debug_camera;
b32 lister_active;
Vec2 lister_pos;
b32 lister_active;
Vec2 lister_pos;
b32 debug_draw;
b32 debug_console;
b32 debug_draw;
b32 debug_console;
//- Per frame
//- Per frame
Vec2I32 screen_size;
Vec2 screen_cursor;
Vec2I32 screen_size;
Vec2 screen_cursor;
Xform ui_to_screen_xf;
Vec2I32 ui_size;
Vec2 ui_cursor;
Xform ui_to_screen_xf;
Vec2I32 ui_size;
Vec2 ui_cursor;
Xform render_to_ui_xf;
Vec2I32 render_size;
Xform render_to_ui_xf;
Vec2I32 render_size;
Xform world_to_render_xf;
Xform world_to_ui_xf;
Vec2 world_cursor;
Xform world_to_render_xf;
Xform world_to_ui_xf;
Vec2 world_cursor;
Vec2 focus_send;
Vec2 focus_send;
StructRegion(AUTO_PERSIST_END);
//- Persist end
//////////////////////////////
StructRegion(AUTO_PERSIST_END);
//- Persist end
//////////////////////////////
} extern PP_shared_user_state;
@ -284,7 +284,7 @@ Struct(PP_SharedUserState)
Struct(PP_SwappedUserState)
{
PP_SharedUserState s;
PP_SharedUserState s;
};
////////////////////////////////////////////////////////////

View File

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

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