res refactor progress
This commit is contained in:
parent
db8a9deba9
commit
db9d3677d5
@ -5,8 +5,8 @@ if not exist build mkdir build
|
|||||||
pushd build
|
pushd build
|
||||||
|
|
||||||
set program_build_cmd=meta.exe %*
|
set program_build_cmd=meta.exe %*
|
||||||
set meta_build_cmd=cl.exe ../src/meta/meta.c /Od /Z7 /nologo /link /DEBUG:FULL /INCREMENTAL:NO
|
set meta_build_cmd=cl.exe ../src/meta/meta.c /Od /Z7 /nologo /diagnostics:column /link /DEBUG:FULL /INCREMENTAL:NO
|
||||||
set meta_rebuild_code=995692758
|
set meta_rebuild_code=1317212284
|
||||||
|
|
||||||
::- Meta build
|
::- Meta build
|
||||||
:meta_build
|
:meta_build
|
||||||
|
|||||||
@ -414,7 +414,7 @@ void __asan_unpoison_memory_region(void const volatile *add, size_t);
|
|||||||
# define alignof(type) __alignof(type)
|
# define alignof(type) __alignof(type)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//- sizeof_field
|
//- field sizeof
|
||||||
#define sizeof_field(type, field) sizeof(((type *)0)->field)
|
#define sizeof_field(type, field) sizeof(((type *)0)->field)
|
||||||
|
|
||||||
//- countof
|
//- countof
|
||||||
@ -635,13 +635,13 @@ Struct(StringList)
|
|||||||
//~ Fiber id
|
//~ Fiber id
|
||||||
|
|
||||||
#if PlatformIsWindows
|
#if PlatformIsWindows
|
||||||
# define FiberId *(i16 *)(void *)(volatile u64)__readgsqword(32)
|
# define FiberId (*(i16 *)(void *)(volatile u64)__readgsqword(32))
|
||||||
#else
|
#else
|
||||||
# error FiberId not implemented
|
# error FiberId not implemented
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define MaxFibers 1024
|
#define MaxFibers 1024
|
||||||
StaticAssert(MaxFibers < I16Max); /* Fiber id type should fit max threads */
|
StaticAssert(MaxFibers < I16Max); /* FiberId type should fit MaxFibers */
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ Exit callback types
|
//~ Exit callback types
|
||||||
|
|||||||
@ -18,7 +18,6 @@
|
|||||||
# include "base_math.h"
|
# include "base_math.h"
|
||||||
# include "base_rand.h"
|
# include "base_rand.h"
|
||||||
# include "base_util.h"
|
# include "base_util.h"
|
||||||
# include "base_incbin.h"
|
|
||||||
# include "base_entry.h"
|
# include "base_entry.h"
|
||||||
#elif LanguageIsGpu
|
#elif LanguageIsGpu
|
||||||
# include "base_math_gpu.h"
|
# include "base_math_gpu.h"
|
||||||
@ -36,7 +35,6 @@
|
|||||||
# include "base_buddy.c"
|
# include "base_buddy.c"
|
||||||
# include "base_math.c"
|
# include "base_math.c"
|
||||||
# include "base_rand.c"
|
# include "base_rand.c"
|
||||||
# include "base_incbin.c"
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//- Win32 impl
|
//- Win32 impl
|
||||||
|
|||||||
@ -1,78 +0,0 @@
|
|||||||
#if PlatformIsWindows
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ Incbin
|
|
||||||
|
|
||||||
/* Find first resource with `type` and return the data in `udata`. */
|
|
||||||
BOOL IncbinEnumerateResourceNamesFunc(HMODULE module, LPCWSTR type, LPWSTR wstr_entry_name, LONG_PTR udata)
|
|
||||||
{
|
|
||||||
TempArena scratch = BeginScratchNoConflict();
|
|
||||||
IncbinRcSearchParams *params = (IncbinRcSearchParams *)udata;
|
|
||||||
String entry_name_lower = LowerString(scratch.arena, StringFromWstrNoLimit(scratch.arena, (LPWSTR)wstr_entry_name));
|
|
||||||
params->found = 0;
|
|
||||||
params->data = STRING(0, 0);
|
|
||||||
if (EqString(entry_name_lower, params->name_lower))
|
|
||||||
{
|
|
||||||
HRSRC hres = FindResourceW(module, wstr_entry_name, type);
|
|
||||||
if (hres)
|
|
||||||
{
|
|
||||||
HGLOBAL hg = LoadResource(module, hres);
|
|
||||||
if (hg)
|
|
||||||
{
|
|
||||||
params->found = 1;
|
|
||||||
params->data.len = SizeofResource(module, hres);
|
|
||||||
params->data.text = LockResource(hg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
EndScratch(scratch);
|
|
||||||
return !params->found;
|
|
||||||
}
|
|
||||||
|
|
||||||
String StringFromIncbinRcResource(IncbinRcResource *inc)
|
|
||||||
{
|
|
||||||
IncbinStatus state = Atomic32Fetch(&inc->state);
|
|
||||||
if (state != IncbinStatus_Searched)
|
|
||||||
{
|
|
||||||
TempArena scratch = BeginScratchNoConflict();
|
|
||||||
|
|
||||||
if (state == IncbinStatus_Unsearched)
|
|
||||||
{
|
|
||||||
IncbinStatus v = Atomic32FetchTestSet(&inc->state, state, IncbinStatus_Searching);
|
|
||||||
if (v == state)
|
|
||||||
{
|
|
||||||
/* Search RC file for the resource name */
|
|
||||||
String name_lower = LowerString(scratch.arena, inc->rc_name);
|
|
||||||
IncbinRcSearchParams params = { .name_lower = name_lower };
|
|
||||||
EnumResourceNamesW(0, RT_RCDATA, &IncbinEnumerateResourceNamesFunc, (LONG_PTR)¶ms);
|
|
||||||
if (!params.found)
|
|
||||||
{
|
|
||||||
/* FIXME: enable this */
|
|
||||||
//Panic(StringFormat(scratch.arena,
|
|
||||||
// Lit("INCBIN include not found in RC file: \"%F\""),
|
|
||||||
// FmtString(inc->rc_name)));
|
|
||||||
(*(volatile int *)0) = 0;
|
|
||||||
}
|
|
||||||
inc->data = params.data;
|
|
||||||
state = IncbinStatus_Searched;
|
|
||||||
Atomic32FetchSet(&inc->state, state);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
state = v;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Spin while another thread searches */
|
|
||||||
while (state != IncbinStatus_Searched)
|
|
||||||
{
|
|
||||||
_mm_pause();
|
|
||||||
state = Atomic32Fetch(&inc->state);
|
|
||||||
}
|
|
||||||
|
|
||||||
EndScratch(scratch);
|
|
||||||
}
|
|
||||||
return inc->data;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* PlatformIsWindows */
|
|
||||||
@ -1,78 +0,0 @@
|
|||||||
#if PlatformIsWindows
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ Windows incbin types
|
|
||||||
|
|
||||||
Struct(IncbinRcSearchParams)
|
|
||||||
{
|
|
||||||
/* In */
|
|
||||||
String name_lower;
|
|
||||||
/* Out */
|
|
||||||
b32 found;
|
|
||||||
String data;
|
|
||||||
};
|
|
||||||
|
|
||||||
Enum(IncbinStatus)
|
|
||||||
{
|
|
||||||
IncbinStatus_Unsearched,
|
|
||||||
IncbinStatus_Searching,
|
|
||||||
IncbinStatus_Searched
|
|
||||||
};
|
|
||||||
|
|
||||||
Struct(IncbinRcResource)
|
|
||||||
{
|
|
||||||
Atomic32 state;
|
|
||||||
String rc_name;
|
|
||||||
String data;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ Msvc incbin operations
|
|
||||||
|
|
||||||
BOOL IncbinEnumerateResourceNamesFunc(HMODULE module, LPCWSTR type, LPWSTR wstr_entry_name, LONG_PTR udata);
|
|
||||||
String StringFromIncbinRcResource(IncbinRcResource *inc);
|
|
||||||
|
|
||||||
/* NOTE: Msvc doesn't have an Inline assembler that can include binary data.
|
|
||||||
* So instead these macros will trigger a lookup into the embedded RC file for
|
|
||||||
* entries matched by name (this requires the build system to generate and link
|
|
||||||
* RC file).
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define IncbinInclude(var, _rc_name) static IncbinRcResource _incbin_ ## var = { .rc_name = LitNoCast((_rc_name)) }
|
|
||||||
#define IncbinGet(var) StringFromIncbinRcResource(&_incbin_ ## var)
|
|
||||||
|
|
||||||
String StringFromIncbinRcResource(struct IncbinRcResource *inc);
|
|
||||||
|
|
||||||
#else /* PlatformIsWindows */
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ Clang incbin operations
|
|
||||||
|
|
||||||
#if PlatformIsWindows
|
|
||||||
# define IncbinSection ".rdata, \"dr\""
|
|
||||||
#elif PlatformIsMac
|
|
||||||
# define IncbinSection "__TEXT,__const"
|
|
||||||
#else
|
|
||||||
# define IncbinSection ".rodata"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Includes raw binary data into the executable. */
|
|
||||||
/* https://gist.github.com/mmozeiko/ed9655cf50341553d282 */
|
|
||||||
#define IncbinInclude(var, filename) \
|
|
||||||
__asm__(".section " IncbinSection "\n" \
|
|
||||||
".global _incbin_" Stringize(var) "_start\n" \
|
|
||||||
".balign 16\n" \
|
|
||||||
"_incbin_" Stringize(var) "_start:\n" \
|
|
||||||
".incbin \"" filename "\"\n" \
|
|
||||||
\
|
|
||||||
".global _incbin_" Stringize(var) "_end\n" \
|
|
||||||
".balign 1\n" \
|
|
||||||
"_incbin_" Stringize(var) "_end:\n" \
|
|
||||||
); \
|
|
||||||
extern __attribute((aligned(16))) const char _incbin_ ## var ## _start[]; \
|
|
||||||
extern const char _incbin_ ## var ## _end[]
|
|
||||||
|
|
||||||
/* Retrieve a string from included data using the variable supplied to IncbinInclude */
|
|
||||||
#define IncbinGet(var) StringFromPointers(_incbin_ ## var ## _start, _incbin_ ## var ## _end)
|
|
||||||
|
|
||||||
#endif /* CompilerIsClang */
|
|
||||||
@ -494,7 +494,7 @@ f32 PowF32(f32 a, f32 b)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* a is negative */
|
/* a is negative */
|
||||||
f32 res_sign = RoundF32ToI32(b) % 2 == 0 ? 1 : -1;
|
i32 res_sign = RoundF32ToI32(b) % 2 == 0 ? 1 : -1;
|
||||||
return ExpF32(LnF32(-a) * b) * res_sign;
|
return ExpF32(LnF32(-a) * b) * res_sign;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -537,8 +537,8 @@ f32 ReduceToPio4(f32 x, i32 *octant_out)
|
|||||||
|
|
||||||
if (x <= ((1 << 24) - 1))
|
if (x <= ((1 << 24) - 1))
|
||||||
{
|
{
|
||||||
octant = x * (4 / Pi); /* Integer part of x/(Pi/4) */
|
octant = (i32)(x * (4 / Pi)); /* Integer part of x/(Pi/4) */
|
||||||
f32 y = octant;
|
f32 y = (f32)octant;
|
||||||
if (octant & 1)
|
if (octant & 1)
|
||||||
{
|
{
|
||||||
octant += 1;
|
octant += 1;
|
||||||
|
|||||||
@ -55,6 +55,7 @@ AlignedStruct(W32_WaitList, 64)
|
|||||||
i32 num_waiters;
|
i32 num_waiters;
|
||||||
W32_WaitList *next_in_bin;
|
W32_WaitList *next_in_bin;
|
||||||
W32_WaitList *prev_in_bin;
|
W32_WaitList *prev_in_bin;
|
||||||
|
u8 pad[32];
|
||||||
};
|
};
|
||||||
StaticAssert(alignof(W32_WaitList) == 64); /* Avoid false sharing */
|
StaticAssert(alignof(W32_WaitList) == 64); /* Avoid false sharing */
|
||||||
|
|
||||||
@ -123,6 +124,8 @@ AlignedStruct(W32_Fiber, 64)
|
|||||||
/* ---------------------------------------------------- */
|
/* ---------------------------------------------------- */
|
||||||
GenericJobDesc *job_desc; /* 08 bytes */
|
GenericJobDesc *job_desc; /* 08 bytes */
|
||||||
/* ---------------------------------------------------- */
|
/* ---------------------------------------------------- */
|
||||||
|
u8 _pad0[8]; /* 08 bytes (padding) */
|
||||||
|
/* ---------------------------------------------------- */
|
||||||
/* -------------------- Cache line -------------------- */
|
/* -------------------- Cache line -------------------- */
|
||||||
/* ---------------------------------------------------- */
|
/* ---------------------------------------------------- */
|
||||||
i32 job_id; /* 04 bytes */
|
i32 job_id; /* 04 bytes */
|
||||||
@ -131,7 +134,7 @@ AlignedStruct(W32_Fiber, 64)
|
|||||||
/* ---------------------------------------------------- */
|
/* ---------------------------------------------------- */
|
||||||
W32_YieldParam *yield_param; /* 08 bytes */
|
W32_YieldParam *yield_param; /* 08 bytes */
|
||||||
/* ---------------------------------------------------- */
|
/* ---------------------------------------------------- */
|
||||||
u8 _pad0[48]; /* 48 bytes (padding) */
|
u8 _pad1[48]; /* 48 bytes (padding) */
|
||||||
|
|
||||||
};
|
};
|
||||||
StaticAssert(sizeof(W32_Fiber) == 128); /* Padding validation (increase if necessary) */
|
StaticAssert(sizeof(W32_Fiber) == 128); /* Padding validation (increase if necessary) */
|
||||||
|
|||||||
@ -17,12 +17,6 @@
|
|||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* If we are not compiling in developer mode, assume resources are embedded as
|
|
||||||
* a tar archive in the executable. Otherwise, assume resources are files on
|
|
||||||
* disk. */
|
|
||||||
#define RESOURCES_EMBEDDED (!DeveloperIsEnabled)
|
|
||||||
#define RESOURCE_RELOADING (DeveloperIsEnabled && !RESOURCES_EMBEDDED)
|
|
||||||
|
|
||||||
#define DEFAULT_CAMERA_WIDTH (16)
|
#define DEFAULT_CAMERA_WIDTH (16)
|
||||||
#define DEFAULT_CAMERA_HEIGHT ((f64)DEFAULT_CAMERA_WIDTH / (16.0 / 9.0))
|
#define DEFAULT_CAMERA_HEIGHT ((f64)DEFAULT_CAMERA_WIDTH / (16.0 / 9.0))
|
||||||
|
|
||||||
|
|||||||
@ -25,27 +25,27 @@ JobDef(F_LoadJob, sig, _)
|
|||||||
0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF
|
0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF
|
||||||
};
|
};
|
||||||
|
|
||||||
String path = sig->path;
|
R_Tag resource = sig->resource;
|
||||||
|
String name = R_NameFromTag(resource);
|
||||||
f32 point_size = sig->point_size;
|
f32 point_size = sig->point_size;
|
||||||
AC_Asset *asset = sig->asset;
|
AC_Asset *asset = sig->asset;
|
||||||
|
|
||||||
P_LogInfoF("Loading font \"%F\" (point size %F)", FmtString(path), FmtFloat((f64)point_size));
|
P_LogInfoF("Loading font \"%F\" (point size %F)", FmtString(name), FmtFloat((f64)point_size));
|
||||||
i64 start_ns = TimeNs();
|
i64 start_ns = TimeNs();
|
||||||
|
|
||||||
Assert(StringEndsWith(path, Lit(".ttf")));
|
Assert(StringEndsWith(name, Lit(".ttf")));
|
||||||
Assert(countof(font_codes) < F_LookupTableSize);
|
Assert(countof(font_codes) < F_LookupTableSize);
|
||||||
|
|
||||||
/* Decode */
|
/* Decode */
|
||||||
RES_Resource res = RES_OpenResource(path);
|
String resource_data = R_DataFromTag(resource);
|
||||||
if (!RES_ResourceExists(&res))
|
if (resource_data.len == 0)
|
||||||
{
|
{
|
||||||
/* FIME: Load baked font instead of panicking */
|
/* FIME: Load baked font instead of panicking */
|
||||||
Panic(StringFormat(scratch.arena,
|
Panic(StringFormat(scratch.arena,
|
||||||
Lit("Font \"%F\" not found"),
|
Lit("Font \"%F\" not found"),
|
||||||
FmtString(path)));
|
FmtString(name)));
|
||||||
}
|
}
|
||||||
TTF_Result result = TTF_Decode(scratch.arena, RES_GetResourceData(&res), point_size, font_codes, countof(font_codes));
|
TTF_Result result = TTF_Decode(scratch.arena, resource_data, point_size, font_codes, countof(font_codes));
|
||||||
RES_CloseResource(&res);
|
|
||||||
|
|
||||||
/* Send texture to GPU */
|
/* Send texture to GPU */
|
||||||
GPU_Resource *texture = 0;
|
GPU_Resource *texture = 0;
|
||||||
@ -80,7 +80,7 @@ JobDef(F_LoadJob, sig, _)
|
|||||||
{
|
{
|
||||||
Panic(StringFormat(scratch.arena,
|
Panic(StringFormat(scratch.arena,
|
||||||
Lit("Parsed 0 glyphs from font \"%F\"!"),
|
Lit("Parsed 0 glyphs from font \"%F\"!"),
|
||||||
FmtString(path)));
|
FmtString(name)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Copy glyphs from decode result */
|
/* Copy glyphs from decode result */
|
||||||
@ -94,7 +94,7 @@ JobDef(F_LoadJob, sig, _)
|
|||||||
font->lookup[codepoint] = result.cache_indices[i];
|
font->lookup[codepoint] = result.cache_indices[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
P_LogSuccessF("Loaded font \"%F\" (point size %F) in %F seconds", FmtString(path), FmtFloat((f64)point_size), FmtFloat(SecondsFromNs(TimeNs() - start_ns)));
|
P_LogSuccessF("Loaded font \"%F\" (point size %F) in %F seconds", FmtString(name), FmtFloat((f64)point_size), FmtFloat(SecondsFromNs(TimeNs() - start_ns)));
|
||||||
AC_MarkReady(asset, font);
|
AC_MarkReady(asset, font);
|
||||||
|
|
||||||
EndScratch(scratch);
|
EndScratch(scratch);
|
||||||
@ -104,15 +104,16 @@ JobDef(F_LoadJob, sig, _)
|
|||||||
//~ Load
|
//~ Load
|
||||||
|
|
||||||
/* Returns the asset from the asset cache */
|
/* Returns the asset from the asset cache */
|
||||||
AC_Asset *F_LoadAsset(String path, f32 point_size, b32 wait)
|
AC_Asset *F_LoadAsset(R_Tag resource, f32 point_size, b32 wait)
|
||||||
{
|
{
|
||||||
__prof;
|
__prof;
|
||||||
TempArena scratch = BeginScratchNoConflict();
|
TempArena scratch = BeginScratchNoConflict();
|
||||||
|
String name = R_NameFromTag(resource);
|
||||||
|
|
||||||
/* Concatenate point_size to path for key */
|
/* Concatenate point_size to name for key */
|
||||||
String key = StringFormat(scratch.arena,
|
String key = StringFormat(scratch.arena,
|
||||||
Lit("%F%F_font"),
|
Lit("%F%F_font"),
|
||||||
FmtString(path),
|
FmtString(name),
|
||||||
FmtFloatP((f64)point_size, 1));
|
FmtFloatP((f64)point_size, 1));
|
||||||
u64 hash = AC_HashFromKey(key);
|
u64 hash = AC_HashFromKey(key);
|
||||||
b32 is_first_touch;
|
b32 is_first_touch;
|
||||||
@ -123,7 +124,7 @@ AC_Asset *F_LoadAsset(String path, f32 point_size, b32 wait)
|
|||||||
AC_MarkLoading(asset);
|
AC_MarkLoading(asset);
|
||||||
F_LoadJob_Desc *desc = PushJobDesc(F_LoadJob, .pool = JobPool_Background, .priority = JobPriority_Low);
|
F_LoadJob_Desc *desc = PushJobDesc(F_LoadJob, .pool = JobPool_Background, .priority = JobPriority_Low);
|
||||||
desc->sig->asset = asset;
|
desc->sig->asset = asset;
|
||||||
desc->sig->path = PushString(desc->arena, path);
|
desc->sig->resource = resource;
|
||||||
desc->sig->point_size = point_size;
|
desc->sig->point_size = point_size;
|
||||||
RunJobEx((GenericJobDesc *)desc);
|
RunJobEx((GenericJobDesc *)desc);
|
||||||
if (wait)
|
if (wait)
|
||||||
@ -136,18 +137,18 @@ AC_Asset *F_LoadAsset(String path, f32 point_size, b32 wait)
|
|||||||
return asset;
|
return asset;
|
||||||
}
|
}
|
||||||
|
|
||||||
F_Font *F_LoadFontAsync(String path, f32 point_size)
|
F_Font *F_LoadFontAsync(R_Tag resource, f32 point_size)
|
||||||
{
|
{
|
||||||
__prof;
|
__prof;
|
||||||
AC_Asset *asset = F_LoadAsset(path, point_size, 0);
|
AC_Asset *asset = F_LoadAsset(resource, point_size, 0);
|
||||||
F_Font *f = (F_Font *)AC_DataFromStore(asset);
|
F_Font *f = (F_Font *)AC_DataFromStore(asset);
|
||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
|
|
||||||
F_Font *F_LoadFontWait(String path, f32 point_size)
|
F_Font *F_LoadFontWait(R_Tag resource, f32 point_size)
|
||||||
{
|
{
|
||||||
__prof;
|
__prof;
|
||||||
AC_Asset *asset = F_LoadAsset(path, point_size, 1);
|
AC_Asset *asset = F_LoadAsset(resource, point_size, 1);
|
||||||
AC_YieldOnAssetReady(asset);
|
AC_YieldOnAssetReady(asset);
|
||||||
F_Font *f = (F_Font *)AC_DataFromStore(asset);
|
F_Font *f = (F_Font *)AC_DataFromStore(asset);
|
||||||
return f;
|
return f;
|
||||||
|
|||||||
@ -27,14 +27,14 @@ Struct(F_Font)
|
|||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ Font load job
|
//~ Font load job
|
||||||
|
|
||||||
JobDecl(F_LoadJob, { AC_Asset *asset; f32 point_size; String path; });
|
JobDecl(F_LoadJob, { AC_Asset *asset; f32 point_size; R_Tag resource; });
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ Font load operations
|
//~ Font load operations
|
||||||
|
|
||||||
AC_Asset *F_LoadAsset(String path, f32 point_size, b32 wait);
|
AC_Asset *F_LoadAsset(R_Tag resource, f32 point_size, b32 wait);
|
||||||
F_Font *F_LoadFontAsync(String path, f32 point_size);
|
F_Font *F_LoadFontAsync(R_Tag resource, f32 point_size);
|
||||||
F_Font *F_LoadFontWait(String path, f32 point_size);
|
F_Font *F_LoadFontWait(R_Tag resource, f32 point_size);
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ Font data operations
|
//~ Font data operations
|
||||||
|
|||||||
@ -3,8 +3,8 @@
|
|||||||
//- Dependencies
|
//- Dependencies
|
||||||
@Dep ttf
|
@Dep ttf
|
||||||
@Dep gpu
|
@Dep gpu
|
||||||
@Dep resource
|
|
||||||
@Dep asset_cache
|
@Dep asset_cache
|
||||||
|
@Dep res
|
||||||
|
|
||||||
//- Api
|
//- Api
|
||||||
@IncludeC font.h
|
@IncludeC font.h
|
||||||
|
|||||||
@ -1,19 +0,0 @@
|
|||||||
/* This is the file that actually includes binary data meant to be embedded in
|
|
||||||
* the executable. Embedded files should be added as dependencies to this source
|
|
||||||
* file via the build system to ensure this translation unit is recompiled upon
|
|
||||||
* changes to an embedded file. */
|
|
||||||
|
|
||||||
#if RESOURCES_EMBEDDED
|
|
||||||
IncbinInclude(res_tar, IncbinDir "res.tar");
|
|
||||||
String INC_GetResTar(void)
|
|
||||||
{
|
|
||||||
return IncbinGet(res_tar);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
IncbinInclude(dxc_tar, IncbinDir "dxc.tar");
|
|
||||||
String INC_GetDxcTar(void)
|
|
||||||
{
|
|
||||||
return IncbinGet(dxc_tar);
|
|
||||||
}
|
|
||||||
@ -1,5 +0,0 @@
|
|||||||
#if RESOURCES_EMBEDDED
|
|
||||||
String INC_GetResTar(void);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
String INC_GetDxcTar(void);
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
@Layer inc
|
|
||||||
|
|
||||||
//- Api
|
|
||||||
@IncludeC inc.h
|
|
||||||
|
|
||||||
//- Impl
|
|
||||||
@IncludeC inc.c
|
|
||||||
@ -1,9 +1,9 @@
|
|||||||
/* TODO: Move decls to meta.h */
|
/* TODO: Move decls to meta.h */
|
||||||
|
|
||||||
#define MetaRebuildCode 0x3b5910d6
|
#define MetaRebuildCode 1317212284
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ Metaprogram default compiler definitions
|
//~ Default base layer compiler definitions
|
||||||
|
|
||||||
#ifndef IsConsoleApp
|
#ifndef IsConsoleApp
|
||||||
# define IsConsoleApp 1
|
# define IsConsoleApp 1
|
||||||
@ -739,13 +739,12 @@ Error *PushError(Arena *arena, ErrorList *list, String file, i64 pos, String s)
|
|||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ Entry point
|
//~ Build
|
||||||
|
|
||||||
void StartupMeta(void)
|
void StartupMeta(void)
|
||||||
{
|
{
|
||||||
Arena *arena = AcquireArena(Gibi(64));
|
Arena *arena = AcquireArena(Gibi(64));
|
||||||
|
|
||||||
i32 ret = 0;
|
|
||||||
ErrorList errors = ZI;
|
ErrorList errors = ZI;
|
||||||
|
|
||||||
//- Unpack args
|
//- Unpack args
|
||||||
@ -864,7 +863,7 @@ void StartupMeta(void)
|
|||||||
}
|
}
|
||||||
/* Write to file */
|
/* Write to file */
|
||||||
String c_out = StringFromList(arena, c_out_lines, Lit("\n"));
|
String c_out = StringFromList(arena, c_out_lines, Lit("\n"));
|
||||||
F_ClearWrite(Lit("gen.c"), c_out);
|
F_ClearWrite(Lit("pp_gen.c"), c_out);
|
||||||
}
|
}
|
||||||
|
|
||||||
//- Echo meta errors
|
//- Echo meta errors
|
||||||
@ -910,11 +909,22 @@ void StartupMeta(void)
|
|||||||
|
|
||||||
//- Msvc
|
//- Msvc
|
||||||
{
|
{
|
||||||
PushStringToList(arena, &msvc_compiler_flags, Lit("-Zi"));
|
PushStringToList(arena, &msvc_compiler_flags, Lit("-Z7"));
|
||||||
PushStringToList(arena, &msvc_compiler_flags, Lit("-DEBUG"));
|
PushStringToList(arena, &msvc_compiler_flags, Lit("-DEBUG:FULL"));
|
||||||
PushStringToList(arena, &msvc_compiler_flags, Lit("-Fo:gen.obj"));
|
PushStringToList(arena, &msvc_compiler_flags, Lit("-Fo:pp_pp_gen.obj"));
|
||||||
PushStringToList(arena, &msvc_compiler_flags, Lit("-Fe:pp.exe"));
|
PushStringToList(arena, &msvc_compiler_flags, Lit("-Fe:pp.exe"));
|
||||||
PushStringToList(arena, &msvc_compiler_flags, Lit("-nologo"));
|
PushStringToList(arena, &msvc_compiler_flags, Lit("-nologo"));
|
||||||
|
PushStringToList(arena, &msvc_compiler_flags, Lit("-diagnostics:column"));
|
||||||
|
/* Enable warnings */
|
||||||
|
PushStringToList(arena, &msvc_compiler_flags, Lit("-W4"));
|
||||||
|
PushStringToList(arena, &msvc_compiler_flags, Lit("-we4013")); /* function undefined; assuming extern returning int */
|
||||||
|
/* Disable warnings */
|
||||||
|
PushStringToList(arena, &msvc_compiler_flags, Lit("-wd4244")); /* function': conversion from 'int' to 'f32', possible loss of data */
|
||||||
|
PushStringToList(arena, &msvc_compiler_flags, Lit("-wd4201")); /* nonstandard extension used: nameless struct/union */
|
||||||
|
PushStringToList(arena, &msvc_compiler_flags, Lit("-wd4324")); /* structure was padded due to alignment specifier */
|
||||||
|
PushStringToList(arena, &msvc_compiler_flags, Lit("-wd4100")); /* unreferenced parameter */
|
||||||
|
PushStringToList(arena, &msvc_compiler_flags, Lit("-wd4189")); /* local variable is initialized but not referenced */
|
||||||
|
PushStringToList(arena, &msvc_compiler_flags, Lit("-wd4200")); /* nonstandard extension used: zero-sized array in struct/union */
|
||||||
}
|
}
|
||||||
|
|
||||||
//- Clang
|
//- Clang
|
||||||
@ -924,13 +934,14 @@ void StartupMeta(void)
|
|||||||
PushStringToList(arena, &clang_compiler_flags, Lit("-g -gcodeview"));
|
PushStringToList(arena, &clang_compiler_flags, Lit("-g -gcodeview"));
|
||||||
PushStringToList(arena, &clang_compiler_flags, Lit("-O0"));
|
PushStringToList(arena, &clang_compiler_flags, Lit("-O0"));
|
||||||
PushStringToList(arena, &clang_compiler_flags, Lit("-msse4.2"));
|
PushStringToList(arena, &clang_compiler_flags, Lit("-msse4.2"));
|
||||||
/* Warnings */
|
/* Enable warnings */
|
||||||
PushStringToList(arena, &clang_compiler_flags, Lit("-Wall"));
|
PushStringToList(arena, &clang_compiler_flags, Lit("-Wall"));
|
||||||
PushStringToList(arena, &clang_compiler_flags, Lit("-Wframe-larger-than=65536"));
|
PushStringToList(arena, &clang_compiler_flags, Lit("-Wframe-larger-than=65536"));
|
||||||
PushStringToList(arena, &clang_compiler_flags, Lit("-Wmissing-prototypes"));
|
PushStringToList(arena, &clang_compiler_flags, Lit("-Wmissing-prototypes"));
|
||||||
PushStringToList(arena, &clang_compiler_flags, Lit("-Wunused-variable"));
|
PushStringToList(arena, &clang_compiler_flags, Lit("-Wunused-variable"));
|
||||||
PushStringToList(arena, &clang_compiler_flags, Lit("-Wunused-but-set-variable"));
|
PushStringToList(arena, &clang_compiler_flags, Lit("-Wunused-but-set-variable"));
|
||||||
PushStringToList(arena, &clang_compiler_flags, Lit("-Wunused-parameter"));
|
PushStringToList(arena, &clang_compiler_flags, Lit("-Wunused-parameter"));
|
||||||
|
/* Disable warnings */
|
||||||
PushStringToList(arena, &clang_compiler_flags, Lit("-Wno-initializer-overrides"));
|
PushStringToList(arena, &clang_compiler_flags, Lit("-Wno-initializer-overrides"));
|
||||||
PushStringToList(arena, &clang_compiler_flags, Lit("-Wno-microsoft-enum-forward-reference"));
|
PushStringToList(arena, &clang_compiler_flags, Lit("-Wno-microsoft-enum-forward-reference"));
|
||||||
}
|
}
|
||||||
@ -946,7 +957,7 @@ void StartupMeta(void)
|
|||||||
FmtString(StringFromList(arena, shared_compiler_flags, Lit(" "))),
|
FmtString(StringFromList(arena, shared_compiler_flags, Lit(" "))),
|
||||||
FmtString(StringFromList(arena, msvc_compiler_flags, Lit(" ")))
|
FmtString(StringFromList(arena, msvc_compiler_flags, Lit(" ")))
|
||||||
);
|
);
|
||||||
msvc_cmd_str = StringF(arena, "\"cl\" gen.c %F", FmtString(flags_str));
|
msvc_cmd_str = StringF(arena, "\"cl\" pp_gen.c %F", FmtString(flags_str));
|
||||||
}
|
}
|
||||||
/* Clang */
|
/* Clang */
|
||||||
{
|
{
|
||||||
@ -955,12 +966,12 @@ void StartupMeta(void)
|
|||||||
FmtString(StringFromList(arena, shared_compiler_flags, Lit(" "))),
|
FmtString(StringFromList(arena, shared_compiler_flags, Lit(" "))),
|
||||||
FmtString(StringFromList(arena, clang_compiler_flags, Lit(" ")))
|
FmtString(StringFromList(arena, clang_compiler_flags, Lit(" ")))
|
||||||
);
|
);
|
||||||
clang_cmd_str = StringF(arena, "\"clang\" gen.c %F", FmtString(flags_str));
|
clang_cmd_str = StringF(arena, "\"clang\" pp_gen.c %F", FmtString(flags_str));
|
||||||
}
|
}
|
||||||
|
|
||||||
//- Compile C
|
//- Compile C
|
||||||
if (ret == 0)
|
i32 ret = errors.count > 0;
|
||||||
{
|
if (ret == 0) {
|
||||||
String cmd_str = msvc_cmd_str;
|
String cmd_str = msvc_cmd_str;
|
||||||
// String cmd_str = clang_cmd_str;
|
// String cmd_str = clang_cmd_str;
|
||||||
OS_CommandResult result = OS_RunCommand(arena, cmd_str);
|
OS_CommandResult result = OS_RunCommand(arena, cmd_str);
|
||||||
@ -973,9 +984,10 @@ void StartupMeta(void)
|
|||||||
{
|
{
|
||||||
Echo(output);
|
Echo(output);
|
||||||
}
|
}
|
||||||
|
ret = result.code;
|
||||||
}
|
}
|
||||||
|
|
||||||
ExitNow(ret != 0 ? ret : errors.count > 0);
|
ExitNow(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
|
|||||||
@ -43,34 +43,6 @@ Struct(P_FileMap)
|
|||||||
b32 valid;
|
b32 valid;
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ Watch info types
|
|
||||||
|
|
||||||
Enum(P_WatchInfoKind)
|
|
||||||
{
|
|
||||||
P_WatchInfoKind_Unknown,
|
|
||||||
P_WatchInfoKind_Added,
|
|
||||||
P_WatchInfoKind_Removed,
|
|
||||||
P_WatchInfoKind_Modified,
|
|
||||||
P_WatchInfoKind_RenamedOld,
|
|
||||||
P_WatchInfoKind_RenamedNew
|
|
||||||
};
|
|
||||||
|
|
||||||
Struct(P_WatchInfo)
|
|
||||||
{
|
|
||||||
P_WatchInfoKind kind;
|
|
||||||
String name;
|
|
||||||
P_WatchInfo *next;
|
|
||||||
P_WatchInfo *prev;
|
|
||||||
};
|
|
||||||
|
|
||||||
Struct(P_WatchInfoList)
|
|
||||||
{
|
|
||||||
P_WatchInfo *first;
|
|
||||||
P_WatchInfo *last;
|
|
||||||
u64 count;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ Window event types
|
//~ Window event types
|
||||||
|
|
||||||
@ -344,15 +316,6 @@ P_FileMap P_OpenFileMap(P_File file);
|
|||||||
void P_CloseFileMap(P_FileMap map);
|
void P_CloseFileMap(P_FileMap map);
|
||||||
String P_GetFileMapData(P_FileMap map);
|
String P_GetFileMapData(P_FileMap map);
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ @hookdecl Watch operations
|
|
||||||
// A watch object allows the caller to watch for changes in a directory
|
|
||||||
|
|
||||||
P_Watch *P_AcquireWatch(String path);
|
|
||||||
void P_ReleaseWatch(P_Watch *dw);
|
|
||||||
P_WatchInfoList P_ReadWatchWait(Arena *arena, P_Watch *dw);
|
|
||||||
void P_WakeWatch(P_Watch *dw);
|
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ @hookdecl Window operations
|
//~ @hookdecl Window operations
|
||||||
|
|
||||||
|
|||||||
@ -1234,195 +1234,6 @@ String P_GetFileMapData(P_FileMap map)
|
|||||||
return map.mapped_memory;
|
return map.mapped_memory;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ @hookdef Watch hooks
|
|
||||||
|
|
||||||
P_Watch *P_AcquireWatch(String dir_path)
|
|
||||||
{
|
|
||||||
TempArena scratch = BeginScratchNoConflict();
|
|
||||||
struct P_W32_SharedCtx *g = &P_W32_shared_ctx;
|
|
||||||
|
|
||||||
P_W32_Watch *w32_watch = 0;
|
|
||||||
{
|
|
||||||
Lock lock = LockE(&g->watches_mutex);
|
|
||||||
{
|
|
||||||
if (g->watches_first_free)
|
|
||||||
{
|
|
||||||
w32_watch = g->watches_first_free;
|
|
||||||
g->watches_first_free = w32_watch->next_free;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
w32_watch = PushStructNoZero(g->watches_arena, P_W32_Watch);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Unlock(&lock);
|
|
||||||
}
|
|
||||||
ZeroStruct(w32_watch);
|
|
||||||
|
|
||||||
wchar_t *dir_path_wstr = WstrFromString(scratch.arena, dir_path);
|
|
||||||
w32_watch->dir_handle = CreateFileW(
|
|
||||||
dir_path_wstr,
|
|
||||||
FILE_LIST_DIRECTORY,
|
|
||||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
|
||||||
0,
|
|
||||||
OPEN_EXISTING,
|
|
||||||
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED,
|
|
||||||
0
|
|
||||||
);
|
|
||||||
|
|
||||||
w32_watch->wake_handle = CreateEventW(0, 0, 0, 0);
|
|
||||||
|
|
||||||
EndScratch(scratch);
|
|
||||||
return (P_Watch *)w32_watch;
|
|
||||||
}
|
|
||||||
|
|
||||||
void P_ReleaseWatch(P_Watch *dw)
|
|
||||||
{
|
|
||||||
P_W32_Watch *w32_watch = (P_W32_Watch *)dw;
|
|
||||||
struct P_W32_SharedCtx *g = &P_W32_shared_ctx;
|
|
||||||
CloseHandle(w32_watch->dir_handle);
|
|
||||||
CloseHandle(w32_watch->wake_handle);
|
|
||||||
|
|
||||||
Lock lock = LockE(&g->watches_mutex);
|
|
||||||
{
|
|
||||||
w32_watch->next_free = g->watches_first_free;
|
|
||||||
g->watches_first_free = w32_watch;
|
|
||||||
}
|
|
||||||
Unlock(&lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
P_WatchInfoList P_ReadWatchWait(Arena *arena, P_Watch *dw)
|
|
||||||
{
|
|
||||||
__prof;
|
|
||||||
P_W32_Watch *w32_watch = (P_W32_Watch *)dw;
|
|
||||||
P_WatchInfoList list = ZI;
|
|
||||||
|
|
||||||
DWORD filter = FILE_NOTIFY_CHANGE_FILE_NAME |
|
|
||||||
FILE_NOTIFY_CHANGE_DIR_NAME |
|
|
||||||
FILE_NOTIFY_CHANGE_LAST_WRITE |
|
|
||||||
FILE_NOTIFY_CHANGE_CREATION;
|
|
||||||
|
|
||||||
b32 done = 0;
|
|
||||||
while (!done)
|
|
||||||
{
|
|
||||||
OVERLAPPED ov = ZI;
|
|
||||||
ov.hEvent = CreateEventW(0, 0, 0, 0);
|
|
||||||
Assert(ov.hEvent);
|
|
||||||
|
|
||||||
BOOL success = ReadDirectoryChangesW(w32_watch->dir_handle,
|
|
||||||
w32_watch->results_buff,
|
|
||||||
countof(w32_watch->results_buff),
|
|
||||||
1,
|
|
||||||
filter,
|
|
||||||
0,
|
|
||||||
&ov,
|
|
||||||
0);
|
|
||||||
LAX success;
|
|
||||||
Assert(success);
|
|
||||||
|
|
||||||
HANDLE handles[] = {
|
|
||||||
ov.hEvent,
|
|
||||||
w32_watch->wake_handle
|
|
||||||
};
|
|
||||||
DWORD wait_result = WaitForMultipleObjects(2, handles, 0, INFINITE);
|
|
||||||
|
|
||||||
if (wait_result == WAIT_OBJECT_0)
|
|
||||||
{
|
|
||||||
i64 offset = 0;
|
|
||||||
while (!done)
|
|
||||||
{
|
|
||||||
FILE_NOTIFY_INFORMATION *result = (FILE_NOTIFY_INFORMATION *)(w32_watch->results_buff + offset);
|
|
||||||
|
|
||||||
P_WatchInfo *info = PushStruct(arena, P_WatchInfo);
|
|
||||||
if (list.last)
|
|
||||||
{
|
|
||||||
list.last->next = info;
|
|
||||||
info->prev = list.last;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
list.first = info;
|
|
||||||
}
|
|
||||||
list.last = info;
|
|
||||||
++list.count;
|
|
||||||
|
|
||||||
String16 name16 = ZI;
|
|
||||||
name16.text = result->FileName;
|
|
||||||
name16.len = result->FileNameLength / sizeof(wchar_t);
|
|
||||||
|
|
||||||
info->name = StringFromString16(arena, name16);
|
|
||||||
for (u64 i = 0; i < info->name.len; ++i)
|
|
||||||
{
|
|
||||||
if (info->name.text[i] == '\\')
|
|
||||||
{
|
|
||||||
info->name.text[i] = '/';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (result->Action)
|
|
||||||
{
|
|
||||||
case FILE_ACTION_ADDED:
|
|
||||||
{
|
|
||||||
info->kind = P_WatchInfoKind_Added;
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case FILE_ACTION_REMOVED:
|
|
||||||
{
|
|
||||||
info->kind = P_WatchInfoKind_Removed;
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case FILE_ACTION_MODIFIED:
|
|
||||||
{
|
|
||||||
info->kind = P_WatchInfoKind_Modified;
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case FILE_ACTION_RENAMED_OLD_NAME:
|
|
||||||
{
|
|
||||||
info->kind = P_WatchInfoKind_RenamedOld;
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case FILE_ACTION_RENAMED_NEW_NAME:
|
|
||||||
{
|
|
||||||
info->kind = P_WatchInfoKind_RenamedNew;
|
|
||||||
} break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
info->kind = P_WatchInfoKind_Unknown;
|
|
||||||
} break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result->NextEntryOffset == 0)
|
|
||||||
{
|
|
||||||
done = 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
offset += result->NextEntryOffset;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (wait_result == WAIT_OBJECT_0 + 1)
|
|
||||||
{
|
|
||||||
ResetEvent(w32_watch->wake_handle);
|
|
||||||
done = 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Assert(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
void P_WakeWatch(P_Watch *dw)
|
|
||||||
{
|
|
||||||
P_W32_Watch *w32_watch = (P_W32_Watch *)dw;
|
|
||||||
SetEvent(w32_watch->wake_handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ @hookdef Window hooks
|
//~ @hookdef Window hooks
|
||||||
|
|
||||||
|
|||||||
0
src/res/res.c
Normal file
0
src/res/res.c
Normal file
13
src/res/res.h
Normal file
13
src/res/res.h
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
////////////////////////////////
|
||||||
|
//~ Tag types
|
||||||
|
|
||||||
|
Struct(R_Tag)
|
||||||
|
{
|
||||||
|
u64 hash;
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ Tag helpers
|
||||||
|
|
||||||
|
String R_DataFromTag(R_Tag tag);
|
||||||
|
String R_NameFromTag(R_Tag tag);
|
||||||
7
src/res/res.lay
Normal file
7
src/res/res.lay
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
@Layer res
|
||||||
|
|
||||||
|
//- Api
|
||||||
|
@IncludeC res.h
|
||||||
|
|
||||||
|
//- Impl
|
||||||
|
@IncludeC res.c
|
||||||
@ -1,97 +0,0 @@
|
|||||||
RES_SharedState RES_shared_state = ZI;
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ Startup
|
|
||||||
|
|
||||||
void RES_Startup(void)
|
|
||||||
{
|
|
||||||
__prof;
|
|
||||||
#if RESOURCES_EMBEDDED
|
|
||||||
String embedded_data = INC_GetResTar();
|
|
||||||
if (embedded_data.len <= 0)
|
|
||||||
{
|
|
||||||
Panic(Lit("No embedded resources found"));
|
|
||||||
}
|
|
||||||
g->archive = TAR_ArchiveFromString(GetPermArena(), embedded_data, Lit(""));
|
|
||||||
#else
|
|
||||||
/* Ensure we have the right working directory */
|
|
||||||
if (!P_IsDir(Lit("res")))
|
|
||||||
{
|
|
||||||
Panic(Lit("Resource directory \"res\" not found. Make sure the executable is being launched from the correct working directory."));
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ Open / close
|
|
||||||
|
|
||||||
RES_Resource RES_OpenResource(String name)
|
|
||||||
{
|
|
||||||
__prof;
|
|
||||||
#if RESOURCES_EMBEDDED
|
|
||||||
RES_SharedState *g = &RES_shared_state;
|
|
||||||
RES_Resource result = ZI;
|
|
||||||
TAR_Entry *entry = TAR_EntryFromName(&g->archive, name);
|
|
||||||
result._data = entry->data;
|
|
||||||
result._name = entry->file_name;
|
|
||||||
result._exists = entry->valid;
|
|
||||||
return result;
|
|
||||||
#else
|
|
||||||
RES_Resource result = ZI;
|
|
||||||
if (name.len < countof(result._name_text))
|
|
||||||
{
|
|
||||||
u8 path_text[RES_ResourceNameLenMax + (sizeof("result/") - 1)];
|
|
||||||
String path = ZI;
|
|
||||||
{
|
|
||||||
path_text[0] = 'r';
|
|
||||||
path_text[1] = 'e';
|
|
||||||
path_text[2] = 's';
|
|
||||||
path_text[3] = '/';
|
|
||||||
u64 path_text_len = 4;
|
|
||||||
CopyBytes(path_text + path_text_len, name.text, name.len);
|
|
||||||
path_text_len += name.len;
|
|
||||||
path = STRING(path_text_len, path_text);
|
|
||||||
}
|
|
||||||
|
|
||||||
P_File file = P_OpenFileReadWait(path);
|
|
||||||
P_FileMap file_map = ZI;
|
|
||||||
String data = ZI;
|
|
||||||
if (file.valid)
|
|
||||||
{
|
|
||||||
file_map = P_OpenFileMap(file);
|
|
||||||
if (file_map.valid)
|
|
||||||
{
|
|
||||||
data = P_GetFileMapData(file_map);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
P_CloseFileMap(file_map);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
P_CloseFIle(file);
|
|
||||||
}
|
|
||||||
|
|
||||||
result._exists = file.valid && file_map.valid;
|
|
||||||
result._data = data;
|
|
||||||
result._file = file;
|
|
||||||
result._file_map = file_map;
|
|
||||||
result._name_len = name.len;
|
|
||||||
CopyBytes(result._name_text, name.text, name.len);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Assert(0);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
#if !RESOURCES_EMBEDDED
|
|
||||||
void RES_CloseResource(RES_Resource *res_ptr)
|
|
||||||
{
|
|
||||||
P_CloseFileMap(res_ptr->_file_map);
|
|
||||||
P_CloseFIle(res_ptr->_file);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
@ -1,61 +0,0 @@
|
|||||||
////////////////////////////////
|
|
||||||
//~ Resource types
|
|
||||||
|
|
||||||
#define RES_ResourceNameLenMax 256
|
|
||||||
|
|
||||||
Struct(RES_Resource)
|
|
||||||
{
|
|
||||||
String _data;
|
|
||||||
b32 _exists;
|
|
||||||
#if RESOURCES_EMBEDDED
|
|
||||||
String _name;
|
|
||||||
#else
|
|
||||||
P_File _file;
|
|
||||||
P_FileMap _file_map;
|
|
||||||
u8 _name_text[RES_ResourceNameLenMax];
|
|
||||||
u8 _name_len;
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ Shared state
|
|
||||||
|
|
||||||
Struct(RES_SharedState)
|
|
||||||
{
|
|
||||||
#if RESOURCES_EMBEDDED
|
|
||||||
TAR_Archive archive;
|
|
||||||
#else
|
|
||||||
i32 _;
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
extern RES_SharedState RES_shared_state;
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ Startup
|
|
||||||
|
|
||||||
void RES_Startup(void);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ Open / close
|
|
||||||
|
|
||||||
RES_Resource RES_OpenResource(String name);
|
|
||||||
|
|
||||||
#if RESOURCES_EMBEDDED
|
|
||||||
# define RES_CloseResource(res_ptr) LAX res_ptr
|
|
||||||
#else
|
|
||||||
void RES_CloseResource(RES_Resource *res_ptr);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ Resource data operations
|
|
||||||
|
|
||||||
#define RES_GetResourceData(res_ptr) (res_ptr)->_data
|
|
||||||
|
|
||||||
#define RES_ResourceExists(res_ptr) (res_ptr)->_exists
|
|
||||||
|
|
||||||
#if RESOURCES_EMBEDDED
|
|
||||||
# define RES_GetResourceName(res_ptr) (res_ptr)->_name
|
|
||||||
#else
|
|
||||||
# define RES_GetResourceName(res_ptr) STRING((res_ptr)->_name_len, (res_ptr)->_name_text)
|
|
||||||
#endif
|
|
||||||
@ -1,15 +0,0 @@
|
|||||||
@Layer resource
|
|
||||||
|
|
||||||
//- Dependencies
|
|
||||||
@Dep platform
|
|
||||||
@Dep tar
|
|
||||||
@Dep inc
|
|
||||||
|
|
||||||
//- Api
|
|
||||||
@IncludeC resource.h
|
|
||||||
|
|
||||||
//- Impl
|
|
||||||
@IncludeC resource.c
|
|
||||||
|
|
||||||
//- Startup
|
|
||||||
@Startup RES_Startup
|
|
||||||
@ -5,39 +5,35 @@ JobDef(SND_LoadJob, sig, UNUSED id)
|
|||||||
{
|
{
|
||||||
__prof;
|
__prof;
|
||||||
TempArena scratch = BeginScratchNoConflict();
|
TempArena scratch = BeginScratchNoConflict();
|
||||||
String path = sig->path;
|
R_Tag resource = sig->resource;
|
||||||
|
String name = R_NameFromTag(resource);
|
||||||
AC_Asset *asset = sig->asset;
|
AC_Asset *asset = sig->asset;
|
||||||
SND_SoundFlag flags = sig->flags;
|
SND_SoundFlag flags = sig->flags;
|
||||||
|
|
||||||
P_LogInfoF("Loading sound \"%F\"", FmtString(path));
|
P_LogInfoF("Loading sound \"%F\"", FmtString(name));
|
||||||
i64 start_ns = TimeNs();
|
i64 start_ns = TimeNs();
|
||||||
|
|
||||||
String error_msg = Lit("Unknown error");
|
String error_msg = Lit("Unknown error");
|
||||||
|
|
||||||
Assert(StringEndsWith(path, Lit(".mp3")));
|
|
||||||
|
|
||||||
/* Decode */
|
/* Decode */
|
||||||
MP3_Result decoded = ZI;
|
MP3_Result decoded = ZI;
|
||||||
|
String resource_data = R_DataFromTag(resource);
|
||||||
|
if (resource_data.len > 0)
|
||||||
{
|
{
|
||||||
RES_Resource sound_rs = RES_OpenResource(path);
|
u64 decode_flags = 0;
|
||||||
if (RES_ResourceExists(&sound_rs))
|
if (flags & SND_SoundFlag_Stereo)
|
||||||
{
|
{
|
||||||
u64 decode_flags = 0;
|
decode_flags |= MP3_DecodeFlag_Stereo;
|
||||||
if (flags & SND_SoundFlag_Stereo)
|
|
||||||
{
|
|
||||||
decode_flags |= MP3_DecodeFlag_Stereo;
|
|
||||||
}
|
|
||||||
decoded = MP3_Decode(scratch.arena, RES_GetResourceData(&sound_rs), SND_SampleRate, decode_flags);
|
|
||||||
if (!decoded.success)
|
|
||||||
{
|
|
||||||
error_msg = Lit("Failed to decode sound file");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
decoded = MP3_Decode(scratch.arena, resource_data, SND_SampleRate, decode_flags);
|
||||||
|
if (!decoded.success)
|
||||||
{
|
{
|
||||||
error_msg = Lit("Resource not found");
|
error_msg = Lit("Failed to decode sound file");
|
||||||
}
|
}
|
||||||
RES_CloseResource(&sound_rs);
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
error_msg = Lit("Missing resource data");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (decoded.success)
|
if (decoded.success)
|
||||||
@ -60,12 +56,12 @@ JobDef(SND_LoadJob, sig, UNUSED id)
|
|||||||
sound->samples = samples;
|
sound->samples = samples;
|
||||||
CopyBytes(sound->samples, decoded.samples, decoded.samples_count * sizeof(*decoded.samples));
|
CopyBytes(sound->samples, decoded.samples, decoded.samples_count * sizeof(*decoded.samples));
|
||||||
|
|
||||||
P_LogSuccessF("Loaded sound \"%F\" in %F seconds", FmtString(path), FmtFloat(SecondsFromNs(TimeNs() - start_ns)));
|
P_LogSuccessF("Loaded sound \"%F\" in %F seconds", FmtString(name), FmtFloat(SecondsFromNs(TimeNs() - start_ns)));
|
||||||
AC_MarkReady(asset, sound);
|
AC_MarkReady(asset, sound);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
P_LogErrorF("Error loading sound \"%F\": %F", FmtString(path), FmtString(error_msg));
|
P_LogErrorF("Error loading sound \"%F\": %F", FmtString(name), FmtString(error_msg));
|
||||||
|
|
||||||
/* Store */
|
/* Store */
|
||||||
SND_Sound *sound = 0;
|
SND_Sound *sound = 0;
|
||||||
@ -84,15 +80,16 @@ JobDef(SND_LoadJob, sig, UNUSED id)
|
|||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ Load sound
|
//~ Load sound
|
||||||
|
|
||||||
AC_Asset *SND_LoadAsset(String path, SND_SoundFlag flags, b32 wait)
|
AC_Asset *SND_LoadAsset(R_Tag resource, SND_SoundFlag flags, b32 wait)
|
||||||
{
|
{
|
||||||
__prof;
|
__prof;
|
||||||
TempArena scratch = BeginScratchNoConflict();
|
TempArena scratch = BeginScratchNoConflict();
|
||||||
|
|
||||||
/* Generate and append sound flags to path key */
|
/* Generate and append sound flags to name key */
|
||||||
|
String name = R_NameFromTag(resource);
|
||||||
String key = StringFormat(scratch.arena,
|
String key = StringFormat(scratch.arena,
|
||||||
Lit("%F%F_sound"),
|
Lit("%F%F_sound"),
|
||||||
FmtString(path),
|
FmtString(name),
|
||||||
FmtUint((u64)flags));
|
FmtUint((u64)flags));
|
||||||
u64 hash = AC_HashFromKey(key);
|
u64 hash = AC_HashFromKey(key);
|
||||||
b32 is_first_touch;
|
b32 is_first_touch;
|
||||||
@ -102,7 +99,7 @@ AC_Asset *SND_LoadAsset(String path, SND_SoundFlag flags, b32 wait)
|
|||||||
{
|
{
|
||||||
AC_MarkLoading(asset);
|
AC_MarkLoading(asset);
|
||||||
SND_LoadJob_Desc *desc = PushJobDesc(SND_LoadJob, .pool = JobPool_Background, .priority = JobPriority_Low, .counter = &asset->counter);
|
SND_LoadJob_Desc *desc = PushJobDesc(SND_LoadJob, .pool = JobPool_Background, .priority = JobPriority_Low, .counter = &asset->counter);
|
||||||
desc->sig->path = PushString(desc->arena, path);
|
desc->sig->resource = resource;
|
||||||
desc->sig->asset = asset;
|
desc->sig->asset = asset;
|
||||||
desc->sig->flags = flags;
|
desc->sig->flags = flags;
|
||||||
RunJobEx((GenericJobDesc *)desc);
|
RunJobEx((GenericJobDesc *)desc);
|
||||||
@ -116,18 +113,18 @@ AC_Asset *SND_LoadAsset(String path, SND_SoundFlag flags, b32 wait)
|
|||||||
return asset;
|
return asset;
|
||||||
}
|
}
|
||||||
|
|
||||||
SND_Sound *SND_LoadSoundAsync(String path, SND_SoundFlag flags)
|
SND_Sound *SND_LoadSoundAsync(R_Tag resource, SND_SoundFlag flags)
|
||||||
{
|
{
|
||||||
__prof;
|
__prof;
|
||||||
AC_Asset *asset = SND_LoadAsset(path, flags, 0);
|
AC_Asset *asset = SND_LoadAsset(resource, flags, 0);
|
||||||
SND_Sound *sound = (SND_Sound *)AC_DataFromStore(asset);
|
SND_Sound *sound = (SND_Sound *)AC_DataFromStore(asset);
|
||||||
return sound;
|
return sound;
|
||||||
}
|
}
|
||||||
|
|
||||||
SND_Sound *SND_LoadSoundWait(String path, SND_SoundFlag flags)
|
SND_Sound *SND_LoadSoundWait(R_Tag resource, SND_SoundFlag flags)
|
||||||
{
|
{
|
||||||
__prof;
|
__prof;
|
||||||
AC_Asset *asset = SND_LoadAsset(path, flags, 1);
|
AC_Asset *asset = SND_LoadAsset(resource, flags, 1);
|
||||||
AC_YieldOnAssetReady(asset);
|
AC_YieldOnAssetReady(asset);
|
||||||
SND_Sound *sound = (SND_Sound *)AC_DataFromStore(asset);
|
SND_Sound *sound = (SND_Sound *)AC_DataFromStore(asset);
|
||||||
return sound;
|
return sound;
|
||||||
|
|||||||
@ -19,7 +19,7 @@ Struct(SND_Sound)
|
|||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ Sound load operations
|
//~ Sound load operations
|
||||||
|
|
||||||
JobDecl(SND_LoadJob, { SND_SoundFlag flags; AC_Asset *asset; String path; });
|
JobDecl(SND_LoadJob, { SND_SoundFlag flags; AC_Asset *asset; R_Tag resource; });
|
||||||
AC_Asset *SND_LoadAsset(String path, SND_SoundFlag flags, b32 wait);
|
AC_Asset *SND_LoadAsset(R_Tag resource, SND_SoundFlag flags, b32 wait);
|
||||||
SND_Sound *SND_LoadSoundAsync(String path, SND_SoundFlag flags);
|
SND_Sound *SND_LoadSoundAsync(R_Tag resource, SND_SoundFlag flags);
|
||||||
SND_Sound *SND_LoadSoundWait(String path, SND_SoundFlag flags);
|
SND_Sound *SND_LoadSoundWait(R_Tag resource, SND_SoundFlag flags);
|
||||||
|
|||||||
@ -3,8 +3,8 @@
|
|||||||
//- Dependencies
|
//- Dependencies
|
||||||
@Dep platform
|
@Dep platform
|
||||||
@Dep mp3
|
@Dep mp3
|
||||||
@Dep resource
|
|
||||||
@Dep asset_cache
|
@Dep asset_cache
|
||||||
|
@Dep res
|
||||||
|
|
||||||
//- Api
|
//- Api
|
||||||
@IncludeC sound.h
|
@IncludeC sound.h
|
||||||
|
|||||||
@ -48,9 +48,6 @@ void S_Startup(void)
|
|||||||
RunJob(1, S_EvictorJob, JobPool_Background, JobPriority_Low, &g->shutdown_counter, 0);
|
RunJob(1, S_EvictorJob, JobPool_Background, JobPriority_Low, &g->shutdown_counter, 0);
|
||||||
|
|
||||||
OnExit(&S_Shutdown);
|
OnExit(&S_Shutdown);
|
||||||
#if RESOURCE_RELOADING
|
|
||||||
W_RegisterCallback(&S_WatchSpriteCallback);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
@ -528,22 +525,6 @@ void S_LoadCacheEntryTexture(S_CacheEntryRef ref, S_Tag tag)
|
|||||||
|
|
||||||
Atomic32FetchSet(&e->state, S_CacheEntryState_Loaded);
|
Atomic32FetchSet(&e->state, S_CacheEntryState_Loaded);
|
||||||
|
|
||||||
#if RESOURCE_RELOADING
|
|
||||||
S_CacheEntryBin *bin = &g->cache.bins[e->hash.v % S_CacheBinsCount];
|
|
||||||
Lock bin_lock = LockE(&bin->mutex);
|
|
||||||
{
|
|
||||||
for (S_CacheEntry *old_entry = bin->first; old_entry; old_entry = old_entry->next_in_bin)
|
|
||||||
{
|
|
||||||
if (old_entry != e && old_entry->hash.v == e->hash.v)
|
|
||||||
{
|
|
||||||
Atomic32FetchSet(&old_entry->out_of_date, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
e->load_time_ns = TimeNs();
|
|
||||||
}
|
|
||||||
Unlock(&bin_lock);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
EndScratch(scratch);
|
EndScratch(scratch);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -611,22 +592,6 @@ void S_LoadCacheEntrySheet(S_CacheEntryRef ref, S_Tag tag)
|
|||||||
|
|
||||||
Atomic32FetchSet(&e->state, S_CacheEntryState_Loaded);
|
Atomic32FetchSet(&e->state, S_CacheEntryState_Loaded);
|
||||||
|
|
||||||
#if RESOURCE_RELOADING
|
|
||||||
S_CacheEntryBin *bin = &g->cache.bins[e->hash.v % S_CacheBinsCount];
|
|
||||||
Lock bin_lock = LockE(&bin->mutex);
|
|
||||||
{
|
|
||||||
for (S_CacheEntry *old_entry = bin->first; old_entry; old_entry = old_entry->next_in_bin)
|
|
||||||
{
|
|
||||||
if (old_entry != e && old_entry->hash.v == e->hash.v)
|
|
||||||
{
|
|
||||||
Atomic32FetchSet(&old_entry->out_of_date, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
e->load_time_ns = TimeNs();
|
|
||||||
}
|
|
||||||
Unlock(&bin_lock);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
EndScratch(scratch);
|
EndScratch(scratch);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -777,29 +742,6 @@ S_ScopeCacheEntryRef *S_EntryFromHashLocked(S_Scope *scope, S_Hash hash, Lock *b
|
|||||||
S_CacheEntryBin *bin = &g->cache.bins[hash.v % S_CacheBinsCount];
|
S_CacheEntryBin *bin = &g->cache.bins[hash.v % S_CacheBinsCount];
|
||||||
AssertLockedES(bin_lock, &bin->mutex); /* Lock required for iterating bin */
|
AssertLockedES(bin_lock, &bin->mutex); /* Lock required for iterating bin */
|
||||||
|
|
||||||
#if RESOURCE_RELOADING
|
|
||||||
/* If resource reloading is enabled, then we want to find the
|
|
||||||
* newest entry rather than the first one that exists since
|
|
||||||
* there may be more than one matching entry in the cache */
|
|
||||||
S_CacheEntry *match = 0;
|
|
||||||
S_CacheEntryState match_state = S_CacheEntryState_None;
|
|
||||||
for (S_CacheEntry *entry = bin->first; entry; entry = entry->next_in_bin)
|
|
||||||
{
|
|
||||||
if (entry->hash.v == hash.v)
|
|
||||||
{
|
|
||||||
S_CacheEntryState entry_state = Atomic32Fetch(&entry->state);
|
|
||||||
if (!match || entry_state > match_state || (entry_state == S_CacheEntryState_Loaded && match_state == S_CacheEntryState_Loaded && entry->load_time_ns > match->load_time_ns))
|
|
||||||
{
|
|
||||||
match = entry;
|
|
||||||
match_state = entry_state;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (match)
|
|
||||||
{
|
|
||||||
scope_ref = S_EnsureRefFromEntryLocked(scope, match, bin_lock);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
for (S_CacheEntry *entry = bin->first; entry; entry = entry->next_in_bin)
|
for (S_CacheEntry *entry = bin->first; entry; entry = entry->next_in_bin)
|
||||||
{
|
{
|
||||||
if (entry->hash.v == hash.v)
|
if (entry->hash.v == hash.v)
|
||||||
@ -808,7 +750,6 @@ S_ScopeCacheEntryRef *S_EntryFromHashLocked(S_Scope *scope, S_Hash hash, Lock *b
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
return scope_ref;
|
return scope_ref;
|
||||||
}
|
}
|
||||||
@ -1095,52 +1036,6 @@ S_SliceArray S_SlicesFromNameIndex(S_Sheet *sheet, String name, u32 frame_index)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ Resource reloading
|
|
||||||
|
|
||||||
#if RESOURCE_RELOADING
|
|
||||||
|
|
||||||
void S_ReloadSpriteFromTag(S_Scope *scope, S_Tag tag, S_CacheEntryKind kind)
|
|
||||||
{
|
|
||||||
S_SharedState *g = &S_shared_state;
|
|
||||||
S_Hash hash = S_CacheEntryFromTagHash(tag.hash, kind);
|
|
||||||
S_CacheEntryBin *bin = &g->cache.bins[hash.v % S_CacheBinsCount];
|
|
||||||
S_ScopeCacheEntryRef *existing_ref = 0;
|
|
||||||
Lock bin_lock = LockS(&bin->mutex);
|
|
||||||
{
|
|
||||||
existing_ref = S_EntryFromHashLocked(scope, hash, &bin_lock);
|
|
||||||
}
|
|
||||||
Unlock(&bin_lock);
|
|
||||||
|
|
||||||
if (existing_ref)
|
|
||||||
{
|
|
||||||
P_LogInfoF("Sprite resource file \"%F\" has changed for sprite [%F].", FmtString(tag.path), FmtHex(hash.v));
|
|
||||||
S_ScopeCacheEntryRef *scope_ref = S_EntryFromTag(scope, tag, kind, 1);
|
|
||||||
S_PushLoadJob(scope_ref->ref, tag);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
W_CallbackFuncDef(S_WatchSpriteCallback, name)
|
|
||||||
{
|
|
||||||
S_Scope *scope = S_BeginScope();
|
|
||||||
|
|
||||||
if (StringStartsWith(name, Lit("res/")))
|
|
||||||
{
|
|
||||||
name.len -= Lit("res/").len;
|
|
||||||
name.text += Lit("res/").len;
|
|
||||||
}
|
|
||||||
|
|
||||||
S_Tag tag = S_TagFromPath(name);
|
|
||||||
for (S_CacheEntryKind kind = 0; kind < S_CacheEntryKind_Count; ++kind)
|
|
||||||
{
|
|
||||||
S_ReloadSpriteFromTag(scope, tag, kind);
|
|
||||||
}
|
|
||||||
|
|
||||||
S_EndScope(scope);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ Evictor
|
//~ Evictor
|
||||||
|
|
||||||
@ -1161,7 +1056,6 @@ MergesortCompareFuncDef(S_EvictorSortCmp, arg_a, arg_b, _)
|
|||||||
* An attempt to evict a cache node will occur when:
|
* An attempt to evict a cache node will occur when:
|
||||||
* - Its refcount = 0 and
|
* - Its refcount = 0 and
|
||||||
* - The cache is over its memory budget and the node's last reference is longer ago than the grace period
|
* - The cache is over its memory budget and the node's last reference is longer ago than the grace period
|
||||||
* - Resource reloading is enabled and the node is out of date due to a change to its original resource file
|
|
||||||
*/
|
*/
|
||||||
JobDef(S_EvictorJob, UNUSED sig, UNUSED job_id)
|
JobDef(S_EvictorJob, UNUSED sig, UNUSED job_id)
|
||||||
{
|
{
|
||||||
@ -1179,7 +1073,7 @@ JobDef(S_EvictorJob, UNUSED sig, UNUSED job_id)
|
|||||||
|
|
||||||
/* Scan for evictable nodes */
|
/* Scan for evictable nodes */
|
||||||
b32 cache_over_budget_threshold = Atomic64Fetch(&g->cache.memory_usage.v) > (i64)S_CacheMemoryBudgetThreshold;
|
b32 cache_over_budget_threshold = Atomic64Fetch(&g->cache.memory_usage.v) > (i64)S_CacheMemoryBudgetThreshold;
|
||||||
if (cache_over_budget_threshold || RESOURCE_RELOADING)
|
if (cache_over_budget_threshold)
|
||||||
{
|
{
|
||||||
__profn("Evictor scan");
|
__profn("Evictor scan");
|
||||||
for (u64 i = 0; i < S_CacheBinsCount; ++i)
|
for (u64 i = 0; i < S_CacheBinsCount; ++i)
|
||||||
@ -1195,22 +1089,13 @@ JobDef(S_EvictorJob, UNUSED sig, UNUSED job_id)
|
|||||||
if (refcount.count <= 0)
|
if (refcount.count <= 0)
|
||||||
{
|
{
|
||||||
/* Add node to evict list */
|
/* Add node to evict list */
|
||||||
#if RESOURCE_RELOADING
|
|
||||||
b32 is_out_of_date = Atomic32Fetch(&n->out_of_date);
|
|
||||||
#else
|
|
||||||
b32 is_out_of_date = 0;
|
|
||||||
#endif
|
|
||||||
b32 is_old = cache_over_budget_threshold && ((cur_cycle - refcount.last_ref_cycle) > S_EvictorGracePeriodCycles);
|
b32 is_old = cache_over_budget_threshold && ((cur_cycle - refcount.last_ref_cycle) > S_EvictorGracePeriodCycles);
|
||||||
if (is_old || is_out_of_date)
|
if (is_old)
|
||||||
{
|
{
|
||||||
S_EvictorNode *en = PushStruct(scratch.arena, S_EvictorNode);
|
S_EvictorNode *en = PushStruct(scratch.arena, S_EvictorNode);
|
||||||
en->cache_entry = n;
|
en->cache_entry = n;
|
||||||
en->cache_bin = bin;
|
en->cache_bin = bin;
|
||||||
en->last_ref_cycle = refcount.last_ref_cycle;
|
en->last_ref_cycle = refcount.last_ref_cycle;
|
||||||
if (is_out_of_date)
|
|
||||||
{
|
|
||||||
en->last_ref_cycle = -1;
|
|
||||||
}
|
|
||||||
++evict_array_count;
|
++evict_array_count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -142,10 +142,6 @@ Struct(S_CacheEntry)
|
|||||||
|
|
||||||
/* Free list */
|
/* Free list */
|
||||||
S_CacheEntry *next_free;
|
S_CacheEntry *next_free;
|
||||||
|
|
||||||
#if RESOURCE_RELOADING
|
|
||||||
Atomic32 out_of_date; /* Has the resource changed since this entry was loaded */
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Struct(S_CacheEntryBin)
|
Struct(S_CacheEntryBin)
|
||||||
@ -335,14 +331,6 @@ S_Span S_SpanFromName(S_Sheet *sheet, String name);
|
|||||||
S_Slice S_SliceFromNameIndex(S_Sheet *sheet, String name, u32 frame_index);
|
S_Slice S_SliceFromNameIndex(S_Sheet *sheet, String name, u32 frame_index);
|
||||||
S_SliceArray S_SlicesFromNameIndex(S_Sheet *sheet, String name, u32 frame_index);
|
S_SliceArray S_SlicesFromNameIndex(S_Sheet *sheet, String name, u32 frame_index);
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ Resource reload
|
|
||||||
|
|
||||||
#if RESOURCE_RELOADING
|
|
||||||
void S_ReloadSpriteFromTag(S_Scope *scope, S_Tag tag, S_CacheEntryKind kind);
|
|
||||||
W_CallbackFuncDef(S_WatchSpriteCallback, name);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ Evictor job
|
//~ Evictor job
|
||||||
|
|
||||||
|
|||||||
@ -4,8 +4,6 @@
|
|||||||
@Dep platform
|
@Dep platform
|
||||||
@Dep gpu
|
@Dep gpu
|
||||||
@Dep ase
|
@Dep ase
|
||||||
@Dep resource
|
|
||||||
@Dep watch
|
|
||||||
|
|
||||||
//- Api
|
//- Api
|
||||||
@IncludeC sprite.h
|
@IncludeC sprite.h
|
||||||
|
|||||||
@ -1,221 +0,0 @@
|
|||||||
W_SharedState W_shared_state = ZI;
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ Startup
|
|
||||||
|
|
||||||
void W_Startup(void)
|
|
||||||
{
|
|
||||||
W_SharedState *g = &W_shared_state;
|
|
||||||
g->watch = P_AcquireWatch(Lit("./"));
|
|
||||||
|
|
||||||
g->watch_events_arena = AcquireArena(Gibi(64));
|
|
||||||
|
|
||||||
RunJob(1, W_MonitorJob, JobPool_Floating, JobPriority_Low, &g->watch_jobs_counter, 0);
|
|
||||||
RunJob(1, W_DispatcherJob, JobPool_Floating, JobPriority_Low, &g->watch_jobs_counter, 0);
|
|
||||||
OnExit(&W_Shutdown);
|
|
||||||
}
|
|
||||||
|
|
||||||
ExitFuncDef(W_Shutdown)
|
|
||||||
{
|
|
||||||
__prof;
|
|
||||||
W_SharedState *g = &W_shared_state;
|
|
||||||
Atomic32FetchSet(&g->W_Shutdown, 1);
|
|
||||||
{
|
|
||||||
Lock lock = LockE(&g->watch_dispatcher_mutex);
|
|
||||||
SignalCv(&g->watch_dispatcher_cv, I32Max);
|
|
||||||
P_WakeWatch(g->watch);
|
|
||||||
Unlock(&lock);
|
|
||||||
}
|
|
||||||
YieldOnCounter(&g->watch_jobs_counter);
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ Callback
|
|
||||||
|
|
||||||
void W_RegisterCallback(W_CallbackFunc *callback)
|
|
||||||
{
|
|
||||||
W_SharedState *g = &W_shared_state;
|
|
||||||
Lock lock = LockE(&g->watch_callbacks_mutex);
|
|
||||||
{
|
|
||||||
if (g->num_watch_callbacks < countof(g->watch_callbacks))
|
|
||||||
{
|
|
||||||
g->watch_callbacks[g->num_watch_callbacks++] = callback;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Panic(Lit("Max resource watch callbacks reached"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Unlock(&lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
JobDef(W_RunCallbacksJob , sig, id)
|
|
||||||
{
|
|
||||||
__prof;
|
|
||||||
String name = sig->name;
|
|
||||||
W_CallbackFunc *callback = sig->callbacks[id];
|
|
||||||
callback(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ Monitor job
|
|
||||||
|
|
||||||
/* NOTE: We separate the responsibilities of monitoring directory changes
|
|
||||||
* & dispatching watch callbacks into two separate jobs so that we can delay
|
|
||||||
* the dispatch, allowing for deduplication of file modification notifications. */
|
|
||||||
|
|
||||||
JobDef(W_MonitorJob, UNUSED sig, UNUSED job_id)
|
|
||||||
{
|
|
||||||
TempArena scratch = BeginScratchNoConflict();
|
|
||||||
W_SharedState *g = &W_shared_state;
|
|
||||||
|
|
||||||
String ignored[] = {
|
|
||||||
Lit(".vs"),
|
|
||||||
Lit(".git")
|
|
||||||
};
|
|
||||||
|
|
||||||
while (!Atomic32Fetch(&g->W_Shutdown))
|
|
||||||
{
|
|
||||||
TempArena temp = BeginTempArena(scratch.arena);
|
|
||||||
P_WatchInfoList info_list = P_ReadWatchWait(temp.arena, g->watch);
|
|
||||||
if (info_list.first && !Atomic32Fetch(&g->W_Shutdown))
|
|
||||||
{
|
|
||||||
Lock lock = LockE(&g->watch_dispatcher_mutex);
|
|
||||||
{
|
|
||||||
for (P_WatchInfo *info = info_list.first; info; info = info->next)
|
|
||||||
{
|
|
||||||
String name_src = info->name;
|
|
||||||
b32 ignore = 0;
|
|
||||||
for (u32 i = 0; i < countof(ignored); ++i)
|
|
||||||
{
|
|
||||||
if (StringStartsWith(name_src, ignored[i]))
|
|
||||||
{
|
|
||||||
ignore = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!ignore)
|
|
||||||
{
|
|
||||||
W_Event *e = PushStruct(g->watch_events_arena, W_Event);
|
|
||||||
e->name = PushString(g->watch_events_arena, name_src);
|
|
||||||
if (g->last_watch_event)
|
|
||||||
{
|
|
||||||
g->last_watch_event->next = e;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
g->first_watch_event = e;
|
|
||||||
}
|
|
||||||
g->last_watch_event = e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
SignalCv(&g->watch_dispatcher_cv, I32Max);
|
|
||||||
Unlock(&lock);
|
|
||||||
}
|
|
||||||
EndTempArena(temp);
|
|
||||||
}
|
|
||||||
|
|
||||||
EndScratch(scratch);
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ Dispatcher job
|
|
||||||
|
|
||||||
JobDef(W_DispatcherJob, UNUSED sig, UNUSED job_id)
|
|
||||||
{
|
|
||||||
W_SharedState *g = &W_shared_state;
|
|
||||||
|
|
||||||
b32 shutdown = 0;
|
|
||||||
while (!shutdown)
|
|
||||||
{
|
|
||||||
{
|
|
||||||
TempArena scratch = BeginScratchNoConflict();
|
|
||||||
W_Event *first_watch_event = 0;
|
|
||||||
W_Event *last_watch_event = 0;
|
|
||||||
|
|
||||||
/* Delay so that duplicate events pile up */
|
|
||||||
{
|
|
||||||
__profn("Delay");
|
|
||||||
FutexYield(0, 0, 0, NsFromSeconds(W_DispatcherDelaySeconds));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Pull watch events from queue */
|
|
||||||
{
|
|
||||||
Lock lock = LockE(&g->watch_dispatcher_mutex);
|
|
||||||
for (W_Event *src_event = g->first_watch_event; src_event; src_event = src_event->next)
|
|
||||||
{
|
|
||||||
W_Event *e = PushStruct(scratch.arena, W_Event);
|
|
||||||
e->name = PushString(scratch.arena, src_event->name);
|
|
||||||
if (last_watch_event)
|
|
||||||
{
|
|
||||||
last_watch_event->next = e;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
first_watch_event = e;
|
|
||||||
}
|
|
||||||
last_watch_event = e;
|
|
||||||
}
|
|
||||||
g->first_watch_event = 0;
|
|
||||||
g->last_watch_event = 0;
|
|
||||||
ResetArena(g->watch_events_arena);
|
|
||||||
Unlock(&lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Build callbacks array */
|
|
||||||
u64 num_callbacks = 0;
|
|
||||||
W_CallbackFunc **callbacks = 0;
|
|
||||||
Lock callbacks_lock = LockS(&g->watch_callbacks_mutex);
|
|
||||||
{
|
|
||||||
num_callbacks = g->num_watch_callbacks;
|
|
||||||
callbacks = PushStructsNoZero(scratch.arena, W_CallbackFunc *, num_callbacks);
|
|
||||||
for (u64 i = 0; i < num_callbacks; ++i)
|
|
||||||
{
|
|
||||||
callbacks[i] = g->watch_callbacks[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Unlock(&callbacks_lock);
|
|
||||||
|
|
||||||
/* Run callbacks */
|
|
||||||
{
|
|
||||||
Dict *dedup_dict = InitDict(scratch.arena, W_DispatcherDedupBins);
|
|
||||||
for (W_Event *e = first_watch_event; e; e = e->next)
|
|
||||||
{
|
|
||||||
__profn("Dispatch");
|
|
||||||
/* Do not run callbacks for the same file more than once */
|
|
||||||
b32 skip = 0;
|
|
||||||
u64 hash = HashFnv64(Fnv64Basis, e->name);
|
|
||||||
if (DictValueFromHash(dedup_dict, hash) == 1)
|
|
||||||
{
|
|
||||||
skip = 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
SetDictValue(scratch.arena, dedup_dict, hash, 1);
|
|
||||||
}
|
|
||||||
if (!skip)
|
|
||||||
{
|
|
||||||
Counter counter = ZI;
|
|
||||||
RunJob(num_callbacks, W_RunCallbacksJob, JobPool_Background, JobPriority_Low, &counter, .name = e->name, .callbacks = callbacks);
|
|
||||||
YieldOnCounter(&counter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
EndScratch(scratch);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Yield for event */
|
|
||||||
Lock lock = LockS(&g->watch_dispatcher_mutex);
|
|
||||||
{
|
|
||||||
shutdown = Atomic32Fetch(&g->W_Shutdown);
|
|
||||||
while (!shutdown && !g->first_watch_event)
|
|
||||||
{
|
|
||||||
YieldOnCv(&g->watch_dispatcher_cv, &lock);
|
|
||||||
shutdown = Atomic32Fetch(&g->W_Shutdown);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Unlock(&lock);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,61 +0,0 @@
|
|||||||
////////////////////////////////
|
|
||||||
//~ Callback types
|
|
||||||
|
|
||||||
#define W_CallbackFuncDef(func_name, arg_name) void func_name(String arg_name)
|
|
||||||
typedef W_CallbackFuncDef(W_CallbackFunc, name);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ Event types
|
|
||||||
|
|
||||||
Struct(W_Event)
|
|
||||||
{
|
|
||||||
String name;
|
|
||||||
W_Event *next;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ Shared state
|
|
||||||
|
|
||||||
#define W_DispatcherDelaySeconds 0.050
|
|
||||||
#define W_DispatcherDedupBins 128
|
|
||||||
|
|
||||||
Struct(W_SharedState)
|
|
||||||
{
|
|
||||||
P_Watch *watch;
|
|
||||||
Atomic32 W_Shutdown;
|
|
||||||
Counter watch_jobs_counter;
|
|
||||||
|
|
||||||
Mutex watch_dispatcher_mutex;
|
|
||||||
Arena *watch_events_arena;
|
|
||||||
W_Event *first_watch_event;
|
|
||||||
W_Event *last_watch_event;
|
|
||||||
Cv watch_dispatcher_cv;
|
|
||||||
|
|
||||||
Mutex watch_callbacks_mutex;
|
|
||||||
W_CallbackFunc *watch_callbacks[64];
|
|
||||||
u64 num_watch_callbacks;
|
|
||||||
};
|
|
||||||
|
|
||||||
extern W_SharedState W_shared_state;
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ Startup
|
|
||||||
|
|
||||||
void W_Startup(void);
|
|
||||||
ExitFuncDef(W_Shutdown);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ Watch operations
|
|
||||||
|
|
||||||
void W_RegisterCallback(W_CallbackFunc *callback);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ Callback job
|
|
||||||
|
|
||||||
JobDecl(W_RunCallbacksJob, { String name; W_CallbackFunc **callbacks; });
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ Long running jobs
|
|
||||||
|
|
||||||
JobDecl(W_MonitorJob, { i32 _; });
|
|
||||||
JobDecl(W_DispatcherJob, { i32 _; });
|
|
||||||
@ -1,13 +0,0 @@
|
|||||||
@Layer watch
|
|
||||||
|
|
||||||
//- Dependencies
|
|
||||||
@Dep platform
|
|
||||||
|
|
||||||
//- Api
|
|
||||||
@IncludeC watch.h
|
|
||||||
|
|
||||||
//- Impl
|
|
||||||
@IncludeC watch.c
|
|
||||||
|
|
||||||
//- Startup
|
|
||||||
@Startup W_Startup
|
|
||||||
Loading…
Reference in New Issue
Block a user