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;
|
typedef struct BuildStepSimpleCommandArg BuildStepSimpleCommandArg;
|
||||||
struct BuildStepSimpleCommandArg {
|
struct BuildStepSimpleCommandArg {
|
||||||
String cmd;
|
String cmd;
|
||||||
AtomicI32 *skip_flag;
|
Atomic32 *skip_flag;
|
||||||
AtomicI32 *failure_flag;
|
Atomic32 *failure_flag;
|
||||||
|
D_Tag delete_file_on_failure;
|
||||||
|
D_Tag dxc_depfile_dependent;
|
||||||
|
D_Tag dxc_depfile;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct BuildStepMsvcCompileCommandArg BuildStepMsvcCompileCommandArg;
|
typedef struct BuildStepMsvcCompileCommandArg BuildStepMsvcCompileCommandArg;
|
||||||
struct BuildStepMsvcCompileCommandArg {
|
struct BuildStepMsvcCompileCommandArg {
|
||||||
String cmd;
|
String cmd;
|
||||||
AtomicI32 *skip_flag;
|
Atomic32 *skip_flag;
|
||||||
AtomicI32 *failure_flag;
|
Atomic32 *failure_flag;
|
||||||
|
D_Tag delete_file_on_failure;
|
||||||
D_Tag depfile_dependent;
|
D_Tag depfile_dependent;
|
||||||
D_Tag output_depfile;
|
D_Tag output_depfile;
|
||||||
D_TagList depfile_force_includes;
|
D_TagList depfile_force_includes;
|
||||||
@ -221,9 +225,9 @@ void BuildStepSimpleCommand(void *arg_raw)
|
|||||||
Step *s = arg_raw;
|
Step *s = arg_raw;
|
||||||
BuildStepSimpleCommandArg *arg = s->arg;
|
BuildStepSimpleCommandArg *arg = s->arg;
|
||||||
|
|
||||||
AtomicI32 *skip_flag = arg->skip_flag;
|
Atomic32 *skip_flag = arg->skip_flag;
|
||||||
AtomicI32 *failure_flag = arg->failure_flag;
|
Atomic32 *failure_flag = arg->failure_flag;
|
||||||
if (!skip_flag || !AtomicI32Eval(skip_flag)) {
|
if (!skip_flag || !Atomic32Fetch(skip_flag)) {
|
||||||
SH_CommandResult result = RunCommand(scratch.arena, arg->cmd);
|
SH_CommandResult result = RunCommand(scratch.arena, arg->cmd);
|
||||||
String result_output_cleaned = CleanResultOutput(scratch.arena, result.output);
|
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);
|
MemoryCopy(s->res_output.text, result_output_cleaned.text, result_output_cleaned.len);
|
||||||
}
|
}
|
||||||
s->res_status = result.error ? StepStatus_Failure : StepStatus_Success;
|
s->res_status = result.error ? StepStatus_Failure : StepStatus_Success;
|
||||||
if (result.error && failure_flag) {
|
if (!D_IsNil(arg->dxc_depfile)) {
|
||||||
AtomicI32EvalExchange(failure_flag, 1);
|
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_ConditionVariableBroadcast(&s->res_cv);
|
||||||
OS_MutexUnlock(&res_lock);
|
OS_MutexUnlock(&res_lock);
|
||||||
@ -248,7 +261,7 @@ void BuildStepSimpleCommand(void *arg_raw)
|
|||||||
OS_Lock res_lock = OS_MutexLockE(&s->res_mutex);
|
OS_Lock res_lock = OS_MutexLockE(&s->res_mutex);
|
||||||
s->res_status = StepStatus_Skipped;
|
s->res_status = StepStatus_Skipped;
|
||||||
if (failure_flag) {
|
if (failure_flag) {
|
||||||
AtomicI32EvalExchange(failure_flag, 1);
|
Atomic32FetchSet(failure_flag, 1);
|
||||||
}
|
}
|
||||||
OS_ConditionVariableBroadcast(&s->res_cv);
|
OS_ConditionVariableBroadcast(&s->res_cv);
|
||||||
OS_MutexUnlock(&res_lock);
|
OS_MutexUnlock(&res_lock);
|
||||||
@ -264,9 +277,9 @@ void BuildStepMsvcCompileCommand(void *arg_raw)
|
|||||||
Step *s = arg_raw;
|
Step *s = arg_raw;
|
||||||
BuildStepMsvcCompileCommandArg *arg = s->arg;
|
BuildStepMsvcCompileCommandArg *arg = s->arg;
|
||||||
|
|
||||||
AtomicI32 *skip_flag = arg->skip_flag;
|
Atomic32 *skip_flag = arg->skip_flag;
|
||||||
AtomicI32 *failure_flag = arg->failure_flag;
|
Atomic32 *failure_flag = arg->failure_flag;
|
||||||
if (!skip_flag || !AtomicI32Eval(skip_flag)) {
|
if (!skip_flag || !Atomic32Fetch(skip_flag)) {
|
||||||
SH_CommandResult result = RunCommand(scratch.arena, arg->cmd);
|
SH_CommandResult result = RunCommand(scratch.arena, arg->cmd);
|
||||||
if (!result.error && !D_IsNil(arg->depfile_dependent) && !D_IsNil(arg->output_depfile)) {
|
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);
|
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);
|
MemoryCopy(s->res_output.text, result_output_cleaned.text, result_output_cleaned.len);
|
||||||
}
|
}
|
||||||
s->res_status = result.error ? StepStatus_Failure : StepStatus_Success;
|
s->res_status = result.error ? StepStatus_Failure : StepStatus_Success;
|
||||||
if (result.error && failure_flag) {
|
if (result.error) {
|
||||||
AtomicI32EvalExchange(failure_flag, 1);
|
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_ConditionVariableBroadcast(&s->res_cv);
|
||||||
OS_MutexUnlock(&res_lock);
|
OS_MutexUnlock(&res_lock);
|
||||||
@ -295,7 +313,7 @@ void BuildStepMsvcCompileCommand(void *arg_raw)
|
|||||||
OS_Lock res_lock = OS_MutexLockE(&s->res_mutex);
|
OS_Lock res_lock = OS_MutexLockE(&s->res_mutex);
|
||||||
s->res_status = StepStatus_Skipped;
|
s->res_status = StepStatus_Skipped;
|
||||||
if (failure_flag) {
|
if (failure_flag) {
|
||||||
AtomicI32EvalExchange(failure_flag, 1);
|
Atomic32FetchSet(failure_flag, 1);
|
||||||
}
|
}
|
||||||
OS_ConditionVariableBroadcast(&s->res_cv);
|
OS_ConditionVariableBroadcast(&s->res_cv);
|
||||||
OS_MutexUnlock(&res_lock);
|
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 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_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_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_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)));
|
String out_bin_dir_path = OS_GetAbsPath(&perm, StringF(&perm, Lit("%F/bin/"), FmtStr(arg_outdir)));
|
||||||
|
|
||||||
if (!OS_DirExists(out_obj_dir_path)) {
|
if (!OS_DirExists(out_obj_dir_path)) {
|
||||||
OS_CreateDirAtAbsPath(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)) {
|
if (!OS_DirExists(out_inc_dir_path)) {
|
||||||
OS_CreateDirAtAbsPath(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;
|
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 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 res_dir = D_TagFromPath(&perm, Lit("res"), D_TagKind_Dir);
|
||||||
D_Tag icon_file = D_TagFromPath(&perm, Lit("icon.ico"), D_TagKind_File);
|
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_warnings = { 0 };
|
||||||
StringList link_args = { 0 };
|
StringList link_args = { 0 };
|
||||||
StringList rc_compile_args = { 0 };
|
StringList rc_compile_args = { 0 };
|
||||||
|
StringList dxc_compile_args = { 0 };
|
||||||
{
|
{
|
||||||
if (arg_msvc) {
|
if (arg_msvc) {
|
||||||
/* Msvc */
|
/* Msvc */
|
||||||
@ -449,7 +473,7 @@ void OnBuild(StringList cli_args)
|
|||||||
|
|
||||||
String warnings = Lit("/WX /Wall "
|
String warnings = Lit("/WX /Wall "
|
||||||
"/options:strict "
|
"/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, &compile_warnings, warnings);
|
||||||
StringListAppend(&perm, &link_warnings, Lit("/WX"));
|
StringListAppend(&perm, &link_warnings, Lit("/WX"));
|
||||||
|
|
||||||
@ -495,6 +519,12 @@ void OnBuild(StringList cli_args)
|
|||||||
StringListAppend(&perm, &link_warnings, warnings);
|
StringListAppend(&perm, &link_warnings, warnings);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* DXC */
|
||||||
|
{
|
||||||
|
StringListAppend(&perm, &dxc_compile_args, Lit("dxc %F -Fo %F -E %F -T %F -H"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* RTC */
|
/* RTC */
|
||||||
if (arg_rtc) {
|
if (arg_rtc) {
|
||||||
if (!arg_crtlib) {
|
if (!arg_crtlib) {
|
||||||
@ -535,6 +565,7 @@ void OnBuild(StringList cli_args)
|
|||||||
} else {
|
} else {
|
||||||
StringListAppend(&perm, &compile_and_link_args, Lit("-O0"));
|
StringListAppend(&perm, &compile_and_link_args, Lit("-O0"));
|
||||||
}
|
}
|
||||||
|
StringListAppend(&perm, &dxc_compile_args, Lit("-Od"));
|
||||||
} else {
|
} else {
|
||||||
if (arg_msvc) {
|
if (arg_msvc) {
|
||||||
StringListAppend(&perm, &compile_args, Lit("/O2"));
|
StringListAppend(&perm, &compile_args, Lit("/O2"));
|
||||||
@ -542,6 +573,7 @@ void OnBuild(StringList cli_args)
|
|||||||
} else {
|
} else {
|
||||||
StringListAppend(&perm, &compile_and_link_args, Lit("-O3 -flto"));
|
StringListAppend(&perm, &compile_and_link_args, Lit("-O3 -flto"));
|
||||||
}
|
}
|
||||||
|
StringListAppend(&perm, &dxc_compile_args, Lit("-O3"));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Debug info */
|
/* Debug info */
|
||||||
@ -552,6 +584,7 @@ void OnBuild(StringList cli_args)
|
|||||||
} else {
|
} else {
|
||||||
StringListAppend(&perm, &compile_and_link_args, Lit("-g"));
|
StringListAppend(&perm, &compile_and_link_args, Lit("-g"));
|
||||||
}
|
}
|
||||||
|
StringListAppend(&perm, &dxc_compile_args, Lit("-Zi -Qembed_debug"));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Address sanitizer */
|
/* Address sanitizer */
|
||||||
@ -638,16 +671,106 @@ void OnBuild(StringList cli_args)
|
|||||||
hist = D_HistFromPath(&perm, hist_path);
|
hist = D_HistFromPath(&perm, hist_path);
|
||||||
D_TagList link_files = { 0 };
|
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
|
* Build step: Tar archives
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
AtomicI32 tar_success_flag = { 0 };
|
Atomic32 tar_success_flag = { 0 };
|
||||||
{
|
{
|
||||||
AddSyncPoint();
|
AddSyncPoint();
|
||||||
|
|
||||||
D_TagList tar_input_dirs = { 0 };
|
D_TagList tar_input_dirs = { 0 };
|
||||||
|
D_TagListAppend(&perm, &tar_input_dirs, dxc_dir);
|
||||||
if (should_embed_res_dir) {
|
if (should_embed_res_dir) {
|
||||||
D_TagListAppend(&perm, &tar_input_dirs, 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);
|
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->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->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)));
|
String step_name = StringF(&perm, Lit("%F -> %F"), FmtStr(D_GetName(input_dir)), FmtStr(D_GetName(tar_file)));
|
||||||
AddStep(step_name, &BuildStepSimpleCommand, bs_arg);
|
AddStep(step_name, &BuildStepSimpleCommand, bs_arg);
|
||||||
}
|
}
|
||||||
@ -675,20 +799,23 @@ void OnBuild(StringList cli_args)
|
|||||||
* Build step: Compile RC files
|
* Build step: Compile RC files
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
AtomicI32 rc_success_flag = { 0 };
|
Atomic32 rc_success_flag = { 0 };
|
||||||
if (PlatformWindows) {
|
if (PlatformWindows) {
|
||||||
AddSyncPoint();
|
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 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 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, icon_file);
|
||||||
|
D_AddDependency(&store, rc_input_file, dxc_tar_file);
|
||||||
if (should_embed_in_rc && should_embed_res_dir) {
|
if (should_embed_in_rc && should_embed_res_dir) {
|
||||||
D_AddDependency(&store, rc_input_file, res_tar_file);
|
D_AddDependency(&store, rc_input_file, res_tar_file);
|
||||||
}
|
}
|
||||||
if (IsDirty(rc_input_file)) {
|
if (IsDirty(rc_input_file)) {
|
||||||
D_ClearWrite(rc_input_file, Lit(""));
|
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(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) {
|
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))));
|
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
|
* Build step: Compile pch files
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
AtomicI32 pch_success_flag = { 0 };
|
Atomic32 pch_success_flag = { 0 };
|
||||||
D_TagList depfile_force_includes = { 0 };
|
D_TagList depfile_force_includes = { 0 };
|
||||||
{
|
{
|
||||||
AddSyncPoint();
|
AddSyncPoint();
|
||||||
@ -767,6 +894,7 @@ void OnBuild(StringList cli_args)
|
|||||||
bs_arg->output_depfile = dep_file;
|
bs_arg->output_depfile = dep_file;
|
||||||
bs_arg->skip_flag = &rc_success_flag;
|
bs_arg->skip_flag = &rc_success_flag;
|
||||||
bs_arg->failure_flag = &pch_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)));
|
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);
|
AddStep(step_name, &BuildStepMsvcCompileCommand, bs_arg);
|
||||||
}
|
}
|
||||||
@ -782,6 +910,7 @@ void OnBuild(StringList cli_args)
|
|||||||
bs_arg->output_depfile = dep_file;
|
bs_arg->output_depfile = dep_file;
|
||||||
bs_arg->skip_flag = &rc_success_flag;
|
bs_arg->skip_flag = &rc_success_flag;
|
||||||
bs_arg->failure_flag = &pch_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)));
|
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);
|
AddStep(step_name, &BuildStepMsvcCompileCommand, bs_arg);
|
||||||
}
|
}
|
||||||
@ -818,7 +947,7 @@ void OnBuild(StringList cli_args)
|
|||||||
* Build step: Compile src files
|
* Build step: Compile src files
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
AtomicI32 src_success_flag = { 0 };
|
Atomic32 src_success_flag = { 0 };
|
||||||
{
|
{
|
||||||
D_TagList src_input_files = { 0 };
|
D_TagList src_input_files = { 0 };
|
||||||
{
|
{
|
||||||
@ -840,13 +969,15 @@ void OnBuild(StringList cli_args)
|
|||||||
StringBeginsWith(name, Lit("gp_")) ||
|
StringBeginsWith(name, Lit("gp_")) ||
|
||||||
StringBeginsWith(name, Lit("playback_")) ||
|
StringBeginsWith(name, Lit("playback_")) ||
|
||||||
StringBeginsWith(name, Lit("mp3_")) ||
|
StringBeginsWith(name, Lit("mp3_")) ||
|
||||||
StringBeginsWith(name, Lit("ttf_"))) {
|
StringBeginsWith(name, Lit("ttf_")) ||
|
||||||
|
StringBeginsWith(name, Lit("dxc"))) {
|
||||||
if (PlatformWindows) {
|
if (PlatformWindows) {
|
||||||
ignore = !(StringEqual(name, Lit("sys_win32.c")) ||
|
ignore = !(StringEqual(name, Lit("sys_win32.c")) ||
|
||||||
StringEqual(name, Lit("gp_dx12.c")) ||
|
StringEqual(name, Lit("gp_dx12.c")) ||
|
||||||
StringEqual(name, Lit("playback_wasapi.c")) ||
|
StringEqual(name, Lit("playback_wasapi.c")) ||
|
||||||
StringEqual(name, Lit("mp3_mmf.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 {
|
} else {
|
||||||
ignore = 0;
|
ignore = 0;
|
||||||
@ -899,6 +1030,7 @@ void OnBuild(StringList cli_args)
|
|||||||
bs_arg->depfile_force_includes = depfile_force_includes;
|
bs_arg->depfile_force_includes = depfile_force_includes;
|
||||||
bs_arg->skip_flag = &pch_success_flag;
|
bs_arg->skip_flag = &pch_success_flag;
|
||||||
bs_arg->failure_flag = &src_success_flag;
|
bs_arg->failure_flag = &src_success_flag;
|
||||||
|
bs_arg->delete_file_on_failure = obj_file;
|
||||||
AddStep(step_name, &BuildStepMsvcCompileCommand, bs_arg);
|
AddStep(step_name, &BuildStepMsvcCompileCommand, bs_arg);
|
||||||
} else {
|
} else {
|
||||||
BuildStepSimpleCommandArg *bs_arg = ArenaPush(&perm, BuildStepSimpleCommandArg);
|
BuildStepSimpleCommandArg *bs_arg = ArenaPush(&perm, BuildStepSimpleCommandArg);
|
||||||
|
|||||||
@ -21,6 +21,7 @@
|
|||||||
#include "phys.h"
|
#include "phys.h"
|
||||||
#include "host.h"
|
#include "host.h"
|
||||||
#include "bitbuff.h"
|
#include "bitbuff.h"
|
||||||
|
#include "watch.h"
|
||||||
|
|
||||||
GLOBAL struct {
|
GLOBAL struct {
|
||||||
struct arena *arena;
|
struct arena *arena;
|
||||||
@ -278,6 +279,7 @@ void sys_app_startup(struct string args_str)
|
|||||||
|
|
||||||
/* Global systems */
|
/* Global systems */
|
||||||
resource_startup();
|
resource_startup();
|
||||||
|
watch_startup();
|
||||||
gp_startup();
|
gp_startup();
|
||||||
|
|
||||||
/* Subsystems */
|
/* Subsystems */
|
||||||
|
|||||||
@ -54,8 +54,8 @@ void arena_release(struct arena *arena)
|
|||||||
ASAN_UNPOISON(arena, arena->committed + ARENA_HEADER_SIZE);
|
ASAN_UNPOISON(arena, arena->committed + ARENA_HEADER_SIZE);
|
||||||
__prof;
|
__prof;
|
||||||
__proffree(arena);
|
__proffree(arena);
|
||||||
gstat_add(GSTAT_MEMORY_COMMITTED, -arena->committed - ARENA_HEADER_SIZE);
|
gstat_add(GSTAT_MEMORY_COMMITTED, -(i64)(arena->committed - ARENA_HEADER_SIZE));
|
||||||
gstat_add(GSTAT_MEMORY_RESERVED, -arena->reserved);
|
gstat_add(GSTAT_MEMORY_RESERVED, -(i64)(arena->reserved));
|
||||||
gstat_add(GSTAT_NUM_ARENAS, -1);
|
gstat_add(GSTAT_NUM_ARENAS, -1);
|
||||||
sys_memory_release(arena);
|
sys_memory_release(arena);
|
||||||
}
|
}
|
||||||
|
|||||||
20
src/common.h
20
src/common.h
@ -119,7 +119,7 @@ extern "C" {
|
|||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
/* Compile time assert */
|
/* Compile time assert */
|
||||||
#if LANGUAGE_C && (__STDC_VERSION__ < 202311L)
|
#if COMPILER_MSVC || (LANGUAGE_C && __STDC_VERSION__ < 202311L)
|
||||||
# if COMPILER_MSVC
|
# if COMPILER_MSVC
|
||||||
# define STATIC_ASSERT3(cond, line) struct STATIC_ASSERT_____##line {int foo[(cond) ? 1 : -1];}
|
# define STATIC_ASSERT3(cond, line) struct STATIC_ASSERT_____##line {int foo[(cond) ? 1 : -1];}
|
||||||
# define STATIC_ASSERT2(cond, line) STATIC_ASSERT3(cond, line)
|
# 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
|
#endif
|
||||||
|
|
||||||
/* alignas */
|
/* alignas */
|
||||||
#if (LANGUAGE_C && (__STDC_VERSION__ < 202311L))
|
#if COMPILER_MSVC || (LANGUAGE_C && __STDC_VERSION__ < 202311L)
|
||||||
# if COMPILER_MSVC
|
# if COMPILER_MSVC
|
||||||
# define alignas(n) __declspec(align(n))
|
# define alignas(n) __declspec(align(n))
|
||||||
# else
|
# else
|
||||||
@ -276,10 +276,14 @@ void __asan_unpoison_memory_region(void const volatile *add, size_t);
|
|||||||
/* Field macros */
|
/* Field macros */
|
||||||
#define FIELD_SIZEOF(type, field) sizeof(((type *)0)->field)
|
#define FIELD_SIZEOF(type, field) sizeof(((type *)0)->field)
|
||||||
|
|
||||||
#if COMPILER_MSVC && !defined _CRT_USE_BUILTIN_OFFSETOF
|
#if 0
|
||||||
|
#if !COMPILER_MSVC
|
||||||
|
# if !defined _CRT_USE_BUILTIN_OFFSETOF
|
||||||
# define offsetof(type, field) ((u64)&(((type *)0)->field))
|
# define offsetof(type, field) ((u64)&(((type *)0)->field))
|
||||||
#else
|
# else
|
||||||
# define offsetof(type, field) __builtin_offsetof(type, field)
|
# define offsetof(type, field) __builtin_offsetof(type, field)
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Array */
|
/* 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"
|
#include "prof_tracy.h"
|
||||||
|
|
||||||
#define PROF_THREAD_GROUP_FIBERS -GIBI(1)
|
#define PROF_THREAD_GROUP_FIBERS -(i64)GIBI(1)
|
||||||
#define PROF_THREAD_GROUP_SCHEDULER -MEBI(3)
|
#define PROF_THREAD_GROUP_SCHEDULER -(i64)MEBI(3)
|
||||||
#define PROF_THREAD_GROUP_WINDOW -MEBI(2)
|
#define PROF_THREAD_GROUP_WINDOW -(i64)MEBI(2)
|
||||||
#define PROF_THREAD_GROUP_MAIN -MEBI(1)
|
#define PROF_THREAD_GROUP_MAIN -(i64)MEBI(1)
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
@ -73,7 +73,7 @@
|
|||||||
#define COLLIDER_DEBUG_DETAILED 1
|
#define COLLIDER_DEBUG_DETAILED 1
|
||||||
#define COLLIDER_DEBUG_DETAILED_DRAW_MENKOWSKI 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 */
|
/* If enabled, bitbuffs will insert/verify magic numbers & length for each read & write */
|
||||||
#define BITBUFF_DEBUG 0
|
#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
|
||||||
653
src/gp_dx12.c
653
src/gp_dx12.c
@ -5,7 +5,6 @@
|
|||||||
#include "string.h"
|
#include "string.h"
|
||||||
#include "app.h"
|
#include "app.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "resource.h"
|
|
||||||
#include "atomic.h"
|
#include "atomic.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "rand.h"
|
#include "rand.h"
|
||||||
@ -13,10 +12,15 @@
|
|||||||
#include "gstat.h"
|
#include "gstat.h"
|
||||||
#include "snc.h"
|
#include "snc.h"
|
||||||
#include "ase.h"
|
#include "ase.h"
|
||||||
|
#include "resource.h"
|
||||||
|
#include "tar.h"
|
||||||
|
#include "inc.h"
|
||||||
|
#include "dxc.h"
|
||||||
|
#include "watch.h"
|
||||||
|
|
||||||
/* Include common shader types */
|
/* Include common shader types */
|
||||||
#define SH_CPU 1
|
#define SH_CPU 1
|
||||||
#include "../res/sh/sh_common.h"
|
#include "sh/sh_common.h"
|
||||||
|
|
||||||
#pragma warning(push, 0)
|
#pragma warning(push, 0)
|
||||||
# define UNICODE
|
# define UNICODE
|
||||||
@ -32,7 +36,6 @@
|
|||||||
#pragma comment(lib, "d3d12")
|
#pragma comment(lib, "d3d12")
|
||||||
#pragma comment(lib, "dxgi")
|
#pragma comment(lib, "dxgi")
|
||||||
#pragma comment(lib, "dxguid")
|
#pragma comment(lib, "dxguid")
|
||||||
#pragma comment(lib, "d3dcompiler")
|
|
||||||
|
|
||||||
#if PROFILING_GPU
|
#if PROFILING_GPU
|
||||||
/* For RegOpenKeyEx */
|
/* For RegOpenKeyEx */
|
||||||
@ -89,33 +92,31 @@ struct pipeline_rtv_desc {
|
|||||||
|
|
||||||
struct pipeline_desc {
|
struct pipeline_desc {
|
||||||
struct string name;
|
struct string name;
|
||||||
struct shader_desc cs;
|
|
||||||
struct shader_desc vs;
|
/* If a dxc string is set, then it will be used directly instead of looking up dxc from archive using pipeline name */
|
||||||
struct shader_desc ps;
|
struct string vs_dxc;
|
||||||
|
struct string ps_dxc;
|
||||||
|
struct string cs_dxc;
|
||||||
|
|
||||||
D3D12_INPUT_ELEMENT_DESC ia[8];
|
D3D12_INPUT_ELEMENT_DESC ia[8];
|
||||||
struct pipeline_rtv_desc rtvs[8];
|
struct pipeline_rtv_desc rtvs[8];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct pipeline {
|
struct pipeline {
|
||||||
b32 success;
|
|
||||||
|
|
||||||
struct arena *arena;
|
|
||||||
struct string name;
|
struct string name;
|
||||||
u64 hash;
|
u64 hash;
|
||||||
|
b32 success;
|
||||||
struct pipeline_error *first_error;
|
struct string error;
|
||||||
struct pipeline_error *last_error;
|
|
||||||
i64 compilation_time_ns;
|
i64 compilation_time_ns;
|
||||||
|
|
||||||
/* Dict with shader source & included file names as keys */
|
|
||||||
struct dict *dependencies;
|
|
||||||
|
|
||||||
/* Lock global pipelines mutex when accessing */
|
/* Lock global pipelines mutex when accessing */
|
||||||
i64 refcount;
|
i64 refcount;
|
||||||
|
|
||||||
ID3D12PipelineState *pso;
|
ID3D12PipelineState *pso;
|
||||||
ID3D12RootSignature *rootsig;
|
ID3D12RootSignature *rootsig;
|
||||||
struct pipeline_desc desc;
|
struct pipeline_desc desc;
|
||||||
|
|
||||||
|
struct pipeline *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct pipeline_error {
|
struct pipeline_error {
|
||||||
@ -323,7 +324,7 @@ struct dx12_upload_job_sig { struct dx12_resource *resource; void *data; };
|
|||||||
INTERNAL SYS_JOB_DEF(dx12_upload_job, job);
|
INTERNAL SYS_JOB_DEF(dx12_upload_job, job);
|
||||||
|
|
||||||
#if RESOURCE_RELOADING
|
#if RESOURCE_RELOADING
|
||||||
INTERNAL RESOURCE_WATCH_CALLBACK_FUNC_DEF(pipeline_resource_watch_callback, name);
|
INTERNAL WATCH_CALLBACK_FUNC_DEF(pipeline_watch_callback, name);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
@ -354,9 +355,13 @@ GLOBAL struct {
|
|||||||
struct arena *swapchains_arena;
|
struct arena *swapchains_arena;
|
||||||
struct swapchain *first_free_swapchain;
|
struct swapchain *first_free_swapchain;
|
||||||
|
|
||||||
|
/* Shader bytecode archive */
|
||||||
|
struct tar_archive dxc_archive;
|
||||||
|
|
||||||
/* Pipeline cache */
|
/* Pipeline cache */
|
||||||
struct snc_mutex pipelines_mutex;
|
struct snc_mutex pipelines_mutex;
|
||||||
struct arena *pipelines_arena;
|
struct arena *pipelines_arena;
|
||||||
|
struct pipeline *first_free_pipeline;
|
||||||
struct dict *pipeline_descs;
|
struct dict *pipeline_descs;
|
||||||
struct dict *top_pipelines; /* Latest pipelines */
|
struct dict *top_pipelines; /* Latest pipelines */
|
||||||
struct dict *top_successful_pipelines; /* Latest pipelines that successfully compiled */
|
struct dict *top_successful_pipelines; /* Latest pipelines that successfully compiled */
|
||||||
@ -430,6 +435,13 @@ void gp_startup(void)
|
|||||||
/* Initialize fenced releases queue */
|
/* Initialize fenced releases queue */
|
||||||
G.fenced_releases_arena = arena_alloc(GIBI(64));
|
G.fenced_releases_arena = arena_alloc(GIBI(64));
|
||||||
|
|
||||||
|
/* Initialize embedded shader archive */
|
||||||
|
struct string embedded_data = inc_dxc_tar();
|
||||||
|
if (embedded_data.len <= 0) {
|
||||||
|
sys_panic(LIT("No embedded shaders found"));
|
||||||
|
}
|
||||||
|
G.dxc_archive = tar_parse(G.pipelines_arena, embedded_data, LIT(""));
|
||||||
|
|
||||||
/* Initialize dx12 */
|
/* Initialize dx12 */
|
||||||
/* TODO: Parallelize phases */
|
/* TODO: Parallelize phases */
|
||||||
dx12_init_device();
|
dx12_init_device();
|
||||||
@ -439,7 +451,7 @@ void gp_startup(void)
|
|||||||
|
|
||||||
/* Register callbacks */
|
/* Register callbacks */
|
||||||
#if RESOURCE_RELOADING
|
#if RESOURCE_RELOADING
|
||||||
resource_register_watch_callback(pipeline_resource_watch_callback);
|
watch_register_callback(pipeline_watch_callback);
|
||||||
#endif
|
#endif
|
||||||
sys_on_exit(gp_shutdown);
|
sys_on_exit(gp_shutdown);
|
||||||
|
|
||||||
@ -662,10 +674,10 @@ INTERNAL void dx12_init_objects(void)
|
|||||||
{
|
{
|
||||||
__profn("Allocate command queues");
|
__profn("Allocate command queues");
|
||||||
struct command_queue_desc params[] = {
|
struct command_queue_desc params[] = {
|
||||||
{ .type = D3D12_COMMAND_LIST_TYPE_DIRECT, .priority = D3D12_COMMAND_QUEUE_PRIORITY_NORMAL, .dbg_name = LIT("Direct queue") },
|
{.type = D3D12_COMMAND_LIST_TYPE_DIRECT, .priority = D3D12_COMMAND_QUEUE_PRIORITY_NORMAL, .dbg_name = LIT("Direct queue") },
|
||||||
{ .type = D3D12_COMMAND_LIST_TYPE_COMPUTE, .priority = D3D12_COMMAND_QUEUE_PRIORITY_NORMAL, .dbg_name = LIT("Compute queue") },
|
{.type = D3D12_COMMAND_LIST_TYPE_COMPUTE, .priority = D3D12_COMMAND_QUEUE_PRIORITY_NORMAL, .dbg_name = LIT("Compute queue") },
|
||||||
{ .type = D3D12_COMMAND_LIST_TYPE_COPY, .priority = D3D12_COMMAND_QUEUE_PRIORITY_HIGH, .dbg_name = LIT("Copy queue") },
|
{.type = D3D12_COMMAND_LIST_TYPE_COPY, .priority = D3D12_COMMAND_QUEUE_PRIORITY_HIGH, .dbg_name = LIT("Copy queue") },
|
||||||
{ .type = D3D12_COMMAND_LIST_TYPE_COPY, .priority = D3D12_COMMAND_QUEUE_PRIORITY_NORMAL, .dbg_name = LIT("Background copy queue") }
|
{.type = D3D12_COMMAND_LIST_TYPE_COPY, .priority = D3D12_COMMAND_QUEUE_PRIORITY_NORMAL, .dbg_name = LIT("Background copy queue") }
|
||||||
};
|
};
|
||||||
struct command_queue_alloc_job_sig sig = ZI;
|
struct command_queue_alloc_job_sig sig = ZI;
|
||||||
sig.descs_in = params;
|
sig.descs_in = params;
|
||||||
@ -707,10 +719,6 @@ INTERNAL void dx12_init_pipelines(void)
|
|||||||
{
|
{
|
||||||
struct pipeline_desc *desc = arena_push(G.pipelines_arena, struct pipeline_desc);
|
struct pipeline_desc *desc = arena_push(G.pipelines_arena, struct pipeline_desc);
|
||||||
desc->name = LIT("material");
|
desc->name = LIT("material");
|
||||||
desc->vs.file = LIT("sh/material.hlsl");
|
|
||||||
desc->ps.file = LIT("sh/material.hlsl");
|
|
||||||
desc->vs.func = LIT("vs");
|
|
||||||
desc->ps.func = LIT("ps");
|
|
||||||
desc->rtvs[0].format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
desc->rtvs[0].format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||||
desc->rtvs[0].blending = 1;
|
desc->rtvs[0].blending = 1;
|
||||||
desc->rtvs[1].format = DXGI_FORMAT_R16G16B16A16_FLOAT;
|
desc->rtvs[1].format = DXGI_FORMAT_R16G16B16A16_FLOAT;
|
||||||
@ -721,26 +729,18 @@ INTERNAL void dx12_init_pipelines(void)
|
|||||||
{
|
{
|
||||||
struct pipeline_desc *desc = arena_push(G.pipelines_arena, struct pipeline_desc);
|
struct pipeline_desc *desc = arena_push(G.pipelines_arena, struct pipeline_desc);
|
||||||
desc->name = LIT("flood");
|
desc->name = LIT("flood");
|
||||||
desc->cs.file = LIT("sh/flood.hlsl");
|
|
||||||
desc->cs.func = LIT("cs");
|
|
||||||
dict_set(G.pipelines_arena, G.pipeline_descs, hash_fnv64(HASH_FNV64_BASIS, desc->name), (u64)desc);
|
dict_set(G.pipelines_arena, G.pipeline_descs, hash_fnv64(HASH_FNV64_BASIS, desc->name), (u64)desc);
|
||||||
}
|
}
|
||||||
/* Shade pipeline */
|
/* Shade pipeline */
|
||||||
{
|
{
|
||||||
struct pipeline_desc *desc = arena_push(G.pipelines_arena, struct pipeline_desc);
|
struct pipeline_desc *desc = arena_push(G.pipelines_arena, struct pipeline_desc);
|
||||||
desc->name = LIT("shade");
|
desc->name = LIT("shade");
|
||||||
desc->cs.file = LIT("sh/shade.hlsl");
|
|
||||||
desc->cs.func = LIT("cs");
|
|
||||||
dict_set(G.pipelines_arena, G.pipeline_descs, hash_fnv64(HASH_FNV64_BASIS, desc->name), (u64)desc);
|
dict_set(G.pipelines_arena, G.pipeline_descs, hash_fnv64(HASH_FNV64_BASIS, desc->name), (u64)desc);
|
||||||
}
|
}
|
||||||
/* Shape pipeline */
|
/* Shape pipeline */
|
||||||
{
|
{
|
||||||
struct pipeline_desc *desc = arena_push(G.pipelines_arena, struct pipeline_desc);
|
struct pipeline_desc *desc = arena_push(G.pipelines_arena, struct pipeline_desc);
|
||||||
desc->name = LIT("shape");
|
desc->name = LIT("shape");
|
||||||
desc->vs.file = LIT("sh/shape.hlsl");
|
|
||||||
desc->ps.file = LIT("sh/shape.hlsl");
|
|
||||||
desc->vs.func = LIT("vs");
|
|
||||||
desc->ps.func = LIT("ps");
|
|
||||||
desc->ia[0] = (D3D12_INPUT_ELEMENT_DESC) { "pos", 0, DXGI_FORMAT_R32G32_FLOAT, 0, D3D12_APPEND_ALIGNED_ELEMENT, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 };
|
desc->ia[0] = (D3D12_INPUT_ELEMENT_DESC) { "pos", 0, DXGI_FORMAT_R32G32_FLOAT, 0, D3D12_APPEND_ALIGNED_ELEMENT, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 };
|
||||||
desc->ia[1] = (D3D12_INPUT_ELEMENT_DESC) { "color_srgb", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, D3D12_APPEND_ALIGNED_ELEMENT, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 };
|
desc->ia[1] = (D3D12_INPUT_ELEMENT_DESC) { "color_srgb", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, D3D12_APPEND_ALIGNED_ELEMENT, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 };
|
||||||
desc->rtvs[0].format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
desc->rtvs[0].format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||||
@ -751,10 +751,6 @@ INTERNAL void dx12_init_pipelines(void)
|
|||||||
{
|
{
|
||||||
struct pipeline_desc *desc = arena_push(G.pipelines_arena, struct pipeline_desc);
|
struct pipeline_desc *desc = arena_push(G.pipelines_arena, struct pipeline_desc);
|
||||||
desc->name = LIT("ui");
|
desc->name = LIT("ui");
|
||||||
desc->vs.file = LIT("sh/ui.hlsl");
|
|
||||||
desc->ps.file = LIT("sh/ui.hlsl");
|
|
||||||
desc->vs.func = LIT("vs");
|
|
||||||
desc->ps.func = LIT("ps");
|
|
||||||
desc->rtvs[0].format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
desc->rtvs[0].format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||||
desc->rtvs[0].blending = 1;
|
desc->rtvs[0].blending = 1;
|
||||||
dict_set(G.pipelines_arena, G.pipeline_descs, hash_fnv64(HASH_FNV64_BASIS, desc->name), (u64)desc);
|
dict_set(G.pipelines_arena, G.pipeline_descs, hash_fnv64(HASH_FNV64_BASIS, desc->name), (u64)desc);
|
||||||
@ -763,10 +759,6 @@ INTERNAL void dx12_init_pipelines(void)
|
|||||||
{
|
{
|
||||||
struct pipeline_desc *desc = arena_push(G.pipelines_arena, struct pipeline_desc);
|
struct pipeline_desc *desc = arena_push(G.pipelines_arena, struct pipeline_desc);
|
||||||
desc->name = LIT("blit");
|
desc->name = LIT("blit");
|
||||||
desc->vs.file = LIT("sh/blit.hlsl");
|
|
||||||
desc->ps.file = LIT("sh/blit.hlsl");
|
|
||||||
desc->vs.func = LIT("vs");
|
|
||||||
desc->ps.func = LIT("ps");
|
|
||||||
desc->rtvs[0].format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
desc->rtvs[0].format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||||
desc->rtvs[0].blending = 1;
|
desc->rtvs[0].blending = 1;
|
||||||
dict_set(G.pipelines_arena, G.pipeline_descs, hash_fnv64(HASH_FNV64_BASIS, desc->name), (u64)desc);
|
dict_set(G.pipelines_arena, G.pipeline_descs, hash_fnv64(HASH_FNV64_BASIS, desc->name), (u64)desc);
|
||||||
@ -795,12 +787,12 @@ INTERNAL void dx12_init_pipelines(void)
|
|||||||
struct pipeline *pipeline = pipelines[i];
|
struct pipeline *pipeline = pipelines[i];
|
||||||
if (pipeline->success) {
|
if (pipeline->success) {
|
||||||
logf_success("Successfully compiled pipeline \"%F\" in %F seconds", FMT_STR(pipeline->name), FMT_FLOAT(SECONDS_FROM_NS(pipeline->compilation_time_ns)));
|
logf_success("Successfully compiled pipeline \"%F\" in %F seconds", FMT_STR(pipeline->name), FMT_FLOAT(SECONDS_FROM_NS(pipeline->compilation_time_ns)));
|
||||||
if (pipeline->first_error) {
|
if (pipeline->error.len) {
|
||||||
struct string msg = string_format(scratch.arena, LIT("Warning while compiling pipeline \"%F\":\n%F"), FMT_STR(pipeline->name), FMT_STR(pipeline->first_error->msg));
|
struct string msg = string_format(scratch.arena, LIT("Warning while compiling pipeline \"%F\":\n%F"), FMT_STR(pipeline->name), FMT_STR(pipeline->error));
|
||||||
log_warning(msg);
|
log_warning(msg);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
struct string error = pipeline->first_error ? pipeline->first_error->msg : LIT("Unknown error");
|
struct string error = pipeline->error.len > 0 ? pipeline->error : LIT("Unknown error");
|
||||||
struct string msg = string_format(scratch.arena, LIT("Error initializing pipeline \"%F\":\n\n%F"), FMT_STR(pipeline->name), FMT_STR(error));
|
struct string msg = string_format(scratch.arena, LIT("Error initializing pipeline \"%F\":\n\n%F"), FMT_STR(pipeline->name), FMT_STR(error));
|
||||||
log_error(msg);
|
log_error(msg);
|
||||||
sys_message_box(SYS_MESSAGE_BOX_KIND_WARNING, msg);
|
sys_message_box(SYS_MESSAGE_BOX_KIND_WARNING, msg);
|
||||||
@ -880,230 +872,60 @@ INTERNAL void dx12_init_noise(void)
|
|||||||
* Shader compilation
|
* Shader compilation
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
struct dx12_include_handler {
|
struct shader_compile_desc {
|
||||||
ID3DInclude d3d_handler;
|
struct string src;
|
||||||
ID3DIncludeVtbl vtbl;
|
struct string friendly_name;
|
||||||
struct pipeline *pipeline;
|
struct string entry;
|
||||||
struct snc_mutex pipeline_mutex;
|
struct string target;
|
||||||
u64 num_open_resources;
|
|
||||||
struct resource open_resources[1024];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
INTERNAL HRESULT dx12_include_open(ID3DInclude *d3d_handler, D3D_INCLUDE_TYPE include_type, LPCSTR name_cstr, LPCVOID parent_data, LPCVOID *data_out, UINT *data_len_out)
|
struct shader_compile_result {
|
||||||
{
|
i64 elapsed_ns;
|
||||||
__prof;
|
struct string dxc;
|
||||||
(UNUSED)include_type;
|
struct string errors;
|
||||||
(UNUSED)parent_data;
|
|
||||||
HRESULT result = E_FAIL;
|
|
||||||
struct dx12_include_handler *handler = (struct dx12_include_handler *)d3d_handler;
|
|
||||||
struct string name = string_from_cstr_no_limit((char *)name_cstr);
|
|
||||||
u64 hash = hash_fnv64(HASH_FNV64_BASIS, name);
|
|
||||||
|
|
||||||
if (handler->num_open_resources >= countof(handler->open_resources)) {
|
|
||||||
sys_panic(LIT("Dx12 include handler resource oversig"));
|
|
||||||
}
|
|
||||||
|
|
||||||
struct snc_lock lock = snc_lock_e(&handler->pipeline_mutex);
|
|
||||||
{
|
|
||||||
struct pipeline *pipeline = handler->pipeline;
|
|
||||||
dict_set(pipeline->arena, pipeline->dependencies, hash, 1);
|
|
||||||
}
|
|
||||||
snc_unlock(&lock);
|
|
||||||
|
|
||||||
struct resource *res = &handler->open_resources[handler->num_open_resources++];
|
|
||||||
*res = resource_open(name);
|
|
||||||
if (resource_exists(res)) {
|
|
||||||
struct string data = resource_get_data(res);
|
|
||||||
*data_out = data.text;
|
|
||||||
*data_len_out = data.len;
|
|
||||||
result = S_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
INTERNAL HRESULT dx12_include_close(ID3DInclude *d3d_handler, LPCVOID data)
|
|
||||||
{
|
|
||||||
__prof;
|
|
||||||
(UNUSED)data;
|
|
||||||
struct dx12_include_handler *handler = (struct dx12_include_handler *)d3d_handler;
|
|
||||||
for (u64 i = 0; i < handler->num_open_resources; ++i) {
|
|
||||||
struct resource *res = &handler->open_resources[i];
|
|
||||||
resource_close(res);
|
|
||||||
}
|
|
||||||
handler->num_open_resources = 0;
|
|
||||||
return S_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
INTERNAL struct dx12_include_handler *dx12_include_handler_alloc(struct arena *arena, struct pipeline *pipeline)
|
|
||||||
{
|
|
||||||
__prof;
|
|
||||||
struct dx12_include_handler *handler = arena_push(arena, struct dx12_include_handler);
|
|
||||||
handler->d3d_handler.lpVtbl = &handler->vtbl;
|
|
||||||
handler->vtbl.Open = dx12_include_open;
|
|
||||||
handler->vtbl.Close = dx12_include_close;
|
|
||||||
handler->pipeline = pipeline;
|
|
||||||
return handler;
|
|
||||||
}
|
|
||||||
|
|
||||||
INTERNAL void dx12_include_handler_release(struct dx12_include_handler *handler)
|
|
||||||
{
|
|
||||||
__prof;
|
|
||||||
for (u64 i = 0; i < handler->num_open_resources; ++i) {
|
|
||||||
ASSERT(0); /* Resource should have been closed by handler by now */
|
|
||||||
struct resource *res = &handler->open_resources[i];
|
|
||||||
resource_close(res);
|
|
||||||
}
|
|
||||||
handler->num_open_resources = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
enum shader_compile_job_kind {
|
|
||||||
SHADER_COMPILE_TASK_KIND_VS,
|
|
||||||
SHADER_COMPILE_TASK_KIND_PS,
|
|
||||||
SHADER_COMPILE_TASK_KIND_CS
|
|
||||||
};
|
|
||||||
|
|
||||||
struct shader_compile_job_param {
|
|
||||||
/* In */
|
|
||||||
enum shader_compile_job_kind kind;
|
|
||||||
struct pipeline *pipeline;
|
|
||||||
struct shader_desc shader_desc;
|
|
||||||
struct resource *shader_res;
|
|
||||||
|
|
||||||
/* Out */
|
|
||||||
b32 success;
|
b32 success;
|
||||||
ID3DBlob *blob;
|
|
||||||
ID3DBlob *error_blob;
|
|
||||||
i64 elapsed;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct shader_compile_job_sig {
|
struct shader_compile_job_sig {
|
||||||
struct shader_compile_job_param **params;
|
struct arena *arena;
|
||||||
|
struct shader_compile_desc *descs;
|
||||||
|
struct shader_compile_result *results;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* TODO: Compile shaders offline w/ dxc for performance & language features */
|
|
||||||
INTERNAL SYS_JOB_DEF(shader_compile_job, job)
|
INTERNAL SYS_JOB_DEF(shader_compile_job, job)
|
||||||
{
|
{
|
||||||
__prof;
|
__prof;
|
||||||
struct shader_compile_job_sig *sig = job.sig;
|
struct shader_compile_job_sig *sig = job.sig;
|
||||||
struct shader_compile_job_param *param = sig->params[job.id];
|
struct arena *arena = sig->arena;
|
||||||
enum shader_compile_job_kind kind = param->kind;
|
struct shader_compile_desc *desc = &sig->descs[job.id];
|
||||||
struct pipeline *pipeline = param->pipeline;
|
struct shader_compile_result *result = &sig->results[job.id];
|
||||||
struct shader_desc shader_desc = param->shader_desc;
|
|
||||||
struct resource *shader_res = param->shader_res;
|
|
||||||
|
|
||||||
struct arena_temp scratch = scratch_begin_no_conflict();
|
struct arena_temp scratch = scratch_begin(arena);
|
||||||
{
|
{
|
||||||
i64 start_ns = sys_time_ns();
|
i64 start_ns = sys_time_ns();
|
||||||
b32 success = 0;
|
struct dxc_compile_result dxc_result = ZI;
|
||||||
ID3DBlob *blob = 0;
|
|
||||||
ID3DBlob *error_blob = 0;
|
|
||||||
|
|
||||||
if (resource_exists(shader_res)) {
|
|
||||||
struct dx12_include_handler *include_handler = dx12_include_handler_alloc(scratch.arena, pipeline);
|
|
||||||
char *func_cstr = cstr_from_string(scratch.arena, shader_desc.func);
|
|
||||||
|
|
||||||
u32 d3d_compile_flags = D3DCOMPILE_ENABLE_UNBOUNDED_DESCRIPTOR_TABLES;
|
|
||||||
#if DX12_SHADER_DEBUG
|
|
||||||
d3d_compile_flags |= D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION | D3DCOMPILE_ENABLE_STRICTNESS;
|
|
||||||
#else
|
|
||||||
d3d_compile_flags |= D3DCOMPILE_OPTIMIZATION_LEVEL3;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Compile shader */
|
|
||||||
{
|
{
|
||||||
__profn("Compile shader");
|
__profn("Compile shader");
|
||||||
struct string shader_src = resource_get_data(shader_res);
|
logf_info("Compiling shader \"%F:%F\"", FMT_STR(desc->friendly_name), FMT_STR(desc->entry));
|
||||||
logf_info("Compiling shader \"%F:%F\"", FMT_STR(shader_desc.file), FMT_STR(shader_desc.func));
|
struct string args[] = {
|
||||||
/* Compile shader */
|
desc->friendly_name,
|
||||||
struct string friendly_name = string_cat(scratch.arena, LIT("res/"), shader_desc.file);
|
LIT("-E"), desc->entry,
|
||||||
char *friendly_name_cstr = cstr_from_string(scratch.arena, friendly_name);
|
LIT("-T"), desc->target,
|
||||||
char *target = 0;
|
LIT("-D SH_CPU=0"),
|
||||||
switch (kind) {
|
LIT("-Zi"),
|
||||||
case SHADER_COMPILE_TASK_KIND_VS:
|
LIT("-Qembed_debug")
|
||||||
{
|
|
||||||
target = "vs_5_1";
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case SHADER_COMPILE_TASK_KIND_PS:
|
|
||||||
{
|
|
||||||
target = "ps_5_1";
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case SHADER_COMPILE_TASK_KIND_CS:
|
|
||||||
{
|
|
||||||
target = "cs_5_1";
|
|
||||||
} break;
|
|
||||||
}
|
|
||||||
D3D_SHADER_MACRO defines[] = {
|
|
||||||
{ "SH_CPU", "0" },
|
|
||||||
{ 0, 0 }
|
|
||||||
};
|
};
|
||||||
HRESULT hr = D3DCompile(shader_src.text, shader_src.len, friendly_name_cstr, defines, (ID3DInclude *)include_handler, func_cstr, target, d3d_compile_flags, 0, &blob, &error_blob);
|
dxc_result = dxc_compile(arena, desc->src, countof(args), args);
|
||||||
success = SUCCEEDED(hr);
|
|
||||||
}
|
}
|
||||||
|
result->success = dxc_result.success;
|
||||||
|
result->dxc = dxc_result.dxc;
|
||||||
|
result->errors = dxc_result.errors;
|
||||||
|
result->elapsed_ns = sys_time_ns() - start_ns;
|
||||||
|
|
||||||
dx12_include_handler_release(include_handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
if (success) {
|
|
||||||
logf_success("Finished compiling shader \"%F\" in %F seconds", FMT_STR(src_name), FMT_FLOAT(SECONDS_FROM_NS(sys_time_ns() - start_ns)));
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
param->success = success;
|
|
||||||
param->blob = blob;
|
|
||||||
param->error_blob = error_blob;
|
|
||||||
param->elapsed = sys_time_ns() - start_ns;
|
|
||||||
}
|
}
|
||||||
scratch_end(scratch);
|
scratch_end(scratch);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ========================== *
|
|
||||||
* Shader error parser
|
|
||||||
* ========================== */
|
|
||||||
|
|
||||||
INTERNAL void parse_pipeline_errors(struct pipeline *pipeline, ID3D10Blob *error_blob)
|
|
||||||
{
|
|
||||||
struct string ignored[] = {
|
|
||||||
LIT("warning X3557") /* Disabled forced loop unrolling warning */
|
|
||||||
};
|
|
||||||
|
|
||||||
if (error_blob) {
|
|
||||||
struct arena_temp scratch = scratch_begin_no_conflict();
|
|
||||||
{
|
|
||||||
u64 error_blob_cstr_len = ID3D10Blob_GetBufferSize(error_blob);
|
|
||||||
char *error_blob_cstr = (char *)ID3D10Blob_GetBufferPointer(error_blob);
|
|
||||||
struct string error_str = string_copy(scratch.arena, string_from_cstr(error_blob_cstr, error_blob_cstr_len));
|
|
||||||
if (string_ends_with(error_str, LIT("\n"))) {
|
|
||||||
/* Remove trailing newline */
|
|
||||||
error_str.len -= 1;
|
|
||||||
}
|
|
||||||
if (error_str.len > 0) {
|
|
||||||
b32 is_ignored = 0;
|
|
||||||
for (u32 i = 0; i < countof(ignored); ++i) {
|
|
||||||
if (string_contains(error_str, ignored[i])) {
|
|
||||||
is_ignored = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!is_ignored) {
|
|
||||||
struct pipeline_error *error = arena_push(pipeline->arena, struct pipeline_error);
|
|
||||||
error->msg = string_copy(pipeline->arena, error_str);
|
|
||||||
if (pipeline->last_error) {
|
|
||||||
pipeline->last_error->next = error;
|
|
||||||
} else {
|
|
||||||
pipeline->first_error = error;
|
|
||||||
}
|
|
||||||
pipeline->last_error = error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
scratch_end(scratch);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
* Pipeline
|
* Pipeline
|
||||||
* ========================== */
|
* ========================== */
|
||||||
@ -1117,15 +939,20 @@ INTERNAL SYS_JOB_DEF(pipeline_alloc_job, job)
|
|||||||
|
|
||||||
struct pipeline *pipeline = 0;
|
struct pipeline *pipeline = 0;
|
||||||
{
|
{
|
||||||
struct arena *pipeline_arena = arena_alloc(MEBI(64));
|
struct snc_lock lock = snc_lock_e(&G.pipelines_mutex);
|
||||||
pipeline = arena_push(pipeline_arena, struct pipeline);
|
if (G.first_free_pipeline) {
|
||||||
pipeline->arena = pipeline_arena;
|
pipeline = G.first_free_pipeline;
|
||||||
pipelines_out[job.id] = pipeline;
|
G.first_free_pipeline = pipeline->next;
|
||||||
|
} else {
|
||||||
|
pipeline = arena_push_no_zero(G.pipelines_arena, struct pipeline);
|
||||||
}
|
}
|
||||||
|
snc_unlock(&lock);
|
||||||
|
}
|
||||||
|
MEMZERO_STRUCT(pipeline);
|
||||||
|
pipelines_out[job.id] = pipeline;
|
||||||
pipeline->desc = *desc;
|
pipeline->desc = *desc;
|
||||||
pipeline->name = string_copy(pipeline->arena, desc->name);
|
pipeline->name = desc->name;
|
||||||
pipeline->hash = hash_fnv64(HASH_FNV64_BASIS, pipeline->name);
|
pipeline->hash = hash_fnv64(HASH_FNV64_BASIS, pipeline->name);
|
||||||
pipeline->dependencies = dict_init(pipeline->arena, 64);
|
|
||||||
|
|
||||||
struct arena_temp scratch = scratch_begin_no_conflict();
|
struct arena_temp scratch = scratch_begin_no_conflict();
|
||||||
{
|
{
|
||||||
@ -1137,110 +964,74 @@ INTERNAL SYS_JOB_DEF(pipeline_alloc_job, job)
|
|||||||
|
|
||||||
struct string error_str = ZI;
|
struct string error_str = ZI;
|
||||||
|
|
||||||
b32 has_cs = desc->cs.file.len > 0;
|
struct string vs_dxc = desc->vs_dxc.len > 0 ? desc->vs_dxc : tar_get(&G.dxc_archive, string_cat(scratch.arena, pipeline_name, LIT(".dxc_vs")))->data;
|
||||||
b32 ps_res_is_shared = string_eq(desc->vs.file, desc->ps.file);
|
struct string ps_dxc = desc->ps_dxc.len > 0 ? desc->ps_dxc : tar_get(&G.dxc_archive, string_cat(scratch.arena, pipeline_name, LIT(".dxc_ps")))->data;
|
||||||
|
struct string cs_dxc = desc->cs_dxc.len > 0 ? desc->cs_dxc : tar_get(&G.dxc_archive, string_cat(scratch.arena, pipeline_name, LIT(".dxc_cs")))->data;
|
||||||
struct resource cs_res = ZI;
|
if (success && vs_dxc.len > 0 && ps_dxc.len <= 0) {
|
||||||
struct resource vs_res = ZI;
|
error_str = LIT("Pipeline has vertex shader without pixel shader");
|
||||||
struct resource ps_res = ZI;
|
|
||||||
if (has_cs) {
|
|
||||||
cs_res = resource_open(desc->cs.file);
|
|
||||||
if (desc->vs.file.len > 0 || desc->ps.file.len > 0) {
|
|
||||||
error_str = LIT("Pipeline desc contains both compute and vs/ps shader");
|
|
||||||
success = 0;
|
success = 0;
|
||||||
}
|
}
|
||||||
|
if (success && vs_dxc.len <= 0 && ps_dxc.len > 0) {
|
||||||
|
error_str = LIT("Pipeline has pixel shader without vertex shader");
|
||||||
|
success = 0;
|
||||||
|
}
|
||||||
|
if (success && cs_dxc.len > 0 && (vs_dxc.len > 0 || ps_dxc.len > 0)) {
|
||||||
|
error_str = LIT("Pipeline has a compute shader with a vertex/pixel shader");
|
||||||
|
success = 0;
|
||||||
|
}
|
||||||
|
if (success && cs_dxc.len <= 0 && vs_dxc.len <= 0 && ps_dxc.len <= 0) {
|
||||||
|
error_str = LIT("Pipeline has no shaders");
|
||||||
|
success = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ID3D10Blob *vs_blob = 0;
|
||||||
|
ID3D10Blob *ps_blob = 0;
|
||||||
|
ID3D10Blob *cs_blob = 0;
|
||||||
|
if (success && vs_dxc.len > 0) {
|
||||||
|
hr = D3DCreateBlob(vs_dxc.len, &vs_blob);
|
||||||
|
if (SUCCEEDED(hr)) {
|
||||||
|
MEMCPY(ID3D10Blob_GetBufferPointer(vs_blob), vs_dxc.text, vs_dxc.len);
|
||||||
} else {
|
} else {
|
||||||
vs_res = resource_open(desc->vs.file);
|
error_str = LIT("Failed to create vertex shader blob");
|
||||||
ps_res = vs_res;
|
|
||||||
if (!ps_res_is_shared) {
|
|
||||||
ps_res = resource_open(desc->ps.file);
|
|
||||||
}
|
|
||||||
if (desc->vs.file.len <= 0 || desc->ps.file.len <= 0) {
|
|
||||||
error_str = LIT("Pipeline desc is missing shaders");
|
|
||||||
success = 0;
|
success = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (success && ps_dxc.len > 0) {
|
||||||
if (success) {
|
hr = D3DCreateBlob(ps_dxc.len, &ps_blob);
|
||||||
if (has_cs) {
|
if (SUCCEEDED(hr)) {
|
||||||
dict_set(pipeline->arena, pipeline->dependencies, hash_fnv64(HASH_FNV64_BASIS, desc->cs.file), 1);
|
MEMCPY(ID3D10Blob_GetBufferPointer(ps_blob), ps_dxc.text, ps_dxc.len);
|
||||||
} else {
|
} else {
|
||||||
dict_set(pipeline->arena, pipeline->dependencies, hash_fnv64(HASH_FNV64_BASIS, desc->vs.file), 1);
|
error_str = LIT("Failed to create pixel shader blob");
|
||||||
dict_set(pipeline->arena, pipeline->dependencies, hash_fnv64(HASH_FNV64_BASIS, desc->ps.file), 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (success) {
|
|
||||||
if (has_cs) {
|
|
||||||
if (!resource_exists(&cs_res)) {
|
|
||||||
error_str = string_format(scratch.arena, LIT("Compute shader source \"%F\" not found"), FMT_STR(desc->vs.file));
|
|
||||||
success = 0;
|
success = 0;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if (success && cs_dxc.len > 0) {
|
||||||
|
hr = D3DCreateBlob(cs_dxc.len, &cs_blob);
|
||||||
|
if (SUCCEEDED(hr)) {
|
||||||
|
MEMCPY(ID3D10Blob_GetBufferPointer(cs_blob), cs_dxc.text, cs_dxc.len);
|
||||||
} else {
|
} else {
|
||||||
if (!resource_exists(&vs_res)) {
|
error_str = LIT("Failed to create compute shader blob");
|
||||||
error_str = string_format(scratch.arena, LIT("Vertex shader source \"%F\" not found"), FMT_STR(desc->vs.file));
|
|
||||||
success = 0;
|
success = 0;
|
||||||
} else if (!resource_exists(&ps_res)) {
|
|
||||||
error_str = string_format(scratch.arena, LIT("Pixel shader source \"%F\" not found"), FMT_STR(desc->ps.file));
|
|
||||||
success = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct shader_compile_job_param vs = ZI;
|
|
||||||
vs.kind = SHADER_COMPILE_TASK_KIND_VS;
|
|
||||||
vs.pipeline = pipeline;
|
|
||||||
vs.shader_desc = desc->vs;
|
|
||||||
vs.shader_res = &vs_res;
|
|
||||||
|
|
||||||
struct shader_compile_job_param ps = ZI;
|
|
||||||
ps.kind = SHADER_COMPILE_TASK_KIND_PS;
|
|
||||||
ps.pipeline = pipeline;
|
|
||||||
ps.shader_desc = desc->ps;
|
|
||||||
ps.shader_res = &ps_res;
|
|
||||||
|
|
||||||
struct shader_compile_job_param cs = ZI;
|
|
||||||
cs.kind = SHADER_COMPILE_TASK_KIND_CS;
|
|
||||||
cs.pipeline = pipeline;
|
|
||||||
cs.shader_desc = desc->cs;
|
|
||||||
cs.shader_res = &cs_res;
|
|
||||||
|
|
||||||
/* Compile shaders */
|
|
||||||
if (success) {
|
|
||||||
if (has_cs) {
|
|
||||||
struct shader_compile_job_param *params[] = { &cs };
|
|
||||||
struct shader_compile_job_sig comp_sig = { .params = params };
|
|
||||||
struct snc_counter counter = ZI;
|
|
||||||
sys_run(countof(params), shader_compile_job, &comp_sig, SYS_POOL_INHERIT, SYS_PRIORITY_INHERIT, &counter);
|
|
||||||
snc_counter_wait(&counter);
|
|
||||||
success = cs.success;
|
|
||||||
} else {
|
|
||||||
struct shader_compile_job_param *params[] = { &vs, &ps };
|
|
||||||
struct shader_compile_job_sig comp_sig = { .params = params };
|
|
||||||
struct snc_counter counter = ZI;
|
|
||||||
sys_run(countof(params), shader_compile_job, &comp_sig, SYS_POOL_INHERIT, SYS_PRIORITY_INHERIT, &counter);
|
|
||||||
snc_counter_wait(&counter);
|
|
||||||
success = vs.success && ps.success;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get root signature blob
|
/* Get root signature blob
|
||||||
* NOTE: This isn't necessary for creating the root signature (since it
|
* NOTE: This isn't necessary for creating the root signature (since it
|
||||||
* could reuse the shader blob), however we'd like to verify that the
|
* could reuse the shader blob), however we'd like to verify that the
|
||||||
* root signature exists and matches between shaders. */
|
* root signature exists and matches between vs & ps shaders. */
|
||||||
ID3D10Blob *rootsig_blob = 0;
|
ID3D10Blob *rootsig_blob = 0;
|
||||||
if (success) {
|
if (success) {
|
||||||
__profn("Validate root signatures");
|
__profn("Validate root signatures");
|
||||||
if (has_cs) {
|
if (cs_dxc.len > 0) {
|
||||||
u32 cs_rootsig_data_len = 0;
|
u32 cs_rootsig_data_len = 0;
|
||||||
ID3D10Blob *cs_rootsig_blob = 0;
|
ID3D10Blob *cs_rootsig_blob = 0;
|
||||||
D3DGetBlobPart(ID3D10Blob_GetBufferPointer(cs.blob), ID3D10Blob_GetBufferSize(cs.blob), D3D_BLOB_ROOT_SIGNATURE, 0, &cs_rootsig_blob);
|
D3DGetBlobPart(ID3D10Blob_GetBufferPointer(cs_blob), ID3D10Blob_GetBufferSize(cs_blob), D3D_BLOB_ROOT_SIGNATURE, 0, &cs_rootsig_blob);
|
||||||
if (cs_rootsig_blob) {
|
if (cs_rootsig_blob) {
|
||||||
cs_rootsig_data_len = ID3D10Blob_GetBufferSize(cs_rootsig_blob);
|
cs_rootsig_data_len = ID3D10Blob_GetBufferSize(cs_rootsig_blob);
|
||||||
}
|
}
|
||||||
if (cs_rootsig_data_len == 0) {
|
if (cs_rootsig_data_len == 0) {
|
||||||
success = 0;
|
success = 0;
|
||||||
error_str = LIT("Vertex shader is missing root signature");
|
error_str = LIT("Compute shader is missing root signature");
|
||||||
} else {
|
} else {
|
||||||
rootsig_blob = cs_rootsig_blob;
|
rootsig_blob = cs_rootsig_blob;
|
||||||
}
|
}
|
||||||
@ -1251,8 +1042,8 @@ INTERNAL SYS_JOB_DEF(pipeline_alloc_job, job)
|
|||||||
u32 ps_rootsig_data_len = 0;
|
u32 ps_rootsig_data_len = 0;
|
||||||
ID3D10Blob *vs_rootsig_blob = 0;
|
ID3D10Blob *vs_rootsig_blob = 0;
|
||||||
ID3D10Blob *ps_rootsig_blob = 0;
|
ID3D10Blob *ps_rootsig_blob = 0;
|
||||||
D3DGetBlobPart(ID3D10Blob_GetBufferPointer(vs.blob), ID3D10Blob_GetBufferSize(vs.blob), D3D_BLOB_ROOT_SIGNATURE, 0, &vs_rootsig_blob);
|
D3DGetBlobPart(ID3D10Blob_GetBufferPointer(vs_blob), ID3D10Blob_GetBufferSize(vs_blob), D3D_BLOB_ROOT_SIGNATURE, 0, &vs_rootsig_blob);
|
||||||
D3DGetBlobPart(ID3D10Blob_GetBufferPointer(ps.blob), ID3D10Blob_GetBufferSize(ps.blob), D3D_BLOB_ROOT_SIGNATURE, 0, &ps_rootsig_blob);
|
D3DGetBlobPart(ID3D10Blob_GetBufferPointer(ps_blob), ID3D10Blob_GetBufferSize(ps_blob), D3D_BLOB_ROOT_SIGNATURE, 0, &ps_rootsig_blob);
|
||||||
if (vs_rootsig_blob) {
|
if (vs_rootsig_blob) {
|
||||||
vs_rootsig_data = ID3D10Blob_GetBufferPointer(vs_rootsig_blob);
|
vs_rootsig_data = ID3D10Blob_GetBufferPointer(vs_rootsig_blob);
|
||||||
vs_rootsig_data_len = ID3D10Blob_GetBufferSize(vs_rootsig_blob);
|
vs_rootsig_data_len = ID3D10Blob_GetBufferSize(vs_rootsig_blob);
|
||||||
@ -1293,14 +1084,12 @@ INTERNAL SYS_JOB_DEF(pipeline_alloc_job, job)
|
|||||||
/* Create PSO */
|
/* Create PSO */
|
||||||
ID3D12PipelineState *pso = 0;
|
ID3D12PipelineState *pso = 0;
|
||||||
if (success) {
|
if (success) {
|
||||||
if (has_cs) {
|
if (cs_dxc.len > 0) {
|
||||||
__profn("Create compute PSO");
|
__profn("Create compute PSO");
|
||||||
D3D12_COMPUTE_PIPELINE_STATE_DESC pso_desc = { 0 };
|
D3D12_COMPUTE_PIPELINE_STATE_DESC pso_desc = { 0 };
|
||||||
pso_desc.pRootSignature = rootsig;
|
pso_desc.pRootSignature = rootsig;
|
||||||
if (cs.success) {
|
pso_desc.CS.pShaderBytecode = ID3D10Blob_GetBufferPointer(cs_blob);
|
||||||
pso_desc.CS.pShaderBytecode = ID3D10Blob_GetBufferPointer(cs.blob);
|
pso_desc.CS.BytecodeLength = ID3D10Blob_GetBufferSize(cs_blob);
|
||||||
pso_desc.CS.BytecodeLength = ID3D10Blob_GetBufferSize(cs.blob);
|
|
||||||
}
|
|
||||||
hr = ID3D12Device_CreateComputePipelineState(G.device, &pso_desc, &IID_ID3D12PipelineState, (void **)&pso);
|
hr = ID3D12Device_CreateComputePipelineState(G.device, &pso_desc, &IID_ID3D12PipelineState, (void **)&pso);
|
||||||
} else {
|
} else {
|
||||||
__profn("Create graphics PSO");
|
__profn("Create graphics PSO");
|
||||||
@ -1364,14 +1153,10 @@ INTERNAL SYS_JOB_DEF(pipeline_alloc_job, job)
|
|||||||
/* PSO */
|
/* PSO */
|
||||||
D3D12_GRAPHICS_PIPELINE_STATE_DESC pso_desc = { 0 };
|
D3D12_GRAPHICS_PIPELINE_STATE_DESC pso_desc = { 0 };
|
||||||
pso_desc.pRootSignature = rootsig;
|
pso_desc.pRootSignature = rootsig;
|
||||||
if (vs.success) {
|
pso_desc.VS.pShaderBytecode = ID3D10Blob_GetBufferPointer(vs_blob);
|
||||||
pso_desc.VS.pShaderBytecode = ID3D10Blob_GetBufferPointer(vs.blob);
|
pso_desc.VS.BytecodeLength = ID3D10Blob_GetBufferSize(vs_blob);
|
||||||
pso_desc.VS.BytecodeLength = ID3D10Blob_GetBufferSize(vs.blob);
|
pso_desc.PS.pShaderBytecode = ID3D10Blob_GetBufferPointer(ps_blob);
|
||||||
}
|
pso_desc.PS.BytecodeLength = ID3D10Blob_GetBufferSize(ps_blob);
|
||||||
if (ps.success) {
|
|
||||||
pso_desc.PS.pShaderBytecode = ID3D10Blob_GetBufferPointer(ps.blob);
|
|
||||||
pso_desc.PS.BytecodeLength = ID3D10Blob_GetBufferSize(ps.blob);
|
|
||||||
}
|
|
||||||
pso_desc.BlendState = blend_desc;
|
pso_desc.BlendState = blend_desc;
|
||||||
pso_desc.SampleMask = UINT_MAX;
|
pso_desc.SampleMask = UINT_MAX;
|
||||||
pso_desc.RasterizerState = raster_desc;
|
pso_desc.RasterizerState = raster_desc;
|
||||||
@ -1398,50 +1183,27 @@ INTERNAL SYS_JOB_DEF(pipeline_alloc_job, job)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Parse errors */
|
/* Parse errors */
|
||||||
parse_pipeline_errors(pipeline, cs.error_blob);
|
if (!success && error_str.len <= 0) {
|
||||||
parse_pipeline_errors(pipeline, vs.error_blob);
|
|
||||||
parse_pipeline_errors(pipeline, ps.error_blob);
|
|
||||||
if (!success && pipeline->first_error == 0 && error_str.len == 0) {
|
|
||||||
error_str = LIT("Unknown error");
|
error_str = LIT("Unknown error");
|
||||||
}
|
}
|
||||||
if (error_str.len > 0) {
|
|
||||||
struct pipeline_error *error = arena_push(pipeline->arena, struct pipeline_error);
|
|
||||||
error->msg = string_copy(pipeline->arena, error_str);
|
|
||||||
if (pipeline->last_error) {
|
|
||||||
pipeline->last_error->next = error;
|
|
||||||
} else {
|
|
||||||
pipeline->first_error = error;
|
|
||||||
}
|
|
||||||
pipeline->last_error = error;
|
|
||||||
}
|
|
||||||
|
|
||||||
pipeline->pso = pso;
|
pipeline->pso = pso;
|
||||||
pipeline->rootsig = rootsig;
|
pipeline->rootsig = rootsig;
|
||||||
pipeline->compilation_time_ns = sys_time_ns() - start_ns;
|
pipeline->compilation_time_ns = sys_time_ns() - start_ns;
|
||||||
pipeline->success = success;
|
pipeline->success = success;
|
||||||
|
pipeline->error = error_str;
|
||||||
|
|
||||||
if (has_cs) {
|
|
||||||
resource_close(&cs_res);
|
|
||||||
} else {
|
|
||||||
resource_close(&vs_res);
|
|
||||||
if (!ps_res_is_shared) {
|
|
||||||
resource_close(&ps_res);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (rootsig_blob) {
|
if (rootsig_blob) {
|
||||||
ID3D10Blob_Release(rootsig_blob);
|
ID3D10Blob_Release(rootsig_blob);
|
||||||
}
|
}
|
||||||
if (vs.blob) {
|
if (vs_blob) {
|
||||||
ID3D10Blob_Release(vs.blob);
|
ID3D10Blob_Release(vs_blob);
|
||||||
}
|
}
|
||||||
if (vs.error_blob) {
|
if (ps_blob) {
|
||||||
ID3D10Blob_Release(vs.error_blob);
|
ID3D10Blob_Release(ps_blob);
|
||||||
}
|
}
|
||||||
if (ps.blob) {
|
if (cs_blob) {
|
||||||
ID3D10Blob_Release(ps.blob);
|
ID3D10Blob_Release(cs_blob);
|
||||||
}
|
|
||||||
if (ps.error_blob) {
|
|
||||||
ID3D10Blob_Release(ps.error_blob);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
scratch_end(scratch);
|
scratch_end(scratch);
|
||||||
@ -1453,7 +1215,12 @@ INTERNAL void pipeline_release_now(struct pipeline *pipeline)
|
|||||||
if (pipeline->pso) {
|
if (pipeline->pso) {
|
||||||
ID3D12PipelineState_Release(pipeline->pso);
|
ID3D12PipelineState_Release(pipeline->pso);
|
||||||
}
|
}
|
||||||
arena_release(pipeline->arena);
|
struct snc_lock lock = snc_lock_e(&G.pipelines_mutex);
|
||||||
|
{
|
||||||
|
pipeline->next = G.first_free_pipeline;
|
||||||
|
G.first_free_pipeline = pipeline;
|
||||||
|
}
|
||||||
|
snc_unlock(&lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
@ -1509,13 +1276,13 @@ INTERNAL struct pipeline *pipeline_from_name(struct pipeline_scope *scope, struc
|
|||||||
struct pipeline *res = &g_nil_pipeline;
|
struct pipeline *res = &g_nil_pipeline;
|
||||||
u64 hash = hash_fnv64(HASH_FNV64_BASIS, name);
|
u64 hash = hash_fnv64(HASH_FNV64_BASIS, name);
|
||||||
|
|
||||||
struct pipeline *tmp = dict_get(scope->refs, hash);
|
struct pipeline *tmp = (struct pipeline *)dict_get(scope->refs, hash);
|
||||||
if (tmp) {
|
if (tmp) {
|
||||||
res = tmp;
|
res = tmp;
|
||||||
} else {
|
} else {
|
||||||
{
|
{
|
||||||
struct snc_lock lock = snc_lock_e(&G.pipelines_mutex);
|
struct snc_lock lock = snc_lock_e(&G.pipelines_mutex);
|
||||||
tmp = dict_get(G.top_successful_pipelines, hash);
|
tmp = (struct pipeline *)dict_get(G.top_successful_pipelines, hash);
|
||||||
if (tmp) {
|
if (tmp) {
|
||||||
++tmp->refcount;
|
++tmp->refcount;
|
||||||
}
|
}
|
||||||
@ -1562,27 +1329,114 @@ INTERNAL void pipeline_register(u64 num_pipelines, struct pipeline **pipelines)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if RESOURCE_RELOADING
|
#if RESOURCE_RELOADING
|
||||||
INTERNAL RESOURCE_WATCH_CALLBACK_FUNC_DEF(pipeline_resource_watch_callback, name)
|
INTERNAL WATCH_CALLBACK_FUNC_DEF(pipeline_watch_callback, name)
|
||||||
{
|
{
|
||||||
__prof;
|
__prof;
|
||||||
struct arena_temp scratch = scratch_begin_no_conflict();
|
struct arena_temp scratch = scratch_begin_no_conflict();
|
||||||
|
|
||||||
/* Find dirty pipelines */
|
struct string rs_extension = LIT(".hlsl_rs");
|
||||||
u64 hash = hash_fnv64(HASH_FNV64_BASIS, name);
|
struct string cs_extension = LIT(".hlsl_cs");
|
||||||
|
|
||||||
|
b32 is_src = string_starts_with(name, LIT("src/"));
|
||||||
|
b32 is_rs = is_src && string_ends_with(name, rs_extension);
|
||||||
|
b32 is_cs = is_src && !is_rs && string_ends_with(name, cs_extension);
|
||||||
|
b32 success = 0;
|
||||||
|
|
||||||
|
/* Recompile shaders */
|
||||||
|
struct string pipeline_name = ZI;
|
||||||
|
struct string friendly_name = ZI;
|
||||||
|
i32 num_shaders = 0;
|
||||||
|
struct shader_compile_desc *shader_descs = 0;
|
||||||
|
struct shader_compile_result *shader_results = 0;
|
||||||
|
if (is_rs || is_cs) {
|
||||||
|
logf_debug("Change detected in shader source file \"%F\", recompiling...", FMT_STR(name));
|
||||||
|
success = 1;
|
||||||
|
struct sys_file file = sys_file_open_read_wait(name);
|
||||||
|
struct string data = sys_file_read_all(scratch.arena, file);
|
||||||
|
{
|
||||||
|
friendly_name = name;
|
||||||
|
struct string_array split = string_split(scratch.arena, friendly_name, LIT("src/"));
|
||||||
|
friendly_name = split.count > 0 ? string_cat(scratch.arena, LIT("src/"), split.strings[split.count - 1]) : friendly_name;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
pipeline_name = name;
|
||||||
|
struct string_array split = string_split(scratch.arena, pipeline_name, LIT("/"));
|
||||||
|
pipeline_name = split.count > 0 ? split.strings[split.count - 1] : pipeline_name;
|
||||||
|
split = string_split(scratch.arena, pipeline_name, LIT("."));
|
||||||
|
pipeline_name = split.count > 1 ? split.strings[split.count - 2] : pipeline_name;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
struct shader_compile_job_sig sig = ZI;
|
||||||
|
sig.arena = scratch.arena;
|
||||||
|
if (is_rs) {
|
||||||
|
num_shaders = 2;
|
||||||
|
shader_descs = arena_push_array(scratch.arena, struct shader_compile_desc, num_shaders);
|
||||||
|
shader_results = arena_push_array(scratch.arena, struct shader_compile_result, num_shaders);
|
||||||
|
sig.descs = shader_descs;
|
||||||
|
sig.results = shader_results;
|
||||||
|
sig.descs[0].src = data;
|
||||||
|
sig.descs[0].friendly_name = friendly_name;
|
||||||
|
sig.descs[0].entry = LIT("vs");
|
||||||
|
sig.descs[0].target = LIT("vs_6_6");
|
||||||
|
sig.descs[1].src = data;
|
||||||
|
sig.descs[1].friendly_name = friendly_name;
|
||||||
|
sig.descs[1].entry = LIT("ps");
|
||||||
|
sig.descs[1].target = LIT("ps_6_6");
|
||||||
|
} else if (is_cs) {
|
||||||
|
num_shaders = 1;
|
||||||
|
shader_descs = arena_push_array(scratch.arena, struct shader_compile_desc, num_shaders);
|
||||||
|
shader_results = arena_push_array(scratch.arena, struct shader_compile_result, num_shaders);
|
||||||
|
sig.descs = shader_descs;
|
||||||
|
sig.results = shader_results;
|
||||||
|
sig.descs[0].src = data;
|
||||||
|
sig.descs[0].friendly_name = friendly_name;
|
||||||
|
sig.descs[0].entry = LIT("cs");
|
||||||
|
sig.descs[0].target = LIT("cs_6_6");
|
||||||
|
}
|
||||||
|
{
|
||||||
|
struct snc_counter counter = ZI;
|
||||||
|
sys_run(num_shaders, shader_compile_job, &sig, SYS_POOL_INHERIT, SYS_PRIORITY_INHERIT, &counter);
|
||||||
|
snc_counter_wait(&counter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sys_file_close(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
for (i32 i = 0; i < num_shaders; ++i) {
|
||||||
|
struct shader_compile_desc *desc = &shader_descs[i];
|
||||||
|
struct shader_compile_result *result = &shader_results[i];
|
||||||
|
if (result->success) {
|
||||||
|
logf_success("Finished compiling shader \"%F:%F\" in %F seconds", FMT_STR(desc->friendly_name), FMT_STR(desc->entry), FMT_FLOAT(SECONDS_FROM_NS(result->elapsed_ns)));
|
||||||
|
if (result->errors.len > 0) {
|
||||||
|
struct string msg = result->errors;
|
||||||
|
log_warning(msg);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
struct string msg = result->errors;
|
||||||
|
log_error(msg);
|
||||||
|
success = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (success) {
|
||||||
|
/* Create pipeline descs */
|
||||||
u32 num_pipelines = 0;
|
u32 num_pipelines = 0;
|
||||||
struct pipeline_desc *pipeline_descs = arena_push_dry(scratch.arena, struct pipeline_desc);
|
struct pipeline_desc *pipeline_descs = arena_push_dry(scratch.arena, struct pipeline_desc);
|
||||||
{
|
for (struct dict_entry *entry = G.pipeline_descs->first; entry; entry = entry->next) {
|
||||||
struct snc_lock lock = snc_lock_s(&G.pipelines_mutex);
|
struct pipeline_desc *pipeline_desc = (struct pipeline_desc *)entry->value;
|
||||||
for (struct dict_entry *entry = G.top_pipelines->first; entry; entry = entry->next) {
|
struct pipeline_desc new_pipeline_desc = *pipeline_desc;
|
||||||
struct pipeline *pipeline = (struct pipeline *)entry->value;
|
if (string_eq(pipeline_desc->name, pipeline_name)) {
|
||||||
if (dict_get(pipeline->dependencies, hash) == 1) {
|
if (is_rs) {
|
||||||
logf_debug("Change detected in shader source file \"%F\", recompiling pipeline \"%F\"", FMT_STR(name), FMT_STR(pipeline->name));
|
new_pipeline_desc.vs_dxc = shader_results[0].dxc;
|
||||||
*arena_push(scratch.arena, struct pipeline_desc) = pipeline->desc;
|
new_pipeline_desc.ps_dxc = shader_results[1].dxc;
|
||||||
|
} else if (is_cs) {
|
||||||
|
new_pipeline_desc.cs_dxc = shader_results[0].dxc;
|
||||||
|
}
|
||||||
|
*arena_push_no_zero(scratch.arena, struct pipeline_desc) = new_pipeline_desc;
|
||||||
++num_pipelines;
|
++num_pipelines;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
snc_unlock(&lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Recompile dirty pipelines */
|
/* Recompile dirty pipelines */
|
||||||
if (num_pipelines > 0) {
|
if (num_pipelines > 0) {
|
||||||
@ -1602,20 +1456,20 @@ INTERNAL RESOURCE_WATCH_CALLBACK_FUNC_DEF(pipeline_resource_watch_callback, name
|
|||||||
struct pipeline *pipeline = pipelines[i];
|
struct pipeline *pipeline = pipelines[i];
|
||||||
if (pipeline->success) {
|
if (pipeline->success) {
|
||||||
logf_success("Successfully compiled pipeline \"%F\" in %F seconds", FMT_STR(pipeline->name), FMT_FLOAT(SECONDS_FROM_NS(pipeline->compilation_time_ns)));
|
logf_success("Successfully compiled pipeline \"%F\" in %F seconds", FMT_STR(pipeline->name), FMT_FLOAT(SECONDS_FROM_NS(pipeline->compilation_time_ns)));
|
||||||
if (pipeline->first_error) {
|
if (pipeline->error.len > 0) {
|
||||||
struct string msg = string_format(scratch.arena, LIT("Warning while compiling pipeline \"%F\":\n%F"), FMT_STR(pipeline->name), FMT_STR(pipeline->first_error->msg));
|
struct string msg = string_format(scratch.arena, LIT("Warning while compiling pipeline \"%F\":\n%F"), FMT_STR(pipeline->name), FMT_STR(pipeline->error));
|
||||||
log_warning(msg);
|
log_warning(msg);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
{
|
{
|
||||||
struct string error = pipeline->first_error ? pipeline->first_error->msg : LIT("Unknown error");
|
struct string error = pipeline->error.len > 0 ? pipeline->error : LIT("Unknown error");
|
||||||
struct string msg = string_format(scratch.arena, LIT("Error compiling pipeline \"%F\":\n%F"), FMT_STR(pipeline->name), FMT_STR(error));
|
struct string msg = string_format(scratch.arena, LIT("Error compiling pipeline \"%F\":\n%F"), FMT_STR(pipeline->name), FMT_STR(error));
|
||||||
log_error(msg);
|
log_error(msg);
|
||||||
}
|
}
|
||||||
struct pipeline *old_pipeline = dict_get(G.top_successful_pipelines, pipeline->hash);
|
struct pipeline *old_pipeline = (struct pipeline *)dict_get(G.top_successful_pipelines, pipeline->hash);
|
||||||
if (!old_pipeline) {
|
if (!old_pipeline) {
|
||||||
/* If no previously successful pipeline exists, then show a message box rather than logging since logs may not be visible to user */
|
/* If no previously successful pipeline exists, then show a message box rather than logging since logs may not be visible to user */
|
||||||
struct string error = pipeline->first_error ? pipeline->first_error->msg : LIT("Unknown error");
|
struct string error = pipeline->error.len > 0 ? pipeline->error : LIT("Unknown error");
|
||||||
struct string msg = string_format(scratch.arena, LIT("Error compiling pipeline \"%F\":\n\n%F"), FMT_STR(pipeline->name), FMT_STR(error));
|
struct string msg = string_format(scratch.arena, LIT("Error compiling pipeline \"%F\":\n\n%F"), FMT_STR(pipeline->name), FMT_STR(error));
|
||||||
sys_message_box(SYS_MESSAGE_BOX_KIND_WARNING, msg);
|
sys_message_box(SYS_MESSAGE_BOX_KIND_WARNING, msg);
|
||||||
}
|
}
|
||||||
@ -1626,6 +1480,7 @@ INTERNAL RESOURCE_WATCH_CALLBACK_FUNC_DEF(pipeline_resource_watch_callback, name
|
|||||||
}
|
}
|
||||||
pipeline_register(num_pipelines, pipelines);
|
pipeline_register(num_pipelines, pipelines);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
scratch_end(scratch);
|
scratch_end(scratch);
|
||||||
}
|
}
|
||||||
@ -2262,7 +2117,7 @@ INTERNAL struct command_buffer *command_list_push_buffer(struct command_list *cl
|
|||||||
{
|
{
|
||||||
u64 group_hash = command_buffer_hash_from_size(size);
|
u64 group_hash = command_buffer_hash_from_size(size);
|
||||||
struct dict_entry *cb_group_entry = dict_ensure_entry(G.command_buffers_arena, G.command_buffers_dict, group_hash);
|
struct dict_entry *cb_group_entry = dict_ensure_entry(G.command_buffers_arena, G.command_buffers_dict, group_hash);
|
||||||
cb_group = cb_group_entry->value;
|
cb_group = (struct command_buffer_group *)cb_group_entry->value;
|
||||||
if (!cb_group) {
|
if (!cb_group) {
|
||||||
/* Create group */
|
/* Create group */
|
||||||
cb_group = arena_push(G.command_buffers_arena, struct command_buffer_group);
|
cb_group = arena_push(G.command_buffers_arena, struct command_buffer_group);
|
||||||
@ -3288,10 +3143,10 @@ struct gp_resource *gp_run_render(struct gp_render_sig *render_sig, struct gp_re
|
|||||||
constants.flags = sh_uint_from_u32(shade_flags);
|
constants.flags = sh_uint_from_u32(shade_flags);
|
||||||
constants.tex_width = sh_uint_from_u32(render_size.x);
|
constants.tex_width = sh_uint_from_u32(render_size.x);
|
||||||
constants.tex_height = sh_uint_from_u32(render_size.y);
|
constants.tex_height = sh_uint_from_u32(render_size.y);
|
||||||
constants.frame_seed = sh_uint4_from_u32((u32)rand_u64_from_state(&sig->rand),
|
constants.frame_seed = sh_uint4_from_u32((u32)(rand_u64_from_state(&sig->rand) & 0xFFFFFFFF),
|
||||||
(u32)rand_u64_from_state(&sig->rand),
|
(u32)(rand_u64_from_state(&sig->rand) & 0xFFFFFFFF),
|
||||||
(u32)rand_u64_from_state(&sig->rand),
|
(u32)(rand_u64_from_state(&sig->rand) & 0xFFFFFFFF),
|
||||||
(u32)rand_u64_from_state(&sig->rand));
|
(u32)(rand_u64_from_state(&sig->rand) & 0xFFFFFFFF));
|
||||||
constants.frame_index = sh_uint_from_u32(sig->frame_index);
|
constants.frame_index = sh_uint_from_u32(sig->frame_index);
|
||||||
constants.camera_offset = sh_float2_from_v2(world_to_render_xf.og);
|
constants.camera_offset = sh_float2_from_v2(world_to_render_xf.og);
|
||||||
constants.albedo_tex_urid = sh_uint_from_u32(sig->albedo->srv_descriptor->index);
|
constants.albedo_tex_urid = sh_uint_from_u32(sig->albedo->srv_descriptor->index);
|
||||||
@ -3357,7 +3212,7 @@ struct gp_resource *gp_run_render(struct gp_render_sig *render_sig, struct gp_re
|
|||||||
constants.projection = sh_float4x4_from_mat4x4(blit_vp_matrix);
|
constants.projection = sh_float4x4_from_mat4x4(blit_vp_matrix);
|
||||||
constants.flags = sh_uint_from_u32(SH_BLIT_FLAG_TONE_MAP | SH_BLIT_FLAG_GAMMA_CORRECT);
|
constants.flags = sh_uint_from_u32(SH_BLIT_FLAG_TONE_MAP | SH_BLIT_FLAG_GAMMA_CORRECT);
|
||||||
constants.exposure = sh_float_from_f32(2.0);
|
constants.exposure = sh_float_from_f32(2.0);
|
||||||
constants.gamma = sh_float_from_f32(2.2);
|
constants.gamma = sh_float_from_f32((f32)2.2);
|
||||||
constants.tex_urid = sh_uint_from_u32(sig->shade_read->uav_descriptor->index);
|
constants.tex_urid = sh_uint_from_u32(sig->shade_read->uav_descriptor->index);
|
||||||
|
|
||||||
/* Set parameters */
|
/* Set parameters */
|
||||||
|
|||||||
@ -13,3 +13,10 @@ struct string inc_res_tar(void)
|
|||||||
return INCBIN_GET(res_tar);
|
return INCBIN_GET(res_tar);
|
||||||
}
|
}
|
||||||
#endif
|
#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);
|
struct string inc_res_tar(void);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
struct string inc_dxc_tar(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
#include "incbin.h"
|
#include "incbin.h"
|
||||||
#include "scratch.h"
|
#include "arena.h"
|
||||||
#include "string.h"
|
#include "string.h"
|
||||||
#include "atomic.h"
|
#include "atomic.h"
|
||||||
#include "intrinsics.h"
|
#include "intrinsics.h"
|
||||||
|
|||||||
@ -16,6 +16,10 @@
|
|||||||
#define COBJMACROS
|
#define COBJMACROS
|
||||||
#define WIN32_LEAN_AND_MEAN
|
#define WIN32_LEAN_AND_MEAN
|
||||||
#define UNICODE
|
#define UNICODE
|
||||||
|
#define WINVER 0x0A00
|
||||||
|
#define _WIN32_WINNT 0x0A00
|
||||||
|
#define NTDDI_WIN11_DT 0x0C0A0000
|
||||||
|
#define NTDDI_VERSION 0x0A000000
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
#include <initguid.h>
|
#include <initguid.h>
|
||||||
#include <objbase.h>
|
#include <objbase.h>
|
||||||
|
|||||||
@ -1,12 +1,12 @@
|
|||||||
#ifndef PROF_H
|
#ifndef PROF_H
|
||||||
#define PROF_H
|
#define PROF_H
|
||||||
|
|
||||||
|
#if PROFILING
|
||||||
|
|
||||||
#if COMPILER_MSVC
|
#if COMPILER_MSVC
|
||||||
# error "MSVC not supported for profiling (cleanup attributes are required for profiling markup)"
|
# error "MSVC not supported for profiling (cleanup attributes are required for profiling markup)"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if PROFILING
|
|
||||||
|
|
||||||
#define PROFILING_SYSTEM_TRACE 0
|
#define PROFILING_SYSTEM_TRACE 0
|
||||||
#define PROFILING_CAPTURE_FRAME_IMAGE 0
|
#define PROFILING_CAPTURE_FRAME_IMAGE 0
|
||||||
#define PROFILING_LOCKS 0
|
#define PROFILING_LOCKS 0
|
||||||
|
|||||||
193
src/resource.c
193
src/resource.c
@ -21,33 +21,12 @@ GLOBAL struct {
|
|||||||
#if RESOURCES_EMBEDDED
|
#if RESOURCES_EMBEDDED
|
||||||
struct tar_archive archive;
|
struct tar_archive archive;
|
||||||
#endif
|
#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);
|
} G = ZI, DEBUG_ALIAS(G, G_resource);
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
* Startup
|
* 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)
|
struct resource_startup_receipt resource_startup(void)
|
||||||
{
|
{
|
||||||
__prof;
|
__prof;
|
||||||
@ -66,17 +45,6 @@ struct resource_startup_receipt resource_startup(void)
|
|||||||
}
|
}
|
||||||
#endif
|
#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 };
|
return (struct resource_startup_receipt) { 0 };
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,11 +58,9 @@ struct resource resource_open(struct string name)
|
|||||||
#if RESOURCES_EMBEDDED
|
#if RESOURCES_EMBEDDED
|
||||||
struct resource res = ZI;
|
struct resource res = ZI;
|
||||||
struct tar_entry *entry = tar_get(&G.archive, name);
|
struct tar_entry *entry = tar_get(&G.archive, name);
|
||||||
if (entry) {
|
|
||||||
res._data = entry->data;
|
res._data = entry->data;
|
||||||
res._name = entry->file_name;
|
res._name = entry->file_name;
|
||||||
res._exists = 1;
|
res._exists = entry->valid;
|
||||||
}
|
|
||||||
return res;
|
return res;
|
||||||
#else
|
#else
|
||||||
struct resource res = ZI;
|
struct resource res = ZI;
|
||||||
@ -146,160 +112,3 @@ void resource_close(struct resource *res_ptr)
|
|||||||
sys_file_close(res_ptr->_file);
|
sys_file_close(res_ptr->_file);
|
||||||
}
|
}
|
||||||
#endif
|
#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"
|
#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.
|
/* A resource contains data that can be retrieved globally by name.
|
||||||
* If enabled during compilation, resource data is embedded in the
|
* 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)
|
#define resource_get_name(res_ptr) STRING((res_ptr)->_name_len, (res_ptr)->_name_text)
|
||||||
#endif
|
#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
|
#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
|
* Root signature
|
||||||
@ -1,4 +1,4 @@
|
|||||||
#include "sh/sh_common.h"
|
#include "sh_common.h"
|
||||||
|
|
||||||
#define TAU 6.28318530718
|
#define TAU 6.28318530718
|
||||||
#define PI 3.14159265359
|
#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
|
* 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
|
* Root signature
|
||||||
@ -4,9 +4,9 @@
|
|||||||
#define SH_DECL(t, n) struct CAT(sh_, t) n
|
#define SH_DECL(t, n) struct CAT(sh_, t) n
|
||||||
#define SH_DECLS(t, n) SH_DECL(t, n)
|
#define SH_DECLS(t, n) SH_DECL(t, n)
|
||||||
#define SH_ENTRY(rootsig) static
|
#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 */ \
|
#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 */ \
|
((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 */
|
(sizeof(s) <= 256)) /* Root constant struct can only fit 64 DWORDS */
|
||||||
|
|
||||||
struct sh_uint { u32 v; };
|
struct sh_uint { u32 v; };
|
||||||
INLINE struct sh_uint sh_uint_from_u32(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
|
* Root signature
|
||||||
@ -69,7 +69,6 @@ INLINE float3 get_light_in_dir(uint2 ray_start, float2 ray_dir)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
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
|
* 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
|
* Root signature
|
||||||
12
src/sprite.c
12
src/sprite.c
@ -11,6 +11,7 @@
|
|||||||
#include "math.h"
|
#include "math.h"
|
||||||
#include "rand.h"
|
#include "rand.h"
|
||||||
#include "snc.h"
|
#include "snc.h"
|
||||||
|
#include "watch.h"
|
||||||
|
|
||||||
/* The evictor will begin evicting once cache usage is > threshold.
|
/* The evictor will begin evicting once cache usage is > threshold.
|
||||||
* It will entries until the budget has shrunk < target. */
|
* 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, _);
|
INTERNAL SYS_JOB_DEF(sprite_evictor_job, _);
|
||||||
|
|
||||||
#if RESOURCE_RELOADING
|
#if RESOURCE_RELOADING
|
||||||
INTERNAL RESOURCE_WATCH_CALLBACK_FUNC_DEF(sprite_resource_watch_callback, info);
|
INTERNAL WATCH_CALLBACK_FUNC_DEF(sprite_watch_callback, info);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct sprite_startup_receipt sprite_startup(void)
|
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_run(1, sprite_evictor_job, 0, SYS_POOL_BACKGROUND, SYS_PRIORITY_LOW, &G.shutdown_counter);
|
||||||
|
|
||||||
sys_on_exit(&sprite_shutdown);
|
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 };
|
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();
|
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);
|
struct sprite_tag tag = sprite_tag_from_path(name);
|
||||||
for (enum cache_entry_kind kind = 0; kind < NUM_CACHE_ENTRY_KINDS; ++kind) {
|
for (enum cache_entry_kind kind = 0; kind < NUM_CACHE_ENTRY_KINDS; ++kind) {
|
||||||
reload_if_exists(scope, tag, kind);
|
reload_if_exists(scope, tag, kind);
|
||||||
|
|||||||
58
src/string.c
58
src/string.c
@ -225,44 +225,38 @@ struct string string_cat(struct arena *arena, struct string str1, struct string
|
|||||||
return new_str;
|
return new_str;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* `arena` is where pieces items will be allocated. These strings point
|
/* `arena` is where pieces will be allocated. These strings point
|
||||||
* into the existing supplied string and do not allocate any new text. */
|
* 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 string_split(struct arena *arena, struct string str, struct string delim)
|
||||||
{
|
{
|
||||||
struct string_array pieces = {
|
struct string_array pieces = ZI;
|
||||||
.count = 0,
|
pieces.strings = arena_push_dry(arena, struct string);
|
||||||
.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 = {
|
b32 is_delimiter = string_eq(cmp, delim);
|
||||||
.len = 0,
|
if (is_delimiter) {
|
||||||
.text = str.text
|
struct string piece = ZI;
|
||||||
};
|
piece.text = &str.text[piece_start];
|
||||||
|
piece.len = i - piece_start;
|
||||||
for (u64 i = 0; i <= str.len - delim.len; ++i) {
|
i += delim.len;
|
||||||
/* Clamp comparison string so we don't overflow. */
|
piece_start = i;
|
||||||
struct string comp_str = {
|
if (piece.len > 0) {
|
||||||
.len = delim.len,
|
*arena_push_no_zero(arena, struct string) = piece;
|
||||||
.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;
|
++pieces.count;
|
||||||
piece.text = piece.text + piece.len + delim.len;
|
|
||||||
piece.len = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
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;
|
return pieces;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -8,8 +8,7 @@ struct snc_counter;
|
|||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
/* Futex-like wait & wake */
|
/* Futex-like wait & wake */
|
||||||
|
void sys_wait(volatile void *addr, void *cmp, u32 size, i64 timeout_ns);
|
||||||
void sys_wait(void *addr, void *cmp, u32 size, i64 timeout_ns);
|
|
||||||
void sys_wake(void *addr, i32 count);
|
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);
|
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
|
* Window
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|||||||
@ -481,7 +481,7 @@ INTERNAL b32 thread_try_release(struct thread *thread, f32 timeout_seconds)
|
|||||||
HANDLE handle = t->handle;
|
HANDLE handle = t->handle;
|
||||||
if (handle) {
|
if (handle) {
|
||||||
/* Wait for thread to stop */
|
/* 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);
|
DWORD wait_res = WaitForSingleObject(handle, timeout_ms);
|
||||||
if (wait_res == WAIT_OBJECT_0) {
|
if (wait_res == WAIT_OBJECT_0) {
|
||||||
/* Release thread */
|
/* Release thread */
|
||||||
@ -524,7 +524,7 @@ INTERNAL void thread_wait_release(struct thread *thread)
|
|||||||
* Wait / wake
|
* 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());
|
struct fiber *fiber = fiber_from_id(sys_current_fiber_id());
|
||||||
i16 parent_id = fiber->parent_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));
|
job_fiber_yield(fiber, fiber_from_id(parent_id));
|
||||||
} else {
|
} else {
|
||||||
i32 timeout_ms = 0;
|
i32 timeout_ms = 0;
|
||||||
if (timeout_ns == I64_MAX) {
|
if (timeout_ns > 10000000000000000ll) {
|
||||||
timeout_ms = INFINITE;
|
timeout_ms = INFINITE;
|
||||||
} else if (timeout_ns != 0) {
|
} else if (timeout_ns != 0) {
|
||||||
timeout_ms = timeout_ns / 1000000;
|
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);
|
tm_unlock(&G.wait_lists_arena_lock);
|
||||||
}
|
}
|
||||||
MEMZERO_STRUCT(wait_addr_list);
|
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) {
|
if (wait_addr_bin->last_wait_list) {
|
||||||
wait_addr_bin->last_wait_list->next_in_bin = wait_addr_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;
|
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;
|
wait_addr_bin->last_wait_list = wait_addr_list;
|
||||||
}
|
}
|
||||||
/* Insert fiber into 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) {
|
if (wait_addr_list->last_waiter) {
|
||||||
fiber_from_id(wait_addr_list->last_waiter)->next_addr_waiter = job_fiber_id;
|
fiber_from_id(wait_addr_list->last_waiter)->next_addr_waiter = job_fiber_id;
|
||||||
job_fiber->prev_addr_waiter = wait_addr_list->last_waiter;
|
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);
|
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
|
* 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 string file_name = string_cat(arena, prefix, file_name_cstr);
|
||||||
|
|
||||||
struct tar_entry *entry = arena_push(arena, struct tar_entry);
|
struct tar_entry *entry = arena_push(arena, struct tar_entry);
|
||||||
|
entry->valid = 1;
|
||||||
entry->is_dir = is_dir;
|
entry->is_dir = is_dir;
|
||||||
entry->file_name = file_name;
|
entry->file_name = file_name;
|
||||||
entry->data = file_data;
|
entry->data = file_data;
|
||||||
@ -162,8 +163,10 @@ struct tar_archive tar_parse(struct arena *arena, struct string data, struct str
|
|||||||
return archive;
|
return archive;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
READONLY GLOBAL struct tar_entry g_nil_tar_entry = ZI;
|
||||||
struct tar_entry *tar_get(struct tar_archive *archive, struct string name)
|
struct tar_entry *tar_get(struct tar_archive *archive, struct string name)
|
||||||
{
|
{
|
||||||
u64 hash = hash_fnv64(HASH_FNV64_BASIS, 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"
|
#include "util.h"
|
||||||
|
|
||||||
struct tar_entry {
|
struct tar_entry {
|
||||||
|
b32 valid;
|
||||||
struct string file_name;
|
struct string file_name;
|
||||||
struct string data;
|
struct string data;
|
||||||
|
|
||||||
|
|||||||
@ -266,7 +266,7 @@ INLINE void sleep_precise(i64 sleep_time_ns)
|
|||||||
__prof;
|
__prof;
|
||||||
|
|
||||||
i64 big_sleep = sys_current_scheduler_period_ns();
|
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 tolerance = 1000000000;
|
||||||
|
|
||||||
i64 now_ns = sys_time_ns();
|
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