diff --git a/src/base/base_win32/base_win32_futex.c b/src/base/base_win32/base_win32_futex.c index acf81fd1..5ab18e86 100644 --- a/src/base/base_win32/base_win32_futex.c +++ b/src/base/base_win32/base_win32_futex.c @@ -8,7 +8,7 @@ void FutexYieldNeq(volatile void *addr, void *cmp, u8 cmp_size) void FutexWakeNeq(void *addr) { - WakeByAddressSingle(addr); + WakeByAddressAll(addr); } //////////////////////////////////////////////////////////// diff --git a/src/meta/meta.c b/src/meta/meta.c index 5ecc972c..1fb6c6a7 100644 --- a/src/meta/meta.c +++ b/src/meta/meta.c @@ -1081,242 +1081,195 @@ void BuildEntryPoint(WaveLaneCtx *lane, void *udata) * */ - Struct(SharedResults) - { - /* C compilation */ - AlignedBlock(CachelineSize) - { - M_ErrorList errors; - StringList obj_files; - StringList output; - i32 return_code; - } c_comp; - - /* HLSL compilation */ - AlignedBlock(CachelineSize) - { - M_ErrorList errors; - StringList obj_files; - StringList output; - i32 return_code; - } gpu_comp; - - /* Resource generation */ - AlignedBlock(CachelineSize) - { - M_ErrorList errors; - StringList obj_files; - StringList output; - i32 return_code; - } res_comp; - }; - - SharedResults *shared = 0; - if (lane->idx == 0) - { - shared = PushStruct(arena, SharedResults); - } - WaveSyncBroadcast(lane, 0, &shared); - String shader_store_name = Lit("ShadersStore"); + String c_out_file = F_GetFull(arena, StringF(arena, "%F_gen_c.c", FmtString(cmdline.leaf_layer_name))); + String gpu_out_file = F_GetFull(arena, StringF(arena, "%F_gen_gpu.hlsl", FmtString(cmdline.leaf_layer_name))); ////////////////////////////// - //- Compile C + //- Generate final C file + Struct(CGenData) { - /* Compile C */ + M_ErrorList errors; + }; + CGenData cgen = ZI; + { + String c_out_file = F_GetFull(arena, StringF(arena, "%F_gen_c.c", FmtString(cmdline.leaf_layer_name))); + StringList c_store_lines = ZI; + StringList c_shader_lines = ZI; + StringList c_include_lines = ZI; + StringList c_startup_lines = ZI; { - //- Generate C file - String c_out_file = F_GetFull(arena, StringF(arena, "%F_gen_c.c", FmtString(cmdline.leaf_layer_name))); + for (M_Entry *entry = flattened.first; entry->valid; entry = entry->next) { - StringList c_store_lines = ZI; - StringList c_shader_lines = ZI; - StringList c_include_lines = ZI; - StringList c_startup_lines = ZI; + M_EntryKind kind = entry->kind; + M_Token *entry_tok = entry->name_token; + M_Token *arg0_tok = entry->arg_tokens[0]; + M_Token *arg1_tok = entry->arg_tokens[1]; + switch (kind) { - for (M_Entry *entry = flattened.first; entry->valid; entry = entry->next) + default: break; + case M_EntryKind_EmbedDir: { - M_EntryKind kind = entry->kind; - M_Token *entry_tok = entry->name_token; - M_Token *arg0_tok = entry->arg_tokens[0]; - M_Token *arg1_tok = entry->arg_tokens[1]; - switch (kind) + if (arg0_tok->valid && arg1_tok->valid) { - default: break; - case M_EntryKind_EmbedDir: + String store_name = arg0_tok->s; + String token_file = arg1_tok->file->name; + String token_parent_dir = F_GetParentDir(token_file); + String arg_dir = arg1_tok->s; + String full = F_GetFullCrossPlatform(arena, StringF(arena, "%F/%F", FmtString(token_parent_dir), FmtString(arg_dir))); + if (F_IsDir(full)) { - if (arg0_tok->valid && arg1_tok->valid) - { - String store_name = arg0_tok->s; - String token_file = arg1_tok->file->name; - String token_parent_dir = F_GetParentDir(token_file); - String arg_dir = arg1_tok->s; - String full = F_GetFullCrossPlatform(arena, StringF(arena, "%F/%F", FmtString(token_parent_dir), FmtString(arg_dir))); - if (F_IsDir(full)) - { - u64 hash = HashFnv64(Fnv64Basis, StringF(arena, "%F/", FmtString(store_name))); - String line = StringF(arena, "ResourceStore %F = { 0x%F };", FmtString(store_name), FmtHex(hash)); - PushStringToList(arena, &c_store_lines, line); - } - else - { - String err = StringF(arena, "Directory '%F' not found", FmtString(full)); - M_PushError(arena, &shared->c_comp.errors, arg1_tok, err); - } - } - else - { - M_PushError(arena, &shared->c_comp.errors, entry_tok, Lit("Expected resource store & directory name")); - } - } break; - case M_EntryKind_VertexShader: - case M_EntryKind_PixelShader: - case M_EntryKind_ComputeShader: + u64 hash = HashFnv64(Fnv64Basis, StringF(arena, "%F/", FmtString(store_name))); + String line = StringF(arena, "ResourceStore %F = { 0x%F };", FmtString(store_name), FmtHex(hash)); + PushStringToList(arena, &c_store_lines, line); + } + else { - if (arg0_tok->valid) - { - String shader_type = kind == M_EntryKind_VertexShader ? Lit("VertexShader") - : kind == M_EntryKind_PixelShader ? Lit("PixelShader") - : kind == M_EntryKind_ComputeShader ? Lit("ComputeShader") - : Lit(""); - String shader_name = arg0_tok->s; - u64 hash = HashFnv64(Fnv64Basis, StringF(arena, "%F/%F", FmtString(shader_store_name), FmtString(shader_name))); - String line = StringF(arena, "%F %F = { 0x%F };", FmtString(shader_type), FmtString(shader_name), FmtHex(hash)); - PushStringToList(arena, &c_shader_lines, line); - } - else - { - M_PushError(arena, &shared->c_comp.errors, entry_tok, Lit("Expected shader name")); - } - } break; - case M_EntryKind_IncludeC: + String err = StringF(arena, "Directory '%F' not found", FmtString(full)); + M_PushError(arena, &cgen.errors, arg1_tok, err); + } + } + else + { + M_PushError(arena, &cgen.errors, entry_tok, Lit("Expected resource store & directory name")); + } + } break; + case M_EntryKind_VertexShader: + case M_EntryKind_PixelShader: + case M_EntryKind_ComputeShader: + { + if (arg0_tok->valid) + { + String shader_type = kind == M_EntryKind_VertexShader ? Lit("VertexShader") + : kind == M_EntryKind_PixelShader ? Lit("PixelShader") + : kind == M_EntryKind_ComputeShader ? Lit("ComputeShader") + : Lit(""); + String shader_name = arg0_tok->s; + u64 hash = HashFnv64(Fnv64Basis, StringF(arena, "%F/%F", FmtString(shader_store_name), FmtString(shader_name))); + String line = StringF(arena, "%F %F = { 0x%F };", FmtString(shader_type), FmtString(shader_name), FmtHex(hash)); + PushStringToList(arena, &c_shader_lines, line); + } + else + { + M_PushError(arena, &cgen.errors, entry_tok, Lit("Expected shader name")); + } + } break; + case M_EntryKind_IncludeC: + { + if (arg0_tok->valid) + { + String token_file = arg0_tok->file->name; + String token_parent_dir = F_GetParentDir(token_file); + String arg_file = arg0_tok->s; + String full = F_GetFull(arena, StringF(arena, "%F/%F", FmtString(token_parent_dir), FmtString(arg_file))); + if (F_IsFile(full)) { - if (arg0_tok->valid) - { - String token_file = arg0_tok->file->name; - String token_parent_dir = F_GetParentDir(token_file); - String arg_file = arg0_tok->s; - String full = F_GetFull(arena, StringF(arena, "%F/%F", FmtString(token_parent_dir), FmtString(arg_file))); - if (F_IsFile(full)) - { - String line = StringF(arena, "#include \"%F\"", FmtString(full)); - PushStringToList(arena, &c_include_lines, line); - } - else - { - String err = StringF(arena, "File '%F' not found", FmtString(full)); - M_PushError(arena, &shared->c_comp.errors, arg0_tok, err); - } - } - else - { - M_PushError(arena, &shared->c_comp.errors, entry_tok, Lit("Expected file name")); - } - } break; - case M_EntryKind_Startup: + String line = StringF(arena, "#include \"%F\"", FmtString(full)); + PushStringToList(arena, &c_include_lines, line); + } + else { - if (arg0_tok->valid) - { - String startup = arg0_tok->s; - String line = StringF(arena, " %F();", FmtString(startup)); - PushStringToList(arena, &c_startup_lines, line); - } - else - { - M_PushError(arena, &shared->c_comp.errors, entry_tok, Lit("Expected startup function name")); - } - } break; + String err = StringF(arena, "File '%F' not found", FmtString(full)); + M_PushError(arena, &cgen.errors, arg0_tok, err); + } } - } - } - if (&shared->c_comp.errors.count == 0) - { - StringList c_out_lines = ZI; - PushStringToList(arena, &c_out_lines, Lit("// Auto generated file")); - /* Include base layer */ - { - String base_inc_path = F_GetFull(arena, Lit("../src/base/base_inc.h")); - PushStringToList(arena, &c_out_lines, Lit("")); - PushStringToList(arena, &c_out_lines, Lit("//- Base layer includes")); - PushStringToList(arena, &c_out_lines, StringF(arena, "#include \"%F\"", FmtString(base_inc_path))); - } - /* Define resource stores */ - if (c_store_lines.count > 0) - { - PushStringToList(arena, &c_out_lines, Lit("")); - PushStringToList(arena, &c_out_lines, Lit("//- Resource stores")); - for (StringListNode *n = c_store_lines.first; n; n = n->next) + else { - PushStringToList(arena, &c_out_lines, n->s); + M_PushError(arena, &cgen.errors, entry_tok, Lit("Expected file name")); } - } - /* Define shaders */ - if (c_shader_lines.count > 0) + } break; + case M_EntryKind_Startup: { - PushStringToList(arena, &c_out_lines, Lit("")); - PushStringToList(arena, &c_out_lines, Lit("//- Shaders")); - for (StringListNode *n = c_shader_lines.first; n; n = n->next) + if (arg0_tok->valid) { - PushStringToList(arena, &c_out_lines, n->s); + String startup = arg0_tok->s; + String line = StringF(arena, " %F();", FmtString(startup)); + PushStringToList(arena, &c_startup_lines, line); } - } - /* Include dependency layers */ - if (c_include_lines.count > 0) - { - PushStringToList(arena, &c_out_lines, Lit("")); - PushStringToList(arena, &c_out_lines, Lit("//- Dependency graph includes")); - for (StringListNode *n = c_include_lines.first; n; n = n->next) + else { - PushStringToList(arena, &c_out_lines, n->s); + M_PushError(arena, &cgen.errors, entry_tok, Lit("Expected startup function name")); } - } - /* Define StartupLayers */ - { - PushStringToList(arena, &c_out_lines, Lit("")); - PushStringToList(arena, &c_out_lines, Lit("//- Startup")); - PushStringToList(arena, &c_out_lines, Lit("void StartupLayers(void)")); - PushStringToList(arena, &c_out_lines, Lit("{")); - for (StringListNode *n = c_startup_lines.first; n; n = n->next) - { - PushStringToList(arena, &c_out_lines, n->s); - } - PushStringToList(arena, &c_out_lines, Lit("}")); - } - /* Write to file */ - PushStringToList(arena, &c_out_lines, Lit("")); - String c_out = StringFromList(arena, c_out_lines, Lit("\n")); - F_ClearWrite(c_out_file, c_out); + } break; } } - - //- Compile C - String c_out_obj_file = StringF(arena, "%F_gen_c.obj", FmtString(cmdline.leaf_layer_name)); - PushStringToList(arena, &shared->c_comp.obj_files, c_out_obj_file); - if (shared->c_comp.errors.count == 0) + } + if (cgen.errors.count == 0) + { + StringList c_out_lines = ZI; + PushStringToList(arena, &c_out_lines, Lit("// Auto generated file")); + /* Include base layer */ { - String cmd = StringF(arena, - "cmd /c cl.exe /c %F -Fo:%F %F %F %F %F", - FmtString(c_out_file), - FmtString(c_out_obj_file), - FmtString(StringFromList(arena, cp.flags_msvc, Lit(" "))), - FmtString(StringFromList(arena, cp.compiler_only_flags_msvc, Lit(" "))), - FmtString(StringFromList(arena, cp.warnings_msvc, Lit(" "))), - FmtString(StringFromList(arena, cp.defs, Lit(" ")))); - OS_CommandResult cmd_result = OS_RunCommand(arena, cmd); - String cmd_output = TrimWhitespace(cmd_result.output); - if (cmd_output.len > 0) - { - PushStringToList(arena, &shared->c_comp.output, cmd_output); - } - shared->c_comp.return_code = cmd_result.code; + String base_inc_path = F_GetFull(arena, Lit("../src/base/base_inc.h")); + PushStringToList(arena, &c_out_lines, Lit("")); + PushStringToList(arena, &c_out_lines, Lit("//- Base layer includes")); + PushStringToList(arena, &c_out_lines, StringF(arena, "#include \"%F\"", FmtString(base_inc_path))); } + /* Define resource stores */ + if (c_store_lines.count > 0) + { + PushStringToList(arena, &c_out_lines, Lit("")); + PushStringToList(arena, &c_out_lines, Lit("//- Resource stores")); + for (StringListNode *n = c_store_lines.first; n; n = n->next) + { + PushStringToList(arena, &c_out_lines, n->s); + } + } + /* Define shaders */ + if (c_shader_lines.count > 0) + { + PushStringToList(arena, &c_out_lines, Lit("")); + PushStringToList(arena, &c_out_lines, Lit("//- Shaders")); + for (StringListNode *n = c_shader_lines.first; n; n = n->next) + { + PushStringToList(arena, &c_out_lines, n->s); + } + } + /* Include dependency layers */ + if (c_include_lines.count > 0) + { + PushStringToList(arena, &c_out_lines, Lit("")); + PushStringToList(arena, &c_out_lines, Lit("//- Dependency graph includes")); + for (StringListNode *n = c_include_lines.first; n; n = n->next) + { + PushStringToList(arena, &c_out_lines, n->s); + } + } + /* Define StartupLayers */ + { + PushStringToList(arena, &c_out_lines, Lit("")); + PushStringToList(arena, &c_out_lines, Lit("//- Startup")); + PushStringToList(arena, &c_out_lines, Lit("void StartupLayers(void)")); + PushStringToList(arena, &c_out_lines, Lit("{")); + for (StringListNode *n = c_startup_lines.first; n; n = n->next) + { + PushStringToList(arena, &c_out_lines, n->s); + } + PushStringToList(arena, &c_out_lines, Lit("}")); + } + /* Write to file */ + PushStringToList(arena, &c_out_lines, Lit("")); + String c_out = StringFromList(arena, c_out_lines, Lit("\n")); + F_ClearWrite(c_out_file, c_out); } } ////////////////////////////// - //- Compile shaders + //- Generate final HLSL file + Enum(ShaderEntryKind) { ShaderEntryKind_VS, ShaderEntryKind_PS, ShaderEntryKind_CS, }; + Struct(ShaderEntry) { ShaderEntry *next; ShaderEntryKind kind; String name; }; + Struct(GpuGenData) { + M_ErrorList errors; + ShaderEntry *first_shader_entry; + ShaderEntry *last_shader_entry; + u64 shader_entries_count; + }; + GpuGenData gpugen = ZI; + { + /* Clear shader store */ OS_Mkdir(shader_store_name); { /* Remove all old shaders */ @@ -1330,16 +1283,15 @@ void BuildEntryPoint(WaveLaneCtx *lane, void *udata) { OS_Rm(n->s); } + else + { + /* Unexpected file in shader store */ + Assert(0); + } } } - //- Generate GPU file & shader entries - String gpu_out_file = F_GetFull(arena, StringF(arena, "%F_gen_gpu.hlsl", FmtString(cmdline.leaf_layer_name))); - Enum(ShaderEntryKind) { ShaderEntryKind_VS, ShaderEntryKind_PS, ShaderEntryKind_CS, }; - Struct(ShaderEntry) { ShaderEntry *next; ShaderEntryKind kind; String name; }; - ShaderEntry *first_shader_entry = 0; - ShaderEntry *last_shader_entry = 0; - u64 shader_entries_count = 0; + /* Generate GPU file & shader entries */ { StringList gpu_include_lines = ZI; { @@ -1368,12 +1320,12 @@ void BuildEntryPoint(WaveLaneCtx *lane, void *udata) else { String err = StringF(arena, "File '%F' not found", FmtString(full)); - M_PushError(arena, &shared->gpu_comp.errors, arg0_tok, err); + M_PushError(arena, &gpugen.errors, arg0_tok, err); } } else { - M_PushError(arena, &shared->gpu_comp.errors, entry_tok, Lit("Expected file name")); + M_PushError(arena, &gpugen.errors, entry_tok, Lit("Expected file name")); } } break; case M_EntryKind_VertexShader: @@ -1390,18 +1342,18 @@ void BuildEntryPoint(WaveLaneCtx *lane, void *udata) ShaderEntry *e = PushStruct(arena, ShaderEntry); e->kind = shader_kind; e->name = shader_name; - SllQueuePush(first_shader_entry, last_shader_entry, e); - ++shader_entries_count; + SllQueuePush(gpugen.first_shader_entry, gpugen.last_shader_entry, e); + ++gpugen.shader_entries_count; } else { - M_PushError(arena, &shared->gpu_comp.errors, entry_tok, Lit("Expected shader name")); + M_PushError(arena, &gpugen.errors, entry_tok, Lit("Expected shader name")); } } break; } } } - if (shared->gpu_comp.errors.count == 0) + if (gpugen.errors.count == 0) { StringList gpu_out_lines = ZI; PushStringToList(arena, &gpu_out_lines, Lit("// Auto generated file")); @@ -1428,82 +1380,347 @@ void BuildEntryPoint(WaveLaneCtx *lane, void *udata) F_ClearWrite(gpu_out_file, c_out); } } + } - //- Compile shaders - String *compile_cmds = PushStructs(arena, String, shader_entries_count); + ////////////////////////////// + //- Compile C + + Struct(CComp) + { + M_ErrorList errors; + String obj_file; + StringList output; + i32 return_code; + }; + CComp ccomp = ZI; + { + ccomp.obj_file = StringF(arena, "%F_gen_c.obj", FmtString(cmdline.leaf_layer_name)); + if (ccomp.errors.count == 0) { - i32 i = 0; - for (ShaderEntry *e = first_shader_entry; e; e = e->next) + String cmd = StringF(arena, + "cmd /c cl.exe /c %F -Fo:%F %F %F %F %F", + FmtString(c_out_file), + FmtString(ccomp.obj_file), + FmtString(StringFromList(arena, cp.flags_msvc, Lit(" "))), + FmtString(StringFromList(arena, cp.compiler_only_flags_msvc, Lit(" "))), + FmtString(StringFromList(arena, cp.warnings_msvc, Lit(" "))), + FmtString(StringFromList(arena, cp.defs, Lit(" ")))); + OS_CommandResult cmd_result = OS_RunCommand(arena, cmd); + String cmd_output = TrimWhitespace(cmd_result.output); + if (cmd_output.len > 0) { - String target = e->kind == ShaderEntryKind_VS ? Lit("vs_6_6") - : e->kind == ShaderEntryKind_PS ? Lit("ps_6_6") - : e->kind == ShaderEntryKind_CS ? Lit("cs_6_6") - : Lit("vs_6_6"); - String *compile_cmd = &compile_cmds[i]; - *compile_cmd = StringF(arena, - "cmd /c dxc.exe -T %F -E %F -Fo %F/%F %F %F %F", - FmtString(target), - FmtString(e->name), - FmtString(shader_store_name), - FmtString(e->name), - FmtString(gpu_out_file), - FmtString(StringFromList(arena, cp.defs, Lit(" "))), - FmtString(StringFromList(arena, cp.flags_dxc, Lit(" ")))); - ++i; + PushStringToList(arena, &ccomp.output, cmd_output); } + ccomp.return_code = cmd_result.code; } + } - for (ShaderEntry *e = first_shader_entry; e; e = e->next) + ////////////////////////////// + //- Compile shaders + + Struct(GpuComp) + { + StringList output; + }; + GpuComp gpucomp = ZI; + for (ShaderEntry *e = gpugen.first_shader_entry; e; e = e->next) + { + String out_file = StringF(arena, "%F/%F", FmtString(shader_store_name), FmtString(e->name)); + String target = e->kind == ShaderEntryKind_VS ? Lit("vs_6_6") + : e->kind == ShaderEntryKind_PS ? Lit("ps_6_6") + : e->kind == ShaderEntryKind_CS ? Lit("cs_6_6") + : Lit("vs_6_6"); + String compile_cmd = StringF(arena, + "cmd /c dxc.exe -T %F -E %F -Fo %F %F %F %F", + FmtString(target), + FmtString(e->name), + FmtString(out_file), + FmtString(gpu_out_file), + FmtString(StringFromList(arena, cp.defs, Lit(" "))), + FmtString(StringFromList(arena, cp.flags_dxc, Lit(" ")))); + + OS_CommandResult cmd_result = OS_RunCommand(arena, compile_cmd); + + if (cmd_result.code == 0) { - String target = e->kind == ShaderEntryKind_VS ? Lit("vs_6_6") - : e->kind == ShaderEntryKind_PS ? Lit("ps_6_6") - : e->kind == ShaderEntryKind_CS ? Lit("cs_6_6") - : Lit("vs_6_6"); - String compile_cmd = StringF(arena, - "cmd /c dxc.exe -T %F -E %F -Fo %F/%F %F %F %F", - FmtString(target), - FmtString(e->name), - FmtString(shader_store_name), - FmtString(e->name), - FmtString(gpu_out_file), - FmtString(StringFromList(arena, cp.defs, Lit(" "))), - FmtString(StringFromList(arena, cp.flags_dxc, Lit(" ")))); - - OS_CommandResult cmd_result = OS_RunCommand(arena, compile_cmd); - - if (cmd_result.code == 0) + // f64 elapsed = SecondsFromNs(cmd_result.elapsed_ns); + f64 elapsed = 0; + PushStringToList(arena, &gpucomp.output, StringF(arena, "%F:%F %Fs", FmtString(F_GetFileName(gpu_out_file)), FmtString(e->name), FmtFloat(elapsed))); + if (cmd_result.output.len > 0) { - // f64 elapsed = SecondsFromNs(cmd_result.elapsed_ns); - f64 elapsed = 0; - PushStringToList(arena, &shared->gpu_comp.output, StringF(arena, "%F:%F %Fs", FmtString(F_GetFileName(gpu_out_file)), FmtString(e->name), FmtFloat(elapsed))); - if (cmd_result.output.len > 0) + PushStringToList(arena, &gpucomp.output, cmd_result.output); + } + cmd_result.code = cmd_result.code; + } + } + + ////////////////////////////// + //- Gather resource archive info + + Struct(ArcInfoEntry) { ArcInfoEntry *next; String dir_path; String store_name; String out_path; }; + Struct(ArcInfoGen) + { + M_ErrorList errors; + ArcInfoEntry *first_arc_entry; + ArcInfoEntry *last_arc_entry; + u64 arc_entries_count; + }; + ArcInfoGen arcinfogen = ZI; + { + /* Gather archives from embedded dirs */ + for (M_Entry *entry = flattened.first; entry->valid; entry = entry->next) + { + M_EntryKind kind = entry->kind; + M_Token *entry_tok = entry->name_token; + M_Token *arg0_tok = entry->arg_tokens[0]; + M_Token *arg1_tok = entry->arg_tokens[1]; + switch (kind) + { + default: break; + case M_EntryKind_EmbedDir: { - PushStringToList(arena, &shared->gpu_comp.output, cmd_result.output); + if (arg0_tok->valid && arg1_tok->valid) + { + String store_name = arg0_tok->s; + String token_file = arg1_tok->file->name; + String token_parent_dir = F_GetParentDir(token_file); + String arg_dir = arg1_tok->s; + String full = F_GetFullCrossPlatform(arena, StringF(arena, "%F/%F", FmtString(token_parent_dir), FmtString(arg_dir))); + if (F_IsDir(full)) + { + ArcInfoEntry *arc = PushStruct(arena, ArcInfoEntry); + arc->store_name = store_name; + arc->dir_path = full; + arc->out_path = StringF(arena, "%F.arc", FmtString(store_name)); + SllQueuePush(arcinfogen.first_arc_entry, arcinfogen.last_arc_entry, arc); + ++arcinfogen.arc_entries_count; + } + else + { + String err = StringF(arena, "Directory '%F' not found", FmtString(full)); + M_PushError(arena, &arcinfogen.errors, arg1_tok, err); + } + } + else + { + M_PushError(arena, &arcinfogen.errors, entry_tok, Lit("Expected resource store & directory name")); + } + } break; + } + } + /* Gather shader archive */ + { + ArcInfoEntry *arc = PushStruct(arena, ArcInfoEntry); + arc->store_name = shader_store_name; + arc->dir_path = F_GetFullCrossPlatform(arena, shader_store_name); + arc->out_path = StringF(arena, "%F.arc", FmtString(shader_store_name)); + SllQueuePush(arcinfogen.first_arc_entry, arcinfogen.last_arc_entry, arc); + ++arcinfogen.arc_entries_count; + } + } + + ////////////////////////////// + //- Generate resource archives + + for (ArcInfoEntry *entry = arcinfogen.first_arc_entry; entry; entry = entry->next) + { + String dir_path = entry->dir_path; + String store_name = entry->store_name; + String arc_path = entry->out_path; + + Struct(EntryNode) + { + EntryNode *next; + String entry_name; + String file_name; + }; + + EntryNode *first_entry = 0; + EntryNode *last_entry = 0; + u64 entries_count = 0; + + StringList files = ZI; + F_FilesFromDir(arena, &files, dir_path, F_IterFlag_Recurse); + for (StringListNode *file_node = files.first; file_node; file_node = file_node->next) + { + String file_name = file_node->s; + if (F_IsFile(file_name)) + { + String entry_name = file_name; + if (entry_name.len > (dir_path.len + 1)) + { + entry_name.len -= dir_path.len + 1; + entry_name.text += dir_path.len + 1; } - cmd_result.code = cmd_result.code; + entry_name = StringF(arena, "%F/%F", FmtString(store_name), FmtString(entry_name)); + for (u64 i = 0; i < entry_name.len; ++i) + { + if (entry_name.text[i] == '\\') + { + entry_name.text[i] = '/'; + } + } + + EntryNode *en = PushStruct(arena, EntryNode); + en->entry_name = entry_name; + en->file_name = file_name; + SllQueuePush(first_entry, last_entry, en); + ++entries_count; } } - //- Build embedded shader archive - // if (result->code == 0) + String arc_contents = ZI; + { + BB_Buff bb = BB_AcquireBuff(Gibi(2)); + BB_Writer bw = BB_WriterFromBuff(&bb); + + /* Write magic */ + BB_WriteUBits(&bw, ResourceEmbeddedMagic, 64); + + /* Write header */ + BB_WriteUBits(&bw, entries_count, 64); + + /* Reserve entries space */ + u64 entry_size = 8 /* Name start */ + + 8 /* Name end */ + + 8 /* Data start */ + + 8; /* Data end */ + u8 *entries_start = BB_GetWrittenRaw(&bw) + BB_GetNumBytesWritten(&bw); + u64 entries_size = entry_size * entries_count; + String entries_str = STRING(entries_size, entries_start); + BB_WriteSeekBytes(&bw, entries_size); + BB_Buff entries_bb = BB_BuffFromString(entries_str); + BB_Writer entries_bw = BB_WriterFromBuff(&entries_bb); + + /* Write entries */ + for (EntryNode *en = first_entry; en; en = en->next) + { + /* TODO: Copy file data directly into archive file */ + String file_data = F_DataFromFile(arena, en->file_name); + + /* Write name */ + BB_WriteAlignBytes(&bw, 64); + u64 name_start = BB_GetNumBytesWritten(&bw) + 1; + BB_WriteString(&bw, en->entry_name); + u64 name_len = BB_GetNumBytesWritten(&bw) - name_start; + + /* Write data */ + BB_WriteAlignBytes(&bw, 64); + /* FIXME: Why no +1 here? */ + u64 data_start = BB_GetNumBytesWritten(&bw); + BB_WriteBytes(&bw, file_data); + u64 data_len = BB_GetNumBytesWritten(&bw) - data_start; + + /* Write entry */ + BB_WriteUBits(&entries_bw, name_start, 64); + BB_WriteUBits(&entries_bw, name_len, 64); + BB_WriteUBits(&entries_bw, data_start, 64); + BB_WriteUBits(&entries_bw, data_len, 64); + } + + arc_contents.len = BB_GetNumBytesWritten(&bw); + arc_contents.text = BB_GetWrittenRaw(&bw); + } + + /* Write arc file */ + F_ClearWrite(arc_path, arc_contents); + // PushStringToList(arena, output, StringF(arena, "%F (%F mb)", FmtString(F_GetFileName(arc_path)), FmtFloatP((f32)arc_contents.len / 1024 / 1024, 3))); + + // if (IsPlatformWindows) // { - // StepParams arc_params = *params; - // StepResult arc_results = ZI; + // //- Generate rc file + // String rc_out_file = StringF(arena, "%F.rc", FmtString(store_name)); + // { + // RandState rs = ZI; + // StringList rc_out_lines = ZI; + // String arc_file_cp = F_GetFullCrossPlatform(arena, arc_path); + // String line = StringF(arena, "%F_%F RCDATA \"%F\"", FmtString(Lit(Stringize(W32_EmbeddedDataPrefix))), FmtHex(RandU64FromState(&rs)), FmtString(arc_file_cp)); + // PushStringToList(arena, &rc_out_lines, line); + // /* Write to file */ + // String rc_out = StringFromList(arena, rc_out_lines, Lit("\n")); + // F_ClearWrite(rc_out_file, rc_out); + // } - // arc_params.flags = StepParamsFlag_CompileArc; - // arc_params.arc_store = shader_store_name; - // arc_params.arc_dir = shader_store_name; - - // u32 job_count = 0; Fence job_fence = ZI; - // job_count += RunJob(Step, .fence = &job_fence, .sig.params = &arc_params, .sig.results = &arc_results); - // YieldOnFence(&job_fence, job_count); - // InheritStepResults(arena, result, 1, &arc_results); + // //- Compile RC + // String res_out_file = StringF(arena, "%F.res", FmtString(store_name)); + // PushStringToList(arena, &result->obj_files, res_out_file); + // if (errors->count == 0) + // { + // String cmd = StringF(arena, "cmd /c rc.exe -nologo -fo %F %F", FmtString(res_out_file), FmtString(F_GetFull(arena, rc_out_file))); + // OS_CommandResult cmd_result = OS_RunCommand(arena, cmd); + // String cmd_output = TrimWhitespace(cmd_result.output); + // PushStringToList(arena, output, rc_out_file); + // if (cmd_output.len > 0) + // { + // PushStringToList(arena, output, cmd_output); + // } + // result->return_code = cmd_result.code; + // } + // } + // else + // { + // /* TODO: Compile object files using .incbin on non-windows platforms */ + // Panic(Lit("Non-windows embedded format not implemented")); // } } ////////////////////////////// - //- Compile resources + //- Compile resource archives + Struct(ResComp) + { + String obj_file; + StringList output; + i32 return_code; + }; + ResComp *rescomps = PushStructs(arena, ResComp, arcinfogen.arc_entries_count); + + { + if (IsPlatformWindows) + { + i32 rescomp_idx = 0; + for (ArcInfoEntry *entry = arcinfogen.first_arc_entry; entry; entry = entry->next) + { + ResComp *rescomp = &rescomps[rescomp_idx]; + + String arc_path = entry->out_path; + + /* Generate RC file */ + String rc_out_file = StringF(arena, "%F.rc", FmtString(entry->store_name)); + { + RandState rs = ZI; + StringList rc_out_lines = ZI; + String arc_file_cp = F_GetFullCrossPlatform(arena, arc_path); + String line = StringF(arena, "%F_%F RCDATA \"%F\"", FmtString(Lit(Stringize(W32_EmbeddedDataPrefix))), FmtHex(RandU64FromState(&rs)), FmtString(arc_file_cp)); + PushStringToList(arena, &rc_out_lines, line); + /* Write to file */ + String rc_out = StringFromList(arena, rc_out_lines, Lit("\n")); + F_ClearWrite(rc_out_file, rc_out); + } + + /* Compile RC file */ + rescomp->obj_file = StringF(arena, "%F.res", FmtString(entry->store_name)); + { + String cmd = StringF(arena, "cmd /c rc.exe -nologo -fo %F %F", FmtString(rescomp->obj_file), FmtString(F_GetFull(arena, rc_out_file))); + OS_CommandResult cmd_result = OS_RunCommand(arena, cmd); + String cmd_output = TrimWhitespace(cmd_result.output); + PushStringToList(arena, &rescomp->output, rc_out_file); + if (cmd_output.len > 0) + { + PushStringToList(arena, &rescomp->output, cmd_output); + } + rescomp->return_code = cmd_result.code; + } + + ++rescomp_idx; + } + } + else + { + /* TODO: Compile object files using .incbin on non-windows platforms */ + Panic(Lit("Non-windows embedded format not implemented")); + } + } ////////////////////////////// //- Link @@ -1521,15 +1738,22 @@ void BuildEntryPoint(WaveLaneCtx *lane, void *udata) if (ret == 0) { i64 start_ns = TimeNs(); - String program_obj_files_str = StringFromList(arena, shared->c_comp.obj_files, Lit(" ")); - String shader_obj_files_str = StringFromList(arena, shared->gpu_comp.obj_files, Lit(" ")); - String resource_obj_files_str = StringFromList(arena, shared->res_comp.obj_files, Lit(" ")); + + String obj_files_str = ZI; + { + StringList obj_files = ZI; + PushStringToList(arena, &obj_files, ccomp.obj_file); + for (u64 rescomp_idx = 0; rescomp_idx < arcinfogen.arc_entries_count; ++rescomp_idx) + { + ResComp *rescomp = &rescomps[rescomp_idx]; + PushStringToList(arena, &obj_files, rescomp->obj_file); + } + obj_files_str = StringFromList(arena, obj_files, Lit(" ")); + } String cmd = StringF(arena, - "cmd /c link.exe %F %F %F /OUT:%F %F %F", - FmtString(program_obj_files_str), - FmtString(shader_obj_files_str), - FmtString(resource_obj_files_str), + "cmd /c link.exe %F /OUT:%F %F %F", + FmtString(obj_files_str), FmtString(exe_file), FmtString(StringFromList(arena, cp.flags_msvc, Lit(" "))), FmtString(StringFromList(arena, cp.linker_only_flags_msvc, Lit(" ")))); @@ -1549,28 +1773,6 @@ void BuildEntryPoint(WaveLaneCtx *lane, void *udata) } } - - - - - - - - - - - - - - - - - - - - - - ////////////////////////////// //- Compile & link