upgrade from fxc to dxc
This commit is contained in:
parent
a7b6b501a2
commit
a8651f7aa7
180
build.c
180
build.c
@ -201,15 +201,19 @@ String CleanResultOutput(Arena *arena, String output)
|
||||
typedef struct BuildStepSimpleCommandArg BuildStepSimpleCommandArg;
|
||||
struct BuildStepSimpleCommandArg {
|
||||
String cmd;
|
||||
AtomicI32 *skip_flag;
|
||||
AtomicI32 *failure_flag;
|
||||
Atomic32 *skip_flag;
|
||||
Atomic32 *failure_flag;
|
||||
D_Tag delete_file_on_failure;
|
||||
D_Tag dxc_depfile_dependent;
|
||||
D_Tag dxc_depfile;
|
||||
};
|
||||
|
||||
typedef struct BuildStepMsvcCompileCommandArg BuildStepMsvcCompileCommandArg;
|
||||
struct BuildStepMsvcCompileCommandArg {
|
||||
String cmd;
|
||||
AtomicI32 *skip_flag;
|
||||
AtomicI32 *failure_flag;
|
||||
Atomic32 *skip_flag;
|
||||
Atomic32 *failure_flag;
|
||||
D_Tag delete_file_on_failure;
|
||||
D_Tag depfile_dependent;
|
||||
D_Tag output_depfile;
|
||||
D_TagList depfile_force_includes;
|
||||
@ -221,9 +225,9 @@ void BuildStepSimpleCommand(void *arg_raw)
|
||||
Step *s = arg_raw;
|
||||
BuildStepSimpleCommandArg *arg = s->arg;
|
||||
|
||||
AtomicI32 *skip_flag = arg->skip_flag;
|
||||
AtomicI32 *failure_flag = arg->failure_flag;
|
||||
if (!skip_flag || !AtomicI32Eval(skip_flag)) {
|
||||
Atomic32 *skip_flag = arg->skip_flag;
|
||||
Atomic32 *failure_flag = arg->failure_flag;
|
||||
if (!skip_flag || !Atomic32Fetch(skip_flag)) {
|
||||
SH_CommandResult result = RunCommand(scratch.arena, arg->cmd);
|
||||
String result_output_cleaned = CleanResultOutput(scratch.arena, result.output);
|
||||
{
|
||||
@ -238,8 +242,17 @@ void BuildStepSimpleCommand(void *arg_raw)
|
||||
MemoryCopy(s->res_output.text, result_output_cleaned.text, result_output_cleaned.len);
|
||||
}
|
||||
s->res_status = result.error ? StepStatus_Failure : StepStatus_Success;
|
||||
if (result.error && failure_flag) {
|
||||
AtomicI32EvalExchange(failure_flag, 1);
|
||||
if (!D_IsNil(arg->dxc_depfile)) {
|
||||
String depfile_data = D_DepfileTextFromDxcOutput(scratch.arena, arg->dxc_depfile_dependent, result.output);
|
||||
D_ClearWrite(arg->dxc_depfile, depfile_data);
|
||||
}
|
||||
if (result.error) {
|
||||
if (failure_flag) {
|
||||
Atomic32FetchSet(failure_flag, 1);
|
||||
}
|
||||
if (!D_IsNil(arg->delete_file_on_failure)) {
|
||||
D_Delete(arg->delete_file_on_failure);
|
||||
}
|
||||
}
|
||||
OS_ConditionVariableBroadcast(&s->res_cv);
|
||||
OS_MutexUnlock(&res_lock);
|
||||
@ -248,7 +261,7 @@ void BuildStepSimpleCommand(void *arg_raw)
|
||||
OS_Lock res_lock = OS_MutexLockE(&s->res_mutex);
|
||||
s->res_status = StepStatus_Skipped;
|
||||
if (failure_flag) {
|
||||
AtomicI32EvalExchange(failure_flag, 1);
|
||||
Atomic32FetchSet(failure_flag, 1);
|
||||
}
|
||||
OS_ConditionVariableBroadcast(&s->res_cv);
|
||||
OS_MutexUnlock(&res_lock);
|
||||
@ -264,9 +277,9 @@ void BuildStepMsvcCompileCommand(void *arg_raw)
|
||||
Step *s = arg_raw;
|
||||
BuildStepMsvcCompileCommandArg *arg = s->arg;
|
||||
|
||||
AtomicI32 *skip_flag = arg->skip_flag;
|
||||
AtomicI32 *failure_flag = arg->failure_flag;
|
||||
if (!skip_flag || !AtomicI32Eval(skip_flag)) {
|
||||
Atomic32 *skip_flag = arg->skip_flag;
|
||||
Atomic32 *failure_flag = arg->failure_flag;
|
||||
if (!skip_flag || !Atomic32Fetch(skip_flag)) {
|
||||
SH_CommandResult result = RunCommand(scratch.arena, arg->cmd);
|
||||
if (!result.error && !D_IsNil(arg->depfile_dependent) && !D_IsNil(arg->output_depfile)) {
|
||||
String depfile_data = D_DepfileTextFromMsvcOutput(scratch.arena, arg->depfile_dependent, arg->depfile_force_includes, result.output);
|
||||
@ -285,8 +298,13 @@ void BuildStepMsvcCompileCommand(void *arg_raw)
|
||||
MemoryCopy(s->res_output.text, result_output_cleaned.text, result_output_cleaned.len);
|
||||
}
|
||||
s->res_status = result.error ? StepStatus_Failure : StepStatus_Success;
|
||||
if (result.error && failure_flag) {
|
||||
AtomicI32EvalExchange(failure_flag, 1);
|
||||
if (result.error) {
|
||||
if (failure_flag) {
|
||||
Atomic32FetchSet(failure_flag, 1);
|
||||
}
|
||||
if (!D_IsNil(arg->delete_file_on_failure)) {
|
||||
D_Delete(arg->delete_file_on_failure);
|
||||
}
|
||||
}
|
||||
OS_ConditionVariableBroadcast(&s->res_cv);
|
||||
OS_MutexUnlock(&res_lock);
|
||||
@ -295,7 +313,7 @@ void BuildStepMsvcCompileCommand(void *arg_raw)
|
||||
OS_Lock res_lock = OS_MutexLockE(&s->res_mutex);
|
||||
s->res_status = StepStatus_Skipped;
|
||||
if (failure_flag) {
|
||||
AtomicI32EvalExchange(failure_flag, 1);
|
||||
Atomic32FetchSet(failure_flag, 1);
|
||||
}
|
||||
OS_ConditionVariableBroadcast(&s->res_cv);
|
||||
OS_MutexUnlock(&res_lock);
|
||||
@ -369,12 +387,16 @@ void OnBuild(StringList cli_args)
|
||||
String build_hash_path = OS_GetAbsPath(&perm, StringF(&perm, Lit("%F/.pp_build_hash"), FmtStr(arg_outdir)));
|
||||
String out_dep_dir_path = OS_GetAbsPath(&perm, StringF(&perm, Lit("%F/dep/"), FmtStr(arg_outdir)));
|
||||
String out_obj_dir_path = OS_GetAbsPath(&perm, StringF(&perm, Lit("%F/obj/"), FmtStr(arg_outdir)));
|
||||
String out_dxc_dir_path = OS_GetAbsPath(&perm, StringF(&perm, Lit("%F/dxc/"), FmtStr(arg_outdir)));
|
||||
String out_inc_dir_path = OS_GetAbsPath(&perm, StringF(&perm, Lit("%F/inc/"), FmtStr(arg_outdir)));
|
||||
String out_bin_dir_path = OS_GetAbsPath(&perm, StringF(&perm, Lit("%F/bin/"), FmtStr(arg_outdir)));
|
||||
|
||||
if (!OS_DirExists(out_obj_dir_path)) {
|
||||
OS_CreateDirAtAbsPath(out_obj_dir_path);
|
||||
}
|
||||
if (!OS_DirExists(out_dxc_dir_path)) {
|
||||
OS_CreateDirAtAbsPath(out_dxc_dir_path);
|
||||
}
|
||||
if (!OS_DirExists(out_inc_dir_path)) {
|
||||
OS_CreateDirAtAbsPath(out_inc_dir_path);
|
||||
}
|
||||
@ -416,6 +438,7 @@ void OnBuild(StringList cli_args)
|
||||
Bool should_embed_in_rc = !!arg_msvc;
|
||||
|
||||
D_Tag executable_file = D_TagFromPath(&perm, StringF(&perm, Lit("%F/PowerPlay.exe"), FmtStr(out_bin_dir_path)), D_TagKind_File);
|
||||
D_Tag dxc_dir = D_TagFromPath(&perm, out_dxc_dir_path, D_TagKind_Dir);
|
||||
D_Tag res_dir = D_TagFromPath(&perm, Lit("res"), D_TagKind_Dir);
|
||||
D_Tag icon_file = D_TagFromPath(&perm, Lit("icon.ico"), D_TagKind_File);
|
||||
|
||||
@ -436,6 +459,7 @@ void OnBuild(StringList cli_args)
|
||||
StringList link_warnings = { 0 };
|
||||
StringList link_args = { 0 };
|
||||
StringList rc_compile_args = { 0 };
|
||||
StringList dxc_compile_args = { 0 };
|
||||
{
|
||||
if (arg_msvc) {
|
||||
/* Msvc */
|
||||
@ -449,7 +473,7 @@ void OnBuild(StringList cli_args)
|
||||
|
||||
String warnings = Lit("/WX /Wall "
|
||||
"/options:strict "
|
||||
"/wd4820 /wd4201 /wd5220 /wd4514 /wd4244 /wd5045 /wd4242 /wd4061 /wd4189 /wd4723 /wd5246");
|
||||
"/wd4820 /wd4201 /wd5220 /wd4514 /wd4244 /wd5045 /wd4242 /wd4061 /wd4189 /wd4723 /wd5246 /wd4324");
|
||||
StringListAppend(&perm, &compile_warnings, warnings);
|
||||
StringListAppend(&perm, &link_warnings, Lit("/WX"));
|
||||
|
||||
@ -495,6 +519,12 @@ void OnBuild(StringList cli_args)
|
||||
StringListAppend(&perm, &link_warnings, warnings);
|
||||
}
|
||||
|
||||
/* DXC */
|
||||
{
|
||||
StringListAppend(&perm, &dxc_compile_args, Lit("dxc %F -Fo %F -E %F -T %F -H"));
|
||||
}
|
||||
|
||||
|
||||
/* RTC */
|
||||
if (arg_rtc) {
|
||||
if (!arg_crtlib) {
|
||||
@ -535,6 +565,7 @@ void OnBuild(StringList cli_args)
|
||||
} else {
|
||||
StringListAppend(&perm, &compile_and_link_args, Lit("-O0"));
|
||||
}
|
||||
StringListAppend(&perm, &dxc_compile_args, Lit("-Od"));
|
||||
} else {
|
||||
if (arg_msvc) {
|
||||
StringListAppend(&perm, &compile_args, Lit("/O2"));
|
||||
@ -542,6 +573,7 @@ void OnBuild(StringList cli_args)
|
||||
} else {
|
||||
StringListAppend(&perm, &compile_and_link_args, Lit("-O3 -flto"));
|
||||
}
|
||||
StringListAppend(&perm, &dxc_compile_args, Lit("-O3"));
|
||||
}
|
||||
|
||||
/* Debug info */
|
||||
@ -552,6 +584,7 @@ void OnBuild(StringList cli_args)
|
||||
} else {
|
||||
StringListAppend(&perm, &compile_and_link_args, Lit("-g"));
|
||||
}
|
||||
StringListAppend(&perm, &dxc_compile_args, Lit("-Zi -Qembed_debug"));
|
||||
}
|
||||
|
||||
/* Address sanitizer */
|
||||
@ -638,16 +671,106 @@ void OnBuild(StringList cli_args)
|
||||
hist = D_HistFromPath(&perm, hist_path);
|
||||
D_TagList link_files = { 0 };
|
||||
|
||||
/* ========================== *
|
||||
* Build step: Compile shaders
|
||||
* ========================== */
|
||||
|
||||
Atomic32 shader_success_flag = { 0 };
|
||||
{
|
||||
D_TagList src_input_files = { 0 };
|
||||
{
|
||||
D_Tag src_dir = D_TagFromPath(&perm, Lit("src/sh"), D_TagKind_Dir);
|
||||
D_TagList src_files = D_GetDirContents(&perm, src_dir, 0);
|
||||
|
||||
for (D_TagListNode *n = src_files.first; n; n = n->next) {
|
||||
D_Tag file = n->tag;
|
||||
String path = file.full_path;
|
||||
String name = D_GetName(file);
|
||||
String extension = StringPathExtension(name);
|
||||
Bool is_dir = file.kind == D_TagKind_Dir;
|
||||
Bool is_rs = !is_dir && StringEqual(extension, Lit("hlsl_rs"));
|
||||
Bool is_cs = !is_dir && StringEqual(extension, Lit("hlsl_cs"));
|
||||
if (is_rs || is_cs) {
|
||||
D_TagListAppend(&perm, &src_input_files, file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
AddSyncPoint();
|
||||
|
||||
String dxc_compile_args_fmt = StringFromStringLists(&perm, Lit(" "), dxc_compile_args);
|
||||
for (D_TagListNode *n = src_input_files.first; n; n = n->next) {
|
||||
D_Tag file = n->tag;
|
||||
String path = file.full_path;
|
||||
String name = D_GetName(file);
|
||||
String name_no_extension = StringPathNoExtension(name);
|
||||
String extension = StringPathExtension(name);
|
||||
Bool is_rs = StringEqual(extension, Lit("hlsl_rs"));
|
||||
Bool is_cs = !is_rs && StringEqual(extension, Lit("hlsl_cs"));
|
||||
for (I32 kind = 0; kind < 3; ++kind) {
|
||||
String out_file_extension = { 0 };
|
||||
String entry = { 0 };
|
||||
String profile = { 0 };
|
||||
if (kind == 0 && is_rs) {
|
||||
/* Vertex shader */
|
||||
out_file_extension = Lit("dxc_vs");
|
||||
entry = Lit("vs");
|
||||
profile = Lit("vs_6_6");
|
||||
} else if (kind == 1 && is_rs) {
|
||||
/* Pixel shader */
|
||||
out_file_extension = Lit("dxc_ps");
|
||||
entry = Lit("ps");
|
||||
profile = Lit("ps_6_6");
|
||||
} else if (kind == 2 && is_cs) {
|
||||
/* Compute shader */
|
||||
out_file_extension = Lit("dxc_cs");
|
||||
entry = Lit("cs");
|
||||
profile = Lit("cs_6_6");
|
||||
}
|
||||
if (entry.len > 0) {
|
||||
D_Tag dep_file;
|
||||
{
|
||||
String dep_file_path = StringF(&perm, Lit("%F/%F.%F"), FmtStr(out_dxc_dir_path), FmtStr(name_no_extension), FmtStr(dep_file_extension));
|
||||
dep_file = D_TagFromPath(&perm, dep_file_path, D_TagKind_DepFile);
|
||||
}
|
||||
|
||||
D_Tag dxc_file;
|
||||
{
|
||||
String dxc_file_path = StringF(&perm, Lit("%F/%F.%F"), FmtStr(out_dxc_dir_path), FmtStr(name_no_extension), FmtStr(out_file_extension));
|
||||
dxc_file = D_TagFromPath(&perm, dxc_file_path, D_TagKind_File);
|
||||
}
|
||||
D_AddDependency(&store, dxc_file, file);
|
||||
D_AddDependency(&store, dxc_file, dep_file);
|
||||
|
||||
if (IsDirty(dxc_file)) {
|
||||
String step_name = StringF(&perm, Lit("%F -> %F"), FmtStr(name), FmtStr(D_GetName(dxc_file)));
|
||||
{
|
||||
BuildStepSimpleCommandArg *bs_arg = ArenaPush(&perm, BuildStepSimpleCommandArg);
|
||||
bs_arg->cmd = StringF(&perm, dxc_compile_args_fmt, FmtStr(file.full_path), FmtStr(dxc_file.full_path), FmtStr(entry), FmtStr(profile));
|
||||
bs_arg->failure_flag = &shader_success_flag;
|
||||
bs_arg->delete_file_on_failure = dxc_file;
|
||||
bs_arg->dxc_depfile_dependent = dxc_file;
|
||||
bs_arg->dxc_depfile = dep_file;
|
||||
AddStep(step_name, &BuildStepSimpleCommand, bs_arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ========================== *
|
||||
* Build step: Tar archives
|
||||
* ========================== */
|
||||
|
||||
AtomicI32 tar_success_flag = { 0 };
|
||||
Atomic32 tar_success_flag = { 0 };
|
||||
{
|
||||
AddSyncPoint();
|
||||
|
||||
D_TagList tar_input_dirs = { 0 };
|
||||
|
||||
D_TagListAppend(&perm, &tar_input_dirs, dxc_dir);
|
||||
if (should_embed_res_dir) {
|
||||
D_TagListAppend(&perm, &tar_input_dirs, res_dir);
|
||||
}
|
||||
@ -665,6 +788,7 @@ void OnBuild(StringList cli_args)
|
||||
BuildStepSimpleCommandArg *bs_arg = ArenaPush(&perm, BuildStepSimpleCommandArg);
|
||||
bs_arg->cmd = StringF(&perm, Lit("cd %F && tar cvf %F ."), FmtStr(input_dir.full_path), FmtStr(tar_file.full_path));
|
||||
bs_arg->failure_flag = &tar_success_flag;
|
||||
bs_arg->skip_flag = &shader_success_flag;
|
||||
String step_name = StringF(&perm, Lit("%F -> %F"), FmtStr(D_GetName(input_dir)), FmtStr(D_GetName(tar_file)));
|
||||
AddStep(step_name, &BuildStepSimpleCommand, bs_arg);
|
||||
}
|
||||
@ -675,20 +799,23 @@ void OnBuild(StringList cli_args)
|
||||
* Build step: Compile RC files
|
||||
* ========================== */
|
||||
|
||||
AtomicI32 rc_success_flag = { 0 };
|
||||
Atomic32 rc_success_flag = { 0 };
|
||||
if (PlatformWindows) {
|
||||
AddSyncPoint();
|
||||
|
||||
D_Tag rc_input_file = D_TagFromPath(&perm, StringF(&perm, Lit("%F/rc.rc"), FmtStr(out_inc_dir_path)), D_TagKind_File);
|
||||
{
|
||||
D_Tag res_tar_file = D_TagFromPath(&perm, StringF(&perm, Lit("%F/%F.tar"), FmtStr(out_inc_dir_path), FmtStr(D_GetName(res_dir))), D_TagKind_File);
|
||||
D_Tag dxc_tar_file = D_TagFromPath(&perm, StringF(&perm, Lit("%F/%F.tar"), FmtStr(out_inc_dir_path), FmtStr(D_GetName(dxc_dir))), D_TagKind_File);
|
||||
D_AddDependency(&store, rc_input_file, icon_file);
|
||||
D_AddDependency(&store, rc_input_file, dxc_tar_file);
|
||||
if (should_embed_in_rc && should_embed_res_dir) {
|
||||
D_AddDependency(&store, rc_input_file, res_tar_file);
|
||||
}
|
||||
if (IsDirty(rc_input_file)) {
|
||||
D_ClearWrite(rc_input_file, Lit(""));
|
||||
D_AppendWrite(rc_input_file, StringF(&perm, Lit("%F %F DISCARDABLE %F\n"), FmtStr(D_GetName(icon_file)), FmtStr(Lit("ICON")), FmtStr(D_GetName(icon_file))));
|
||||
D_AppendWrite(rc_input_file, StringF(&perm, Lit("%F %F DISCARDABLE %F\n"), FmtStr(D_GetName(dxc_tar_file)), FmtStr(Lit("RCDATA")), FmtStr(D_GetName(dxc_tar_file))));
|
||||
if (should_embed_in_rc && should_embed_res_dir) {
|
||||
D_AppendWrite(rc_input_file, StringF(&perm, Lit("%F %F DISCARDABLE %F\n"), FmtStr(D_GetName(res_tar_file)), FmtStr(Lit("RCDATA")), FmtStr(D_GetName(res_tar_file))));
|
||||
}
|
||||
@ -716,7 +843,7 @@ void OnBuild(StringList cli_args)
|
||||
* Build step: Compile pch files
|
||||
* ========================== */
|
||||
|
||||
AtomicI32 pch_success_flag = { 0 };
|
||||
Atomic32 pch_success_flag = { 0 };
|
||||
D_TagList depfile_force_includes = { 0 };
|
||||
{
|
||||
AddSyncPoint();
|
||||
@ -767,6 +894,7 @@ void OnBuild(StringList cli_args)
|
||||
bs_arg->output_depfile = dep_file;
|
||||
bs_arg->skip_flag = &rc_success_flag;
|
||||
bs_arg->failure_flag = &pch_success_flag;
|
||||
bs_arg->delete_file_on_failure = pch_c_file;
|
||||
String step_name = StringF(&perm, Lit("%F -> %F"), FmtStr(D_GetName(pch_header_file)), FmtStr(D_GetName(pch_c_file)));
|
||||
AddStep(step_name, &BuildStepMsvcCompileCommand, bs_arg);
|
||||
}
|
||||
@ -782,6 +910,7 @@ void OnBuild(StringList cli_args)
|
||||
bs_arg->output_depfile = dep_file;
|
||||
bs_arg->skip_flag = &rc_success_flag;
|
||||
bs_arg->failure_flag = &pch_success_flag;
|
||||
bs_arg->delete_file_on_failure = pch_cpp_file;
|
||||
String step_name = StringF(&perm, Lit("%F -> %F"), FmtStr(D_GetName(pch_header_file)), FmtStr(D_GetName(pch_cpp_file)));
|
||||
AddStep(step_name, &BuildStepMsvcCompileCommand, bs_arg);
|
||||
}
|
||||
@ -818,7 +947,7 @@ void OnBuild(StringList cli_args)
|
||||
* Build step: Compile src files
|
||||
* ========================== */
|
||||
|
||||
AtomicI32 src_success_flag = { 0 };
|
||||
Atomic32 src_success_flag = { 0 };
|
||||
{
|
||||
D_TagList src_input_files = { 0 };
|
||||
{
|
||||
@ -840,13 +969,15 @@ void OnBuild(StringList cli_args)
|
||||
StringBeginsWith(name, Lit("gp_")) ||
|
||||
StringBeginsWith(name, Lit("playback_")) ||
|
||||
StringBeginsWith(name, Lit("mp3_")) ||
|
||||
StringBeginsWith(name, Lit("ttf_"))) {
|
||||
StringBeginsWith(name, Lit("ttf_")) ||
|
||||
StringBeginsWith(name, Lit("dxc"))) {
|
||||
if (PlatformWindows) {
|
||||
ignore = !(StringEqual(name, Lit("sys_win32.c")) ||
|
||||
StringEqual(name, Lit("gp_dx12.c")) ||
|
||||
StringEqual(name, Lit("playback_wasapi.c")) ||
|
||||
StringEqual(name, Lit("mp3_mmf.c")) ||
|
||||
StringEqual(name, Lit("ttf_dwrite.cpp")));
|
||||
StringEqual(name, Lit("ttf_dwrite.cpp")) ||
|
||||
StringEqual(name, Lit("dxc.cpp")));
|
||||
}
|
||||
} else {
|
||||
ignore = 0;
|
||||
@ -899,6 +1030,7 @@ void OnBuild(StringList cli_args)
|
||||
bs_arg->depfile_force_includes = depfile_force_includes;
|
||||
bs_arg->skip_flag = &pch_success_flag;
|
||||
bs_arg->failure_flag = &src_success_flag;
|
||||
bs_arg->delete_file_on_failure = obj_file;
|
||||
AddStep(step_name, &BuildStepMsvcCompileCommand, bs_arg);
|
||||
} else {
|
||||
BuildStepSimpleCommandArg *bs_arg = ArenaPush(&perm, BuildStepSimpleCommandArg);
|
||||
|
||||
@ -21,6 +21,7 @@
|
||||
#include "phys.h"
|
||||
#include "host.h"
|
||||
#include "bitbuff.h"
|
||||
#include "watch.h"
|
||||
|
||||
GLOBAL struct {
|
||||
struct arena *arena;
|
||||
@ -278,6 +279,7 @@ void sys_app_startup(struct string args_str)
|
||||
|
||||
/* Global systems */
|
||||
resource_startup();
|
||||
watch_startup();
|
||||
gp_startup();
|
||||
|
||||
/* Subsystems */
|
||||
|
||||
@ -54,8 +54,8 @@ void arena_release(struct arena *arena)
|
||||
ASAN_UNPOISON(arena, arena->committed + ARENA_HEADER_SIZE);
|
||||
__prof;
|
||||
__proffree(arena);
|
||||
gstat_add(GSTAT_MEMORY_COMMITTED, -arena->committed - ARENA_HEADER_SIZE);
|
||||
gstat_add(GSTAT_MEMORY_RESERVED, -arena->reserved);
|
||||
gstat_add(GSTAT_MEMORY_COMMITTED, -(i64)(arena->committed - ARENA_HEADER_SIZE));
|
||||
gstat_add(GSTAT_MEMORY_RESERVED, -(i64)(arena->reserved));
|
||||
gstat_add(GSTAT_NUM_ARENAS, -1);
|
||||
sys_memory_release(arena);
|
||||
}
|
||||
|
||||
24
src/common.h
24
src/common.h
@ -119,7 +119,7 @@ extern "C" {
|
||||
* ========================== */
|
||||
|
||||
/* Compile time assert */
|
||||
#if LANGUAGE_C && (__STDC_VERSION__ < 202311L)
|
||||
#if COMPILER_MSVC || (LANGUAGE_C && __STDC_VERSION__ < 202311L)
|
||||
# if COMPILER_MSVC
|
||||
# define STATIC_ASSERT3(cond, line) struct STATIC_ASSERT_____##line {int foo[(cond) ? 1 : -1];}
|
||||
# define STATIC_ASSERT2(cond, line) STATIC_ASSERT3(cond, line)
|
||||
@ -265,7 +265,7 @@ void __asan_unpoison_memory_region(void const volatile *add, size_t);
|
||||
#endif
|
||||
|
||||
/* alignas */
|
||||
#if (LANGUAGE_C && (__STDC_VERSION__ < 202311L))
|
||||
#if COMPILER_MSVC || (LANGUAGE_C && __STDC_VERSION__ < 202311L)
|
||||
# if COMPILER_MSVC
|
||||
# define alignas(n) __declspec(align(n))
|
||||
# else
|
||||
@ -276,10 +276,14 @@ void __asan_unpoison_memory_region(void const volatile *add, size_t);
|
||||
/* Field macros */
|
||||
#define FIELD_SIZEOF(type, field) sizeof(((type *)0)->field)
|
||||
|
||||
#if COMPILER_MSVC && !defined _CRT_USE_BUILTIN_OFFSETOF
|
||||
# define offsetof(type, field) ((u64)&(((type *)0)->field))
|
||||
#else
|
||||
# define offsetof(type, field) __builtin_offsetof(type, field)
|
||||
#if 0
|
||||
#if !COMPILER_MSVC
|
||||
# if !defined _CRT_USE_BUILTIN_OFFSETOF
|
||||
# define offsetof(type, field) ((u64)&(((type *)0)->field))
|
||||
# else
|
||||
# define offsetof(type, field) __builtin_offsetof(type, field)
|
||||
# endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Array */
|
||||
@ -682,10 +686,10 @@ INLINE f64 clamp_f64(f64 v, f64 min, f64 max) { return v < min ? min : v > max ?
|
||||
|
||||
#include "prof_tracy.h"
|
||||
|
||||
#define PROF_THREAD_GROUP_FIBERS -GIBI(1)
|
||||
#define PROF_THREAD_GROUP_SCHEDULER -MEBI(3)
|
||||
#define PROF_THREAD_GROUP_WINDOW -MEBI(2)
|
||||
#define PROF_THREAD_GROUP_MAIN -MEBI(1)
|
||||
#define PROF_THREAD_GROUP_FIBERS -(i64)GIBI(1)
|
||||
#define PROF_THREAD_GROUP_SCHEDULER -(i64)MEBI(3)
|
||||
#define PROF_THREAD_GROUP_WINDOW -(i64)MEBI(2)
|
||||
#define PROF_THREAD_GROUP_MAIN -(i64)MEBI(1)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@ -73,7 +73,7 @@
|
||||
#define COLLIDER_DEBUG_DETAILED 1
|
||||
#define COLLIDER_DEBUG_DETAILED_DRAW_MENKOWSKI 1
|
||||
|
||||
#define FLOOD_DEBUG 1
|
||||
#define FLOOD_DEBUG 0
|
||||
|
||||
/* If enabled, bitbuffs will insert/verify magic numbers & length for each read & write */
|
||||
#define BITBUFF_DEBUG 0
|
||||
|
||||
69
src/dxc.cpp
Normal file
69
src/dxc.cpp
Normal file
@ -0,0 +1,69 @@
|
||||
extern "C"
|
||||
{
|
||||
#include "dxc.h"
|
||||
#include "arena.h"
|
||||
#include "string.h"
|
||||
}
|
||||
|
||||
#pragma clang diagnostic ignored "-Wlanguage-extension-token"
|
||||
#include <Windows.h>
|
||||
#include <atlbase.h>
|
||||
#include <dxcapi.h>
|
||||
#include <d3d12shader.h>
|
||||
|
||||
#pragma comment(lib, "d3dcompiler")
|
||||
#pragma comment(lib, "dxcompiler")
|
||||
|
||||
/* https://github.com/microsoft/DirectXShaderCompiler/wiki/Using-dxc.exe-and-dxcompiler.dll */
|
||||
struct dxc_compile_result dxc_compile(struct arena *arena, string shader_source, i32 num_args, struct string *args)
|
||||
{
|
||||
__prof;
|
||||
struct arena_temp scratch = scratch_begin(arena);
|
||||
struct dxc_compile_result res = ZI;
|
||||
|
||||
wchar_t **wstr_args = arena_push_array(scratch.arena, wchar_t *, num_args);
|
||||
for (i32 i = 0; i < num_args; ++i) {
|
||||
wstr_args[i] = wstr_from_string(scratch.arena, args[i]);
|
||||
}
|
||||
|
||||
DxcBuffer dxc_src_buffer = ZI;
|
||||
dxc_src_buffer.Ptr = shader_source.text;
|
||||
dxc_src_buffer.Size = shader_source.len;
|
||||
dxc_src_buffer.Encoding = DXC_CP_UTF8;
|
||||
|
||||
/* Init compiler */
|
||||
CComPtr<IDxcUtils> dxc_utils;
|
||||
CComPtr<IDxcCompiler3> dxc_compiler;
|
||||
CComPtr<IDxcIncludeHandler> dxc_include_handler;
|
||||
DxcCreateInstance(CLSID_DxcUtils, IID_PPV_ARGS(&dxc_utils));
|
||||
DxcCreateInstance(CLSID_DxcCompiler, IID_PPV_ARGS(&dxc_compiler));
|
||||
dxc_utils->CreateDefaultIncludeHandler(&dxc_include_handler);
|
||||
|
||||
/* Compile */
|
||||
CComPtr<IDxcResult> compile_results = 0;
|
||||
dxc_compiler->Compile(&dxc_src_buffer, (LPCWSTR *)wstr_args, num_args, dxc_include_handler, IID_PPV_ARGS(&compile_results));
|
||||
|
||||
/* Copy errors */
|
||||
CComPtr<IDxcBlobUtf8> dxc_errors = 0;
|
||||
compile_results->GetOutput(DXC_OUT_ERRORS, IID_PPV_ARGS(&dxc_errors), 0);
|
||||
if (dxc_errors != 0) {
|
||||
res.errors = string_copy(arena, STRING(dxc_errors->GetStringLength(), (u8 *)dxc_errors->GetBufferPointer()));
|
||||
}
|
||||
|
||||
/* Get status */
|
||||
HRESULT dxc_hr = 0;
|
||||
compile_results->GetStatus(&dxc_hr);
|
||||
res.success = SUCCEEDED(dxc_hr);
|
||||
|
||||
/* Copy shader output */
|
||||
if (res.success) {
|
||||
CComPtr<IDxcBlob> dxc_shader = 0;
|
||||
compile_results->GetOutput(DXC_OUT_OBJECT, IID_PPV_ARGS(&dxc_shader), 0);
|
||||
if (dxc_shader != 0) {
|
||||
res.dxc = string_copy(arena, STRING(dxc_shader->GetBufferSize(), (u8 *)dxc_shader->GetBufferPointer()));
|
||||
}
|
||||
}
|
||||
|
||||
scratch_end(scratch);
|
||||
return res;
|
||||
}
|
||||
12
src/dxc.h
Normal file
12
src/dxc.h
Normal file
@ -0,0 +1,12 @@
|
||||
#ifndef DXC_H
|
||||
#define DXC_H
|
||||
|
||||
struct dxc_compile_result {
|
||||
struct string dxc;
|
||||
struct string errors;
|
||||
b32 success;
|
||||
};
|
||||
|
||||
struct dxc_compile_result dxc_compile(struct arena *arena, struct string shader_source, i32 num_args, struct string *args);
|
||||
|
||||
#endif
|
||||
745
src/gp_dx12.c
745
src/gp_dx12.c
File diff suppressed because it is too large
Load Diff
@ -13,3 +13,10 @@ struct string inc_res_tar(void)
|
||||
return INCBIN_GET(res_tar);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
INCBIN_INCLUDE(dxc_tar, INCBIN_DIR "dxc.tar");
|
||||
struct string inc_dxc_tar(void)
|
||||
{
|
||||
return INCBIN_GET(dxc_tar);
|
||||
}
|
||||
|
||||
@ -5,4 +5,6 @@
|
||||
struct string inc_res_tar(void);
|
||||
#endif
|
||||
|
||||
struct string inc_dxc_tar(void);
|
||||
|
||||
#endif
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
* ========================== */
|
||||
|
||||
#include "incbin.h"
|
||||
#include "scratch.h"
|
||||
#include "arena.h"
|
||||
#include "string.h"
|
||||
#include "atomic.h"
|
||||
#include "intrinsics.h"
|
||||
|
||||
@ -16,6 +16,10 @@
|
||||
#define COBJMACROS
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#define UNICODE
|
||||
#define WINVER 0x0A00
|
||||
#define _WIN32_WINNT 0x0A00
|
||||
#define NTDDI_WIN11_DT 0x0C0A0000
|
||||
#define NTDDI_VERSION 0x0A000000
|
||||
#include <Windows.h>
|
||||
#include <initguid.h>
|
||||
#include <objbase.h>
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
#ifndef PROF_H
|
||||
#define PROF_H
|
||||
|
||||
#if PROFILING
|
||||
|
||||
#if COMPILER_MSVC
|
||||
# error "MSVC not supported for profiling (cleanup attributes are required for profiling markup)"
|
||||
#endif
|
||||
|
||||
#if PROFILING
|
||||
|
||||
#define PROFILING_SYSTEM_TRACE 0
|
||||
#define PROFILING_CAPTURE_FRAME_IMAGE 0
|
||||
#define PROFILING_LOCKS 0
|
||||
|
||||
197
src/resource.c
197
src/resource.c
@ -21,33 +21,12 @@ GLOBAL struct {
|
||||
#if RESOURCES_EMBEDDED
|
||||
struct tar_archive archive;
|
||||
#endif
|
||||
|
||||
#if RESOURCE_RELOADING
|
||||
struct sys_watch *watch;
|
||||
struct atomic32 watch_shutdown;
|
||||
struct snc_counter watch_jobs_counter;
|
||||
|
||||
struct snc_mutex watch_dispatcher_mutex;
|
||||
struct arena *watch_dispatcher_info_arena;
|
||||
struct sys_watch_info_list watch_dispatcher_info_list;
|
||||
struct snc_cv watch_dispatcher_cv;
|
||||
|
||||
struct snc_mutex watch_callbacks_mutex;
|
||||
resource_watch_callback *watch_callbacks[64];
|
||||
u64 num_watch_callbacks;
|
||||
#endif
|
||||
} G = ZI, DEBUG_ALIAS(G, G_resource);
|
||||
|
||||
/* ========================== *
|
||||
* Startup
|
||||
* ========================== */
|
||||
|
||||
#if RESOURCE_RELOADING
|
||||
INTERNAL SYS_JOB_DEF(resource_watch_monitor_job, _);
|
||||
INTERNAL SYS_JOB_DEF(resource_watch_dispatcher_job, _);
|
||||
INTERNAL SYS_EXIT_FUNC(resource_shutdown);
|
||||
#endif
|
||||
|
||||
struct resource_startup_receipt resource_startup(void)
|
||||
{
|
||||
__prof;
|
||||
@ -66,17 +45,6 @@ struct resource_startup_receipt resource_startup(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
#if RESOURCE_RELOADING
|
||||
G.watch = sys_watch_alloc(LIT("res"));
|
||||
|
||||
G.watch_dispatcher_info_arena = arena_alloc(GIBI(64));
|
||||
|
||||
sys_run(1, resource_watch_monitor_job, 0, SYS_POOL_FLOATING, SYS_PRIORITY_LOW, &G.watch_jobs_counter);
|
||||
sys_run(1, resource_watch_dispatcher_job, 0, SYS_POOL_BACKGROUND, SYS_PRIORITY_LOW, &G.watch_jobs_counter);
|
||||
sys_on_exit(&resource_shutdown);
|
||||
#endif
|
||||
|
||||
|
||||
return (struct resource_startup_receipt) { 0 };
|
||||
}
|
||||
|
||||
@ -90,11 +58,9 @@ struct resource resource_open(struct string name)
|
||||
#if RESOURCES_EMBEDDED
|
||||
struct resource res = ZI;
|
||||
struct tar_entry *entry = tar_get(&G.archive, name);
|
||||
if (entry) {
|
||||
res._data = entry->data;
|
||||
res._name = entry->file_name;
|
||||
res._exists = 1;
|
||||
}
|
||||
res._data = entry->data;
|
||||
res._name = entry->file_name;
|
||||
res._exists = entry->valid;
|
||||
return res;
|
||||
#else
|
||||
struct resource res = ZI;
|
||||
@ -146,160 +112,3 @@ void resource_close(struct resource *res_ptr)
|
||||
sys_file_close(res_ptr->_file);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* ========================== *
|
||||
* Watch
|
||||
* ========================== */
|
||||
|
||||
#if RESOURCE_RELOADING
|
||||
|
||||
INTERNAL SYS_EXIT_FUNC(resource_shutdown)
|
||||
{
|
||||
__prof;
|
||||
atomic32_fetch_set(&G.watch_shutdown, 1);
|
||||
|
||||
{
|
||||
struct snc_lock lock = snc_lock_e(&G.watch_dispatcher_mutex);
|
||||
snc_cv_signal(&G.watch_dispatcher_cv, I32_MAX);
|
||||
sys_watch_wake(G.watch);
|
||||
snc_unlock(&lock);
|
||||
}
|
||||
snc_counter_wait(&G.watch_jobs_counter);
|
||||
}
|
||||
|
||||
void resource_register_watch_callback(resource_watch_callback *callback)
|
||||
{
|
||||
struct snc_lock lock = snc_lock_e(&G.watch_callbacks_mutex);
|
||||
{
|
||||
if (G.num_watch_callbacks < countof(G.watch_callbacks)) {
|
||||
G.watch_callbacks[G.num_watch_callbacks++] = callback;
|
||||
} else {
|
||||
sys_panic(LIT("Max resource watch callbacks reached"));
|
||||
}
|
||||
}
|
||||
snc_unlock(&lock);
|
||||
}
|
||||
|
||||
INTERNAL SYS_JOB_DEF(resource_watch_monitor_job, _)
|
||||
{
|
||||
(UNUSED)_;
|
||||
struct arena_temp scratch = scratch_begin_no_conflict();
|
||||
|
||||
while (!atomic32_fetch(&G.watch_shutdown)) {
|
||||
struct arena_temp temp = arena_temp_begin(scratch.arena);
|
||||
struct sys_watch_info_list res = sys_watch_read_wait(temp.arena, G.watch);
|
||||
if (res.first && !atomic32_fetch(&G.watch_shutdown)) {
|
||||
struct snc_lock lock = snc_lock_e(&G.watch_dispatcher_mutex);
|
||||
{
|
||||
struct sys_watch_info_list list_part = sys_watch_info_copy(G.watch_dispatcher_info_arena, res);
|
||||
if (G.watch_dispatcher_info_list.last) {
|
||||
G.watch_dispatcher_info_list.last->next = list_part.first;
|
||||
list_part.first->prev = G.watch_dispatcher_info_list.last;
|
||||
G.watch_dispatcher_info_list.last = list_part.last;
|
||||
} else {
|
||||
G.watch_dispatcher_info_list = list_part;
|
||||
}
|
||||
}
|
||||
snc_cv_signal(&G.watch_dispatcher_cv, I32_MAX);
|
||||
snc_unlock(&lock);
|
||||
}
|
||||
arena_temp_end(temp);
|
||||
}
|
||||
|
||||
scratch_end(scratch);
|
||||
}
|
||||
|
||||
/* 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. */
|
||||
|
||||
#define WATCH_DISPATCHER_DELAY_SECONDS 0.050
|
||||
#define WATCH_DISPATCHER_DEDUP_DICT_BINS 128
|
||||
|
||||
struct resource_watch_callback_job_sig {
|
||||
struct string name;
|
||||
resource_watch_callback **callbacks;
|
||||
};
|
||||
|
||||
INTERNAL SYS_JOB_DEF(resource_watch_callback_job, job)
|
||||
{
|
||||
__prof;
|
||||
struct resource_watch_callback_job_sig *sig = job.sig;
|
||||
struct string name = sig->name;
|
||||
resource_watch_callback *callback = sig->callbacks[job.id];
|
||||
callback(name);
|
||||
}
|
||||
|
||||
INTERNAL SYS_JOB_DEF(resource_watch_dispatcher_job, _)
|
||||
{
|
||||
(UNUSED)_;
|
||||
struct arena_temp scratch = scratch_begin_no_conflict();
|
||||
|
||||
struct snc_lock watch_dispatcher_lock = snc_lock_e(&G.watch_dispatcher_mutex);
|
||||
while (!atomic32_fetch(&G.watch_shutdown)) {
|
||||
snc_cv_wait(&G.watch_dispatcher_cv, &watch_dispatcher_lock);
|
||||
if (!atomic32_fetch(&G.watch_shutdown) && G.watch_dispatcher_info_arena->pos > 0) {
|
||||
__profn("Dispatch resource watch callbacks");
|
||||
/* Unlock and sleep a bit so duplicate events pile up */
|
||||
{
|
||||
__profn("Delay");
|
||||
snc_unlock(&watch_dispatcher_lock);
|
||||
sys_wait(0, 0, 0, NS_FROM_SECONDS(WATCH_DISPATCHER_DELAY_SECONDS));
|
||||
watch_dispatcher_lock = snc_lock_e(&G.watch_dispatcher_mutex);
|
||||
}
|
||||
if (!atomic32_fetch(&G.watch_shutdown)) {
|
||||
struct arena_temp temp = arena_temp_begin(scratch.arena);
|
||||
|
||||
/* Pull watch info from queue */
|
||||
struct sys_watch_info_list watch_info_list = sys_watch_info_copy(temp.arena, G.watch_dispatcher_info_list);
|
||||
MEMZERO_STRUCT(&G.watch_dispatcher_info_list);
|
||||
arena_reset(G.watch_dispatcher_info_arena);
|
||||
|
||||
/* Build callbacks array */
|
||||
u64 num_callbacks = 0;
|
||||
resource_watch_callback **callbacks = 0;
|
||||
struct snc_lock callbacks_lock = snc_lock_s(&G.watch_callbacks_mutex);
|
||||
{
|
||||
num_callbacks = G.num_watch_callbacks;
|
||||
callbacks = arena_push_array_no_zero(temp.arena, resource_watch_callback *, num_callbacks);
|
||||
for (u64 i = 0; i < num_callbacks; ++i) {
|
||||
callbacks[i] = G.watch_callbacks[i];
|
||||
}
|
||||
}
|
||||
snc_unlock(&callbacks_lock);
|
||||
|
||||
/* Unlock and run callbacks */
|
||||
snc_unlock(&watch_dispatcher_lock);
|
||||
{
|
||||
struct dict *dedup_dict = dict_init(temp.arena, WATCH_DISPATCHER_DEDUP_DICT_BINS);
|
||||
for (struct sys_watch_info *info = watch_info_list.first; info; info = info->next) {
|
||||
__profn("Dispatch");
|
||||
/* Do not run callbacks for the same file more than once */
|
||||
b32 skip = 0;
|
||||
u64 hash = hash_fnv64(HASH_FNV64_BASIS, info->name);
|
||||
if (dict_get(dedup_dict, hash) == 1) {
|
||||
skip = 1;
|
||||
} else {
|
||||
dict_set(temp.arena, dedup_dict, hash, 1);
|
||||
}
|
||||
if (!skip) {
|
||||
struct resource_watch_callback_job_sig sig = ZI;
|
||||
sig.name = info->name;
|
||||
sig.callbacks = callbacks;
|
||||
struct snc_counter counter = ZI;
|
||||
sys_run(num_callbacks, resource_watch_callback_job, &sig, SYS_POOL_BACKGROUND, SYS_PRIORITY_LOW, &counter);
|
||||
snc_counter_wait(&counter);
|
||||
}
|
||||
}
|
||||
}
|
||||
watch_dispatcher_lock = snc_lock_e(&G.watch_dispatcher_mutex);
|
||||
|
||||
arena_temp_end(temp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
scratch_end(scratch);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
|
||||
#include "sys.h"
|
||||
|
||||
#define RESOURCE_NAME_LEN_MAX 255
|
||||
#define RESOURCE_NAME_LEN_MAX 256
|
||||
|
||||
/* A resource contains data that can be retrieved globally by name.
|
||||
* If enabled during compilation, resource data is embedded in the
|
||||
@ -54,17 +54,4 @@ struct resource resource_open(struct string name);
|
||||
#define resource_get_name(res_ptr) STRING((res_ptr)->_name_len, (res_ptr)->_name_text)
|
||||
#endif
|
||||
|
||||
/* ========================== *
|
||||
* Watch
|
||||
* ========================== */
|
||||
|
||||
#define RESOURCE_WATCH_CALLBACK_FUNC_DEF(func_name, arg_name) void func_name(struct string arg_name)
|
||||
typedef RESOURCE_WATCH_CALLBACK_FUNC_DEF(resource_watch_callback, name);
|
||||
|
||||
#if RESOURCE_RELOADING
|
||||
void resource_register_watch_callback(resource_watch_callback *callback);
|
||||
#else
|
||||
#define resource_register_watch_callback(callback)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
3
src/sh/blit.d
Normal file
3
src/sh/blit.d
Normal file
@ -0,0 +1,3 @@
|
||||
C:\Users\Jacob\Home\dev\repos\power_play\build\clang-developer-debug\dxc\blit.dxc_ps: C:\Users\Jacob\Home\dev\repos\power_play\src\sh\blit.hlsl_rs \
|
||||
C:\Users\Jacob\Home\dev\repos\power_play\src\sh/common.hlsl \
|
||||
C:\Users\Jacob\Home\dev\repos\power_play\src\sh/sh_common.h
|
||||
@ -1,4 +1,4 @@
|
||||
#include "sh/common.hlsl"
|
||||
#include "common.hlsl"
|
||||
|
||||
/* ========================== *
|
||||
* Root signature
|
||||
@ -1,4 +1,4 @@
|
||||
#include "sh/sh_common.h"
|
||||
#include "sh_common.h"
|
||||
|
||||
#define TAU 6.28318530718
|
||||
#define PI 3.14159265359
|
||||
3
src/sh/flood.d
Normal file
3
src/sh/flood.d
Normal file
@ -0,0 +1,3 @@
|
||||
C:\Users\Jacob\Home\dev\repos\power_play\build\clang-developer-debug\dxc\flood.dxc_cs: C:\Users\Jacob\Home\dev\repos\power_play\src\sh\flood.hlsl_cs \
|
||||
C:\Users\Jacob\Home\dev\repos\power_play\src\sh/common.hlsl \
|
||||
C:\Users\Jacob\Home\dev\repos\power_play\src\sh/sh_common.h
|
||||
@ -1,4 +1,4 @@
|
||||
#include "sh/common.hlsl"
|
||||
#include "common.hlsl"
|
||||
|
||||
/* ========================== *
|
||||
* Root signature
|
||||
3
src/sh/material.d
Normal file
3
src/sh/material.d
Normal file
@ -0,0 +1,3 @@
|
||||
C:\Users\Jacob\Home\dev\repos\power_play\build\clang-developer-debug\dxc\material.dxc_ps: C:\Users\Jacob\Home\dev\repos\power_play\src\sh\material.hlsl_rs \
|
||||
C:\Users\Jacob\Home\dev\repos\power_play\src\sh/common.hlsl \
|
||||
C:\Users\Jacob\Home\dev\repos\power_play\src\sh/sh_common.h
|
||||
@ -1,4 +1,4 @@
|
||||
#include "sh/common.hlsl"
|
||||
#include "common.hlsl"
|
||||
|
||||
/* ========================== *
|
||||
* Root signature
|
||||
@ -4,9 +4,9 @@
|
||||
#define SH_DECL(t, n) struct CAT(sh_, t) n
|
||||
#define SH_DECLS(t, n) SH_DECL(t, n)
|
||||
#define SH_ENTRY(rootsig) static
|
||||
#define SH_ASSERT_ROOT_CONST(s, n) STATIC_ASSERT(sizeof(s) % 16 == 0); /* Root constant struct should pad to 16 byte alignment */ \
|
||||
STATIC_ASSERT((sizeof(s) / 4) == n); /* Root constant struct size should match the specified 32-bit-constant count */ \
|
||||
STATIC_ASSERT((sizeof(s) <= 256)) /* Root constant struct can only fit 64 DWORDS */
|
||||
#define SH_ASSERT_ROOT_CONST(s, n) STATIC_ASSERT((sizeof(s) % 16 == 0) && /* Root constant struct should pad to 16 byte alignment */ \
|
||||
((sizeof(s) / 4) == n) && /* Root constant struct size should match the specified 32-bit-constant count */ \
|
||||
(sizeof(s) <= 256)) /* Root constant struct can only fit 64 DWORDS */
|
||||
|
||||
struct sh_uint { u32 v; };
|
||||
INLINE struct sh_uint sh_uint_from_u32(u32 v)
|
||||
3
src/sh/shade.d
Normal file
3
src/sh/shade.d
Normal file
@ -0,0 +1,3 @@
|
||||
C:\Users\Jacob\Home\dev\repos\power_play\build\clang-developer-debug\dxc\shade.dxc_cs: C:\Users\Jacob\Home\dev\repos\power_play\src\sh\shade.hlsl_cs \
|
||||
C:\Users\Jacob\Home\dev\repos\power_play\src\sh/common.hlsl \
|
||||
C:\Users\Jacob\Home\dev\repos\power_play\src\sh/sh_common.h
|
||||
@ -1,4 +1,4 @@
|
||||
#include "sh/common.hlsl"
|
||||
#include "common.hlsl"
|
||||
|
||||
/* ========================== *
|
||||
* Root signature
|
||||
@ -69,7 +69,6 @@ INLINE float3 get_light_in_dir(uint2 ray_start, float2 ray_dir)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
3
src/sh/shape.d
Normal file
3
src/sh/shape.d
Normal file
@ -0,0 +1,3 @@
|
||||
C:\Users\Jacob\Home\dev\repos\power_play\build\clang-developer-debug\dxc\shape.dxc_ps: C:\Users\Jacob\Home\dev\repos\power_play\src\sh\shape.hlsl_rs \
|
||||
C:\Users\Jacob\Home\dev\repos\power_play\src\sh/common.hlsl \
|
||||
C:\Users\Jacob\Home\dev\repos\power_play\src\sh/sh_common.h
|
||||
@ -1,4 +1,4 @@
|
||||
#include "sh/common.hlsl"
|
||||
#include "common.hlsl"
|
||||
|
||||
/* ========================== *
|
||||
* Root signature
|
||||
3
src/sh/ui.d
Normal file
3
src/sh/ui.d
Normal file
@ -0,0 +1,3 @@
|
||||
C:\Users\Jacob\Home\dev\repos\power_play\build\clang-developer-debug\dxc\ui.dxc_ps: C:\Users\Jacob\Home\dev\repos\power_play\src\sh\ui.hlsl_rs \
|
||||
C:\Users\Jacob\Home\dev\repos\power_play\src\sh/common.hlsl \
|
||||
C:\Users\Jacob\Home\dev\repos\power_play\src\sh/sh_common.h
|
||||
@ -1,4 +1,4 @@
|
||||
#include "sh/common.hlsl"
|
||||
#include "common.hlsl"
|
||||
|
||||
/* ========================== *
|
||||
* Root signature
|
||||
12
src/sprite.c
12
src/sprite.c
@ -11,6 +11,7 @@
|
||||
#include "math.h"
|
||||
#include "rand.h"
|
||||
#include "snc.h"
|
||||
#include "watch.h"
|
||||
|
||||
/* The evictor will begin evicting once cache usage is > threshold.
|
||||
* It will entries until the budget has shrunk < target. */
|
||||
@ -205,7 +206,7 @@ INTERNAL SYS_JOB_DEF(sprite_load_job, arg);
|
||||
INTERNAL SYS_JOB_DEF(sprite_evictor_job, _);
|
||||
|
||||
#if RESOURCE_RELOADING
|
||||
INTERNAL RESOURCE_WATCH_CALLBACK_FUNC_DEF(sprite_resource_watch_callback, info);
|
||||
INTERNAL WATCH_CALLBACK_FUNC_DEF(sprite_watch_callback, info);
|
||||
#endif
|
||||
|
||||
struct sprite_startup_receipt sprite_startup(void)
|
||||
@ -249,7 +250,7 @@ struct sprite_startup_receipt sprite_startup(void)
|
||||
sys_run(1, sprite_evictor_job, 0, SYS_POOL_BACKGROUND, SYS_PRIORITY_LOW, &G.shutdown_counter);
|
||||
|
||||
sys_on_exit(&sprite_shutdown);
|
||||
resource_register_watch_callback(&sprite_resource_watch_callback);
|
||||
watch_register_callback(&sprite_watch_callback);
|
||||
|
||||
return (struct sprite_startup_receipt) { 0 };
|
||||
}
|
||||
@ -1173,10 +1174,15 @@ INTERNAL void reload_if_exists(struct sprite_scope *scope, struct sprite_tag tag
|
||||
}
|
||||
}
|
||||
|
||||
INTERNAL RESOURCE_WATCH_CALLBACK_FUNC_DEF(sprite_resource_watch_callback, name)
|
||||
INTERNAL WATCH_CALLBACK_FUNC_DEF(sprite_watch_callback, name)
|
||||
{
|
||||
struct sprite_scope *scope = sprite_scope_begin();
|
||||
|
||||
if (string_starts_with(name, LIT("res/"))) {
|
||||
name.len -= LIT("res/").len;
|
||||
name.text += LIT("res/").len;
|
||||
}
|
||||
|
||||
struct sprite_tag tag = sprite_tag_from_path(name);
|
||||
for (enum cache_entry_kind kind = 0; kind < NUM_CACHE_ENTRY_KINDS; ++kind) {
|
||||
reload_if_exists(scope, tag, kind);
|
||||
|
||||
60
src/string.c
60
src/string.c
@ -225,44 +225,38 @@ struct string string_cat(struct arena *arena, struct string str1, struct string
|
||||
return new_str;
|
||||
}
|
||||
|
||||
/* `arena` is where pieces items will be allocated. These strings point
|
||||
* into the existing supplied string and do not allocate any new text. */
|
||||
/* `arena` is where pieces will be allocated. These strings point
|
||||
* into the existing string and do not allocate any new text. */
|
||||
struct string_array string_split(struct arena *arena, struct string str, struct string delim)
|
||||
{
|
||||
struct string_array pieces = {
|
||||
.count = 0,
|
||||
.strings = arena_push_dry(arena, struct string)
|
||||
};
|
||||
struct string_array pieces = ZI;
|
||||
pieces.strings = arena_push_dry(arena, struct string);
|
||||
i64 piece_start = 0;
|
||||
for (i64 i = 0; i < (i64)str.len - (i64)delim.len; ++i) {
|
||||
struct string cmp = ZI;
|
||||
cmp.text = &str.text[i];
|
||||
cmp.len = min_i64(str.len - i, delim.len);
|
||||
|
||||
struct string piece = {
|
||||
.len = 0,
|
||||
.text = str.text
|
||||
};
|
||||
|
||||
for (u64 i = 0; i <= str.len - delim.len; ++i) {
|
||||
/* Clamp comparison string so we don't overflow. */
|
||||
struct string comp_str = {
|
||||
.len = delim.len,
|
||||
.text = &str.text[i]
|
||||
};
|
||||
|
||||
b32 is_delimiter = string_eq(comp_str, delim);
|
||||
b32 is_end = i == str.len - 1;
|
||||
|
||||
if (!is_delimiter || is_end) {
|
||||
++piece.len;
|
||||
}
|
||||
|
||||
if (is_delimiter || is_end) {
|
||||
/* Delimiter found */
|
||||
struct string *piece_pushed = arena_push_no_zero(arena, struct string);
|
||||
*piece_pushed = piece;
|
||||
++pieces.count;
|
||||
piece.text = piece.text + piece.len + delim.len;
|
||||
piece.len = 0;
|
||||
b32 is_delimiter = string_eq(cmp, delim);
|
||||
if (is_delimiter) {
|
||||
struct string piece = ZI;
|
||||
piece.text = &str.text[piece_start];
|
||||
piece.len = i - piece_start;
|
||||
i += delim.len;
|
||||
piece_start = i;
|
||||
if (piece.len > 0) {
|
||||
*arena_push_no_zero(arena, struct string) = piece;
|
||||
++pieces.count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (piece_start < (i64)str.len) {
|
||||
struct string piece = ZI;
|
||||
piece.text = &str.text[piece_start];
|
||||
piece.len = str.len - piece_start;
|
||||
*arena_push_no_zero(arena, struct string) = piece;
|
||||
++pieces.count;
|
||||
}
|
||||
return pieces;
|
||||
}
|
||||
|
||||
|
||||
@ -8,8 +8,7 @@ struct snc_counter;
|
||||
* ========================== */
|
||||
|
||||
/* Futex-like wait & wake */
|
||||
|
||||
void sys_wait(void *addr, void *cmp, u32 size, i64 timeout_ns);
|
||||
void sys_wait(volatile void *addr, void *cmp, u32 size, i64 timeout_ns);
|
||||
void sys_wake(void *addr, i32 count);
|
||||
|
||||
/* ========================== *
|
||||
@ -232,8 +231,6 @@ struct sys_watch_info_list sys_watch_read_wait(struct arena *arena, struct sys_w
|
||||
|
||||
void sys_watch_wake(struct sys_watch *dw);
|
||||
|
||||
struct sys_watch_info_list sys_watch_info_copy(struct arena *arena, struct sys_watch_info_list src);
|
||||
|
||||
/* ========================== *
|
||||
* Window
|
||||
* ========================== */
|
||||
|
||||
@ -481,7 +481,7 @@ INTERNAL b32 thread_try_release(struct thread *thread, f32 timeout_seconds)
|
||||
HANDLE handle = t->handle;
|
||||
if (handle) {
|
||||
/* Wait for thread to stop */
|
||||
DWORD timeout_ms = (timeout_seconds == F32_INFINITY) ? INFINITE : math_round_to_int(timeout_seconds * 1000);
|
||||
DWORD timeout_ms = (timeout_seconds > 10000000) ? INFINITE : math_round_to_int(timeout_seconds * 1000);
|
||||
DWORD wait_res = WaitForSingleObject(handle, timeout_ms);
|
||||
if (wait_res == WAIT_OBJECT_0) {
|
||||
/* Release thread */
|
||||
@ -524,7 +524,7 @@ INTERNAL void thread_wait_release(struct thread *thread)
|
||||
* Wait / wake
|
||||
* ========================== */
|
||||
|
||||
void sys_wait(void *addr, void *cmp, u32 size, i64 timeout_ns)
|
||||
void sys_wait(volatile void *addr, void *cmp, u32 size, i64 timeout_ns)
|
||||
{
|
||||
struct fiber *fiber = fiber_from_id(sys_current_fiber_id());
|
||||
i16 parent_id = fiber->parent_id;
|
||||
@ -541,7 +541,7 @@ void sys_wait(void *addr, void *cmp, u32 size, i64 timeout_ns)
|
||||
job_fiber_yield(fiber, fiber_from_id(parent_id));
|
||||
} else {
|
||||
i32 timeout_ms = 0;
|
||||
if (timeout_ns == I64_MAX) {
|
||||
if (timeout_ns > 10000000000000000ll) {
|
||||
timeout_ms = INFINITE;
|
||||
} else if (timeout_ns != 0) {
|
||||
timeout_ms = timeout_ns / 1000000;
|
||||
@ -1258,7 +1258,7 @@ INTERNAL THREAD_DEF(job_worker_entry, worker_ctx_arg)
|
||||
tm_unlock(&G.wait_lists_arena_lock);
|
||||
}
|
||||
MEMZERO_STRUCT(wait_addr_list);
|
||||
wait_addr_list->value = wait_addr;
|
||||
wait_addr_list->value = (u64)wait_addr;
|
||||
if (wait_addr_bin->last_wait_list) {
|
||||
wait_addr_bin->last_wait_list->next_in_bin = wait_addr_list;
|
||||
wait_addr_list->prev_in_bin = wait_addr_bin->last_wait_list;
|
||||
@ -1268,7 +1268,7 @@ INTERNAL THREAD_DEF(job_worker_entry, worker_ctx_arg)
|
||||
wait_addr_bin->last_wait_list = wait_addr_list;
|
||||
}
|
||||
/* Insert fiber into wait addr list */
|
||||
job_fiber->wait_addr = wait_addr;
|
||||
job_fiber->wait_addr = (u64)wait_addr;
|
||||
if (wait_addr_list->last_waiter) {
|
||||
fiber_from_id(wait_addr_list->last_waiter)->next_addr_waiter = job_fiber_id;
|
||||
job_fiber->prev_addr_waiter = wait_addr_list->last_waiter;
|
||||
@ -2107,26 +2107,6 @@ void sys_watch_wake(struct sys_watch *dw)
|
||||
SetEvent(w32_watch->wake_handle);
|
||||
}
|
||||
|
||||
struct sys_watch_info_list sys_watch_info_copy(struct arena *arena, struct sys_watch_info_list src_list)
|
||||
{
|
||||
struct sys_watch_info_list dst_list = ZI;
|
||||
for (struct sys_watch_info *src = src_list.first; src; src = src->next) {
|
||||
struct sys_watch_info *dst = arena_push(arena, struct sys_watch_info);
|
||||
dst->kind = src->kind;
|
||||
dst->name = string_copy(arena, src->name);
|
||||
if (dst_list.last) {
|
||||
dst_list.last->next = dst;
|
||||
dst->prev = dst_list.last;
|
||||
dst_list.last = dst;
|
||||
} else {
|
||||
dst_list.first = dst;
|
||||
dst_list.last = dst;
|
||||
}
|
||||
dst_list.count = src_list.count;
|
||||
}
|
||||
return dst_list;
|
||||
}
|
||||
|
||||
/* ========================== *
|
||||
* Window
|
||||
* ========================== */
|
||||
|
||||
@ -120,6 +120,7 @@ struct tar_archive tar_parse(struct arena *arena, struct string data, struct str
|
||||
struct string file_name = string_cat(arena, prefix, file_name_cstr);
|
||||
|
||||
struct tar_entry *entry = arena_push(arena, struct tar_entry);
|
||||
entry->valid = 1;
|
||||
entry->is_dir = is_dir;
|
||||
entry->file_name = file_name;
|
||||
entry->data = file_data;
|
||||
@ -162,8 +163,10 @@ struct tar_archive tar_parse(struct arena *arena, struct string data, struct str
|
||||
return archive;
|
||||
}
|
||||
|
||||
READONLY GLOBAL struct tar_entry g_nil_tar_entry = ZI;
|
||||
struct tar_entry *tar_get(struct tar_archive *archive, struct string name)
|
||||
{
|
||||
u64 hash = hash_fnv64(HASH_FNV64_BASIS, name);
|
||||
return (struct tar_entry *)dict_get(archive->lookup, hash);
|
||||
struct tar_entry *lookup = (struct tar_entry *)dict_get(archive->lookup, hash);
|
||||
return lookup ? lookup : &g_nil_tar_entry;
|
||||
}
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
#include "util.h"
|
||||
|
||||
struct tar_entry {
|
||||
b32 valid;
|
||||
struct string file_name;
|
||||
struct string data;
|
||||
|
||||
|
||||
@ -266,7 +266,7 @@ INLINE void sleep_precise(i64 sleep_time_ns)
|
||||
__prof;
|
||||
|
||||
i64 big_sleep = sys_current_scheduler_period_ns();
|
||||
i64 tolerance = big_sleep * 0.5;
|
||||
i64 tolerance = (f64)big_sleep * 0.5;
|
||||
//i64 tolerance = 1000000000;
|
||||
|
||||
i64 now_ns = sys_time_ns();
|
||||
|
||||
245
src/watch.c
Normal file
245
src/watch.c
Normal file
@ -0,0 +1,245 @@
|
||||
#include "watch.h"
|
||||
|
||||
#if RESOURCE_RELOADING
|
||||
|
||||
#include "sys.h"
|
||||
#include "snc.h"
|
||||
#include "arena.h"
|
||||
#include "atomic.h"
|
||||
#include "util.h"
|
||||
#include "string.h"
|
||||
|
||||
struct watch_event {
|
||||
struct string name;
|
||||
struct watch_event *next;
|
||||
};
|
||||
|
||||
GLOBAL struct {
|
||||
struct sys_watch *watch;
|
||||
struct atomic32 watch_shutdown;
|
||||
struct snc_counter watch_jobs_counter;
|
||||
|
||||
struct snc_mutex watch_dispatcher_mutex;
|
||||
struct arena *watch_events_arena;
|
||||
struct watch_event *first_watch_event;
|
||||
struct watch_event *last_watch_event;
|
||||
struct snc_cv watch_dispatcher_cv;
|
||||
|
||||
struct snc_mutex watch_callbacks_mutex;
|
||||
watch_callback *watch_callbacks[64];
|
||||
u64 num_watch_callbacks;
|
||||
} G = ZI, DEBUG_ALIAS(G, G_watch);
|
||||
|
||||
/* ========================== *
|
||||
* Startup
|
||||
* ========================== */
|
||||
|
||||
INTERNAL SYS_JOB_DEF(watch_monitor_job, _);
|
||||
INTERNAL SYS_JOB_DEF(watch_dispatcher_job, _);
|
||||
INTERNAL SYS_EXIT_FUNC(watch_shutdown);
|
||||
|
||||
void watch_startup(void)
|
||||
{
|
||||
G.watch = sys_watch_alloc(LIT("./"));
|
||||
|
||||
G.watch_events_arena = arena_alloc(GIBI(64));
|
||||
|
||||
sys_run(1, watch_monitor_job, 0, SYS_POOL_FLOATING, SYS_PRIORITY_LOW, &G.watch_jobs_counter);
|
||||
sys_run(1, watch_dispatcher_job, 0, SYS_POOL_BACKGROUND, SYS_PRIORITY_LOW, &G.watch_jobs_counter);
|
||||
sys_on_exit(&watch_shutdown);
|
||||
}
|
||||
|
||||
/* ========================== *
|
||||
* Watch
|
||||
* ========================== */
|
||||
|
||||
INTERNAL SYS_EXIT_FUNC(watch_shutdown)
|
||||
{
|
||||
__prof;
|
||||
atomic32_fetch_set(&G.watch_shutdown, 1);
|
||||
|
||||
{
|
||||
struct snc_lock lock = snc_lock_e(&G.watch_dispatcher_mutex);
|
||||
snc_cv_signal(&G.watch_dispatcher_cv, I32_MAX);
|
||||
sys_watch_wake(G.watch);
|
||||
snc_unlock(&lock);
|
||||
}
|
||||
snc_counter_wait(&G.watch_jobs_counter);
|
||||
}
|
||||
|
||||
void watch_register_callback(watch_callback *callback)
|
||||
{
|
||||
struct snc_lock lock = snc_lock_e(&G.watch_callbacks_mutex);
|
||||
{
|
||||
if (G.num_watch_callbacks < countof(G.watch_callbacks)) {
|
||||
G.watch_callbacks[G.num_watch_callbacks++] = callback;
|
||||
} else {
|
||||
sys_panic(LIT("Max resource watch callbacks reached"));
|
||||
}
|
||||
}
|
||||
snc_unlock(&lock);
|
||||
}
|
||||
|
||||
INTERNAL SYS_JOB_DEF(watch_monitor_job, _)
|
||||
{
|
||||
(UNUSED)_;
|
||||
struct arena_temp scratch = scratch_begin_no_conflict();
|
||||
|
||||
struct string ignored[] = {
|
||||
LIT(".vs"),
|
||||
LIT(".git")
|
||||
};
|
||||
|
||||
while (!atomic32_fetch(&G.watch_shutdown)) {
|
||||
struct arena_temp temp = arena_temp_begin(scratch.arena);
|
||||
struct sys_watch_info_list info_list = sys_watch_read_wait(temp.arena, G.watch);
|
||||
if (info_list.first && !atomic32_fetch(&G.watch_shutdown)) {
|
||||
struct snc_lock lock = snc_lock_e(&G.watch_dispatcher_mutex);
|
||||
{
|
||||
for (struct sys_watch_info *info = info_list.first; info; info = info->next) {
|
||||
struct string name_src = info->name;
|
||||
b32 ignore = 0;
|
||||
for (u32 i = 0; i < countof(ignored); ++i) {
|
||||
if (string_starts_with(name_src, ignored[i])) {
|
||||
ignore = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!ignore) {
|
||||
struct watch_event *e = arena_push(G.watch_events_arena, struct watch_event);
|
||||
e->name = string_copy(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;
|
||||
}
|
||||
}
|
||||
}
|
||||
snc_cv_signal(&G.watch_dispatcher_cv, I32_MAX);
|
||||
snc_unlock(&lock);
|
||||
}
|
||||
arena_temp_end(temp);
|
||||
}
|
||||
|
||||
scratch_end(scratch);
|
||||
}
|
||||
|
||||
/* 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. */
|
||||
|
||||
#define WATCH_DISPATCHER_DELAY_SECONDS 0.050
|
||||
#define WATCH_DISPATCHER_DEDUP_DICT_BINS 128
|
||||
|
||||
struct watch_callback_job_sig {
|
||||
struct string name;
|
||||
watch_callback **callbacks;
|
||||
};
|
||||
|
||||
INTERNAL SYS_JOB_DEF(watch_callback_job, job)
|
||||
{
|
||||
__prof;
|
||||
struct watch_callback_job_sig *sig = job.sig;
|
||||
struct string name = sig->name;
|
||||
watch_callback *callback = sig->callbacks[job.id];
|
||||
callback(name);
|
||||
}
|
||||
|
||||
INTERNAL SYS_JOB_DEF(watch_dispatcher_job, _)
|
||||
{
|
||||
(UNUSED)_;
|
||||
|
||||
b32 shutdown = 0;
|
||||
while (!shutdown) {
|
||||
{
|
||||
struct arena_temp scratch = scratch_begin_no_conflict();
|
||||
struct watch_event *first_watch_event = 0;
|
||||
struct watch_event *last_watch_event = 0;
|
||||
|
||||
/* Delay so that duplicate events pile up */
|
||||
{
|
||||
__profn("Delay");
|
||||
sys_wait(0, 0, 0, NS_FROM_SECONDS(WATCH_DISPATCHER_DELAY_SECONDS));
|
||||
}
|
||||
|
||||
/* Pull watch events from queue */
|
||||
{
|
||||
struct snc_lock lock = snc_lock_e(&G.watch_dispatcher_mutex);
|
||||
for (struct watch_event *src_event = G.first_watch_event; src_event; src_event = src_event->next) {
|
||||
struct watch_event *e = arena_push(scratch.arena, struct watch_event);
|
||||
e->name = string_copy(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;
|
||||
arena_reset(G.watch_events_arena);
|
||||
snc_unlock(&lock);
|
||||
}
|
||||
|
||||
/* Build callbacks array */
|
||||
u64 num_callbacks = 0;
|
||||
watch_callback **callbacks = 0;
|
||||
struct snc_lock callbacks_lock = snc_lock_s(&G.watch_callbacks_mutex);
|
||||
{
|
||||
num_callbacks = G.num_watch_callbacks;
|
||||
callbacks = arena_push_array_no_zero(scratch.arena, watch_callback *, num_callbacks);
|
||||
for (u64 i = 0; i < num_callbacks; ++i) {
|
||||
callbacks[i] = G.watch_callbacks[i];
|
||||
}
|
||||
}
|
||||
snc_unlock(&callbacks_lock);
|
||||
|
||||
/* Run callbacks */
|
||||
{
|
||||
struct dict *dedup_dict = dict_init(scratch.arena, WATCH_DISPATCHER_DEDUP_DICT_BINS);
|
||||
for (struct watch_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 = hash_fnv64(HASH_FNV64_BASIS, e->name);
|
||||
if (dict_get(dedup_dict, hash) == 1) {
|
||||
skip = 1;
|
||||
} else {
|
||||
dict_set(scratch.arena, dedup_dict, hash, 1);
|
||||
}
|
||||
if (!skip) {
|
||||
struct watch_callback_job_sig sig = ZI;
|
||||
sig.name = e->name;
|
||||
sig.callbacks = callbacks;
|
||||
struct snc_counter counter = ZI;
|
||||
sys_run(num_callbacks, watch_callback_job, &sig, SYS_POOL_BACKGROUND, SYS_PRIORITY_LOW, &counter);
|
||||
snc_counter_wait(&counter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
scratch_end(scratch);
|
||||
}
|
||||
|
||||
/* Wait for event */
|
||||
struct snc_lock lock = snc_lock_s(&G.watch_dispatcher_mutex);
|
||||
{
|
||||
shutdown = atomic32_fetch(&G.watch_shutdown);
|
||||
while (!shutdown && !G.first_watch_event) {
|
||||
snc_cv_wait(&G.watch_dispatcher_cv, &lock);
|
||||
shutdown = atomic32_fetch(&G.watch_shutdown);
|
||||
}
|
||||
}
|
||||
snc_unlock(&lock);
|
||||
}
|
||||
}
|
||||
|
||||
#else /* RESOURCE_RELOADING */
|
||||
|
||||
void watch_startup(void)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* RESOURCE_RELOADING */
|
||||
15
src/watch.h
Normal file
15
src/watch.h
Normal file
@ -0,0 +1,15 @@
|
||||
#ifndef WATCH_H
|
||||
#define WATCH_H
|
||||
|
||||
#define WATCH_CALLBACK_FUNC_DEF(func_name, arg_name) void func_name(struct string arg_name)
|
||||
typedef WATCH_CALLBACK_FUNC_DEF(watch_callback, name);
|
||||
|
||||
void watch_startup(void);
|
||||
|
||||
#if RESOURCE_RELOADING
|
||||
void watch_register_callback(watch_callback *callback);
|
||||
#else
|
||||
#define watch_register_callback(callback)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
Loading…
Reference in New Issue
Block a user