diff --git a/src/gpu/gpu.h b/src/gpu/gpu.h index 7ee39c7e..8c53b85f 100644 --- a/src/gpu/gpu.h +++ b/src/gpu/gpu.h @@ -287,7 +287,7 @@ Struct(GPU_ResourceDesc) { GPU_Format format; Vec3I32 size; - i32 mip_levels; + i32 mip_levels; /* Defaults to 1 (unless GPU_ResourceFlag_MaxMipLevels is set) */ } texture; struct { diff --git a/src/meta/meta.c b/src/meta/meta.c index 84af924d..e7037697 100644 --- a/src/meta/meta.c +++ b/src/meta/meta.c @@ -990,95 +990,98 @@ JobDef(Build, _, __) ret = errors.count > 0; //////////////////////////////// - //~ Compile - - StepParams params_array[3] = ZI; - StepResult results_array[3] = ZI; - - StepParams *program_params = ¶ms_array[0]; - StepResult *program_result = &results_array[0]; - program_params->flags |= StepParamsFlag_CompileProgram; - program_params->compiler_params = cp; - program_params->flattened = flattened; - - StepParams *shader_params = ¶ms_array[1]; - StepResult *shader_result = &results_array[1]; - shader_params->flags |= StepParamsFlag_CompileShaders; - shader_params->compiler_params = cp; - shader_params->flattened = flattened; - - StepParams *resource_params = ¶ms_array[2]; - StepResult *resource_result = &results_array[2]; - resource_params->flags |= StepParamsFlag_CompileEmbeddedDirs; - resource_params->compiler_params = cp; - resource_params->flattened = flattened; - - u32 job_count = 0; Fence job_fence = ZI; - job_count += RunJob(Step, .count = countof(params_array), .fence = &job_fence, .sig.params = params_array, .sig.results = results_array); - YieldOnFence(&job_fence, job_count); - - //////////////////////////////// - //~ Process compile step results - - /* Copy meta errors */ - for (M_Error *e = program_result->meta_errors.first; e; e = e->next) M_PushError(arena, &errors, e->token, e->msg); - for (M_Error *e = shader_result->meta_errors.first; e; e = e->next) M_PushError(arena, &errors, e->token, e->msg); - for (M_Error *e = resource_result->meta_errors.first; e; e = e->next) M_PushError(arena, &errors, e->token, e->msg); - - ret = (ret != 0) ? ret : program_result->return_code; - ret = (ret != 0) ? ret : shader_result->return_code; - ret = (ret != 0) ? ret : resource_result->return_code; - ret = (ret != 0) ? ret : errors.count > 0; + //~ Compile & link + if (errors.count == 0) { - String program_output = StringFromList(arena, program_result->output_lines, Lit("\n")); - String shader_output = StringFromList(arena, shader_result->output_lines, Lit("\n")); - String resource_output = StringFromList(arena, resource_result->output_lines, Lit("\n")); + //- Compile + StepParams params_array[3] = ZI; + StepResult results_array[3] = ZI; - EchoLine(StringF(arena, ">>>>> Built C in %Fs", FmtFloat(SecondsFromNs(program_result->elapsed_ns)))); - if (program_output.len > 0) EchoLine(program_output); + StepParams *program_params = ¶ms_array[0]; + StepResult *program_result = &results_array[0]; + program_params->flags |= StepParamsFlag_CompileProgram; + program_params->compiler_params = cp; + program_params->flattened = flattened; - EchoLine(StringF(arena, ">>>>> Built shaders in %Fs", FmtFloat(SecondsFromNs(shader_result->elapsed_ns)))); - if (shader_output.len > 0) EchoLine(shader_output); + StepParams *shader_params = ¶ms_array[1]; + StepResult *shader_result = &results_array[1]; + shader_params->flags |= StepParamsFlag_CompileShaders; + shader_params->compiler_params = cp; + shader_params->flattened = flattened; - EchoLine(StringF(arena, ">>>>> Built resources in %Fs", FmtFloat(SecondsFromNs(resource_result->elapsed_ns)))); - if (resource_output.len > 0) EchoLine(resource_output); - } + StepParams *resource_params = ¶ms_array[2]; + StepResult *resource_result = &results_array[2]; + resource_params->flags |= StepParamsFlag_CompileEmbeddedDirs; + resource_params->compiler_params = cp; + resource_params->flattened = flattened; - //////////////////////////////// - //~ Link + u32 job_count = 0; Fence job_fence = ZI; + job_count += RunJob(Step, .count = countof(params_array), .fence = &job_fence, .sig.params = params_array, .sig.results = results_array); + YieldOnFence(&job_fence, job_count); - String exe_file = Lit("pp.exe"); - i64 link_elapsed_ns = 0; - if (ret == 0) - { - i64 start_ns = TimeNs(); - String program_obj_files_str = StringFromList(arena, program_result->obj_files, Lit(" ")); - String shader_obj_files_str = StringFromList(arena, shader_result->obj_files, Lit(" ")); - String resource_obj_files_str = StringFromList(arena, resource_result->obj_files, Lit(" ")); + //- Process compile step results + + /* Copy meta errors */ + for (M_Error *e = program_result->meta_errors.first; e; e = e->next) M_PushError(arena, &errors, e->token, e->msg); + for (M_Error *e = shader_result->meta_errors.first; e; e = e->next) M_PushError(arena, &errors, e->token, e->msg); + for (M_Error *e = resource_result->meta_errors.first; e; e = e->next) M_PushError(arena, &errors, e->token, e->msg); + + ret = (ret != 0) ? ret : program_result->return_code; + ret = (ret != 0) ? ret : shader_result->return_code; + ret = (ret != 0) ? ret : resource_result->return_code; + ret = (ret != 0) ? ret : errors.count > 0; - 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), - FmtString(exe_file), - FmtString(StringFromList(arena, cp.flags_msvc, Lit(" "))), - FmtString(StringFromList(arena, cp.linker_only_flags_msvc, Lit(" ")))); - OS_CommandResult result = OS_RunCommand(arena, cmd); - String output = TrimWhitespace(result.output); - if (output.len > 0) { - EchoLine(output); + String program_output = StringFromList(arena, program_result->output_lines, Lit("\n")); + String shader_output = StringFromList(arena, shader_result->output_lines, Lit("\n")); + String resource_output = StringFromList(arena, resource_result->output_lines, Lit("\n")); + + EchoLine(StringF(arena, ">>>>> Built C in %Fs", FmtFloat(SecondsFromNs(program_result->elapsed_ns)))); + if (program_output.len > 0) EchoLine(program_output); + + EchoLine(StringF(arena, ">>>>> Built shaders in %Fs", FmtFloat(SecondsFromNs(shader_result->elapsed_ns)))); + if (shader_output.len > 0) EchoLine(shader_output); + + EchoLine(StringF(arena, ">>>>> Built resources in %Fs", FmtFloat(SecondsFromNs(resource_result->elapsed_ns)))); + if (resource_output.len > 0) EchoLine(resource_output); + } + + //- Link + + String exe_file = Lit("pp.exe"); + i64 link_elapsed_ns = 0; + if (ret == 0) + { + i64 start_ns = TimeNs(); + String program_obj_files_str = StringFromList(arena, program_result->obj_files, Lit(" ")); + String shader_obj_files_str = StringFromList(arena, shader_result->obj_files, Lit(" ")); + String resource_obj_files_str = StringFromList(arena, resource_result->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), + FmtString(exe_file), + FmtString(StringFromList(arena, cp.flags_msvc, Lit(" "))), + FmtString(StringFromList(arena, cp.linker_only_flags_msvc, Lit(" ")))); + OS_CommandResult result = OS_RunCommand(arena, cmd); + String output = TrimWhitespace(result.output); + if (output.len > 0) + { + EchoLine(output); + } + ret = result.code; + link_elapsed_ns = TimeNs() - start_ns; + } + + if (ret == 0) + { + EchoLine(StringF(arena, ">>>>> Linked in %Fs", FmtFloat(SecondsFromNs(link_elapsed_ns)))); } - ret = result.code; - link_elapsed_ns = TimeNs() - start_ns; } - if (ret == 0) - { - EchoLine(StringF(arena, ">>>>> Linked in %Fs", FmtFloat(SecondsFromNs(link_elapsed_ns)))); - } //////////////////////////////// //~ Echo errors diff --git a/src/meta/meta_lay.c b/src/meta/meta_lay.c index d0eb5763..c6a7a98f 100644 --- a/src/meta/meta_lay.c +++ b/src/meta/meta_lay.c @@ -286,6 +286,11 @@ M_LayerList M_LayersFromTokenFiles(Arena *arena, M_TokenFileList lexed) { entry->kind = kind_plus_1 - 1; } + else + { + String err = StringF(arena, "Unexpected token \"%F\"", FmtString(entry_token->s)); + M_PushError(arena, &layer->errors, entry->name_token, err); + } } } token = token->next; diff --git a/src/pp/pp.c b/src/pp/pp.c index 96e05d65..4fcf7429 100644 --- a/src/pp/pp.c +++ b/src/pp/pp.c @@ -495,6 +495,11 @@ void UpdateUser(P_Window *window) g->real_time_ns += g->real_dt_ns; g->screen_size = P_GetWindowSize(window); + //- Begin UI + UI_BeginBuild(); + UI_Box *pp_root_box = UI_BuildBox(UI_Flag_DrawImage, UI_NilKey); + UI_PushParent(pp_root_box); + //- Pull latest local sim snapshot { @@ -517,7 +522,7 @@ void UpdateUser(P_Window *window) { __profn("Blend snapshots"); - /* How along are we between sim ticks (0 = start of tick, 1 = end of tick) */ + /* Determine how far along are we between sim ticks (0 = start of tick, 1 = end of tick) */ f64 tick_progress = 0; i64 next_tick_expected_ns = g->last_local_to_user_snapshot_published_at_ns + g->average_local_to_user_snapshot_publish_dt_ns; if (next_tick_expected_ns > g->last_local_to_user_snapshot_published_at_ns) @@ -2630,12 +2635,12 @@ void UpdateUser(P_Window *window) { DelayReleaseGpuResources_Sig *sig = PushStruct(job->arena, DelayReleaseGpuResources_Sig); job->count = countof(release_resources); + job->sig = sig; sig->begin_fence = render_fence; sig->begin_fence_target = g->gpu_render_fence_target; sig->resources = PushStructsNoZero(job->arena, GPU_Resource *, job->count); sig->flags = GPU_ReleaseFlag_Reuse; CopyBytes(sig->resources, release_resources, sizeof(release_resources)); - job->sig = sig; } CloseJob(job); } @@ -2645,12 +2650,21 @@ void UpdateUser(P_Window *window) ResetArena(g->ui_shape_indices_arena); ResetArena(g->grids_arena); } - - Vec2 backbuffer_dst_f = MulXformV2(g->ui_to_screen_xf, VEC2(0, 0)); - Vec2I32 backbuffer_dst = VEC2I32(RoundF32ToI32(backbuffer_dst_f.x), RoundF32ToI32(backbuffer_dst_f.y)); - g->gpu_render_fence_target = GPU_PresentSwapchain(g->swapchain, g->ui_target, g->screen_size, backbuffer_dst, VSYNC); } + /* Render UI */ + UI_PopParent(); + UI_SetDisplayImage(pp_root_box, g->ui_target); + GPU_Resource *ui_render = UI_EndBuild(); + + //////////////////////////////// + //~ Present + + Vec2 backbuffer_dst_f = MulXformV2(g->ui_to_screen_xf, VEC2(0, 0)); + Vec2I32 backbuffer_dst = VEC2I32(RoundF32ToI32(backbuffer_dst_f.x), RoundF32ToI32(backbuffer_dst_f.y)); + g->gpu_render_fence_target = GPU_PresentSwapchain(g->swapchain, ui_render, g->screen_size, backbuffer_dst, VSYNC); + // g->gpu_render_fence_target = GPU_PresentSwapchain(g->swapchain, g->ui_target, g->screen_size, backbuffer_dst, VSYNC); + EndScratch(scratch); } diff --git a/src/pp/pp_draw.gpu b/src/pp/pp_draw.gpu index fa6841e5..576d2282 100644 --- a/src/pp/pp_draw.gpu +++ b/src/pp/pp_draw.gpu @@ -42,14 +42,14 @@ MaterialPS_Input VSDef(MaterialVS, Semantic(u32, sv_instanceid), Semantic(u32, s Vec2 world_pos = mul(instance.xf, Vec3(vert, 1)).xy; - MaterialPS_Input output; - output.sv_position = mul(sig.projection, Vec4(world_pos, 0, 1)); - output.tex = instance.tex; - output.grid_id = instance.grid_id; - output.uv = instance.uv0 + ((vert + 0.5) * (instance.uv1 - instance.uv0)); - output.tint_lin = LinearFromSrgbU32(instance.tint_srgb); - output.emittance_lin = LinearFromSrgbVec4(Vec4(instance.light_emittance_srgb, instance.is_light)); - return output; + MaterialPS_Input result; + result.sv_position = mul(sig.projection, Vec4(world_pos, 0, 1)); + result.tex = instance.tex; + result.grid_id = instance.grid_id; + result.uv = instance.uv0 + ((vert + 0.5) * (instance.uv1 - instance.uv0)); + result.tint_lin = LinearFromSrgbU32(instance.tint_srgb); + result.emittance_lin = LinearFromSrgbVec4(Vec4(instance.light_emittance_srgb, instance.is_light)); + return result; } //- Pixel shader @@ -58,7 +58,7 @@ MaterialPS_Output PSDef(MaterialPS, MaterialPS_Input input) { ConstantBuffer sig = mat_sig; - MaterialPS_Output output; + MaterialPS_Output result; Vec4 albedo = input.tint_lin; /* Texture */ @@ -116,10 +116,10 @@ MaterialPS_Output PSDef(MaterialPS, MaterialPS_Input input) Vec4 emittance = input.emittance_lin * albedo.a; - output.sv_target0 = albedo; - output.sv_target1 = emittance; + result.sv_target0 = albedo; + result.sv_target1 = emittance; - return output; + return result; } //////////////////////////////// @@ -330,10 +330,10 @@ UiBlitPS_Input VSDef(UiBlitVS, Semantic(u32, sv_vertexid)) }; Vec2 vert = unit_quad_verts[sv_vertexid]; - UiBlitPS_Input output; - output.sv_position = mul(sig.projection, Vec4(vert, 0, 1)); - output.uv = vert + 0.5; - return output; + UiBlitPS_Input result; + result.sv_position = mul(sig.projection, Vec4(vert, 0, 1)); + result.uv = vert + 0.5; + return result; } //- Pixel shader @@ -343,7 +343,7 @@ UiBlitPS_Output PSDef(UiBlitPS, UiBlitPS_Input input) ConstantBuffer sig = ui_blit_sig; SamplerState sampler = UniformSamplerFromRid(sig.sampler); - UiBlitPS_Output output; + UiBlitPS_Output result; Texture2D tex = UniformResourceFromRid(sig.src); Vec4 color = tex.Sample(sampler, input.uv); @@ -361,8 +361,8 @@ UiBlitPS_Output PSDef(UiBlitPS, UiBlitPS_Input input) color = pow(abs(color), 1/sig.gamma); } - output.sv_target = color; - return output; + result.sv_target = color; + return result; } //////////////////////////////// @@ -398,12 +398,12 @@ UiRectPS_Input VSDef(UiRectVS, Semantic(u32, sv_instanceid), Semantic(u32, sv_ve Vec2 vert = unit_quad_verts[sv_vertexid]; Vec2 world_pos = mul(instance.xf, Vec3(vert, 1)).xy; - UiRectPS_Input output; - output.sv_position = mul(sig.projection, Vec4(world_pos, 0, 1)); - output.tex = instance.tex; - output.uv = instance.uv0 + ((vert + 0.5) * (instance.uv1 - instance.uv0)); - output.tint_srgb = Vec4NormFromU32(instance.tint_srgb); - return output; + UiRectPS_Input result; + result.sv_position = mul(sig.projection, Vec4(world_pos, 0, 1)); + result.tex = instance.tex; + result.uv = instance.uv0 + ((vert + 0.5) * (instance.uv1 - instance.uv0)); + result.tint_srgb = Vec4NormFromU32(instance.tint_srgb); + return result; } //- Pixel shader @@ -411,7 +411,7 @@ UiRectPS_Input VSDef(UiRectVS, Semantic(u32, sv_instanceid), Semantic(u32, sv_ve UiRectPS_Output PSDef(UiRectPS, UiRectPS_Input input) { ConstantBuffer sig = ui_rect_sig; - UiRectPS_Output output; + UiRectPS_Output result; Vec4 color = input.tint_srgb; /* Texture */ @@ -422,8 +422,8 @@ UiRectPS_Output PSDef(UiRectPS, UiRectPS_Input input) color *= tex.Sample(sampler, input.uv); } - output.sv_target0 = color; - return output; + result.sv_target0 = color; + return result; } //////////////////////////////// @@ -447,17 +447,17 @@ UiShapePS_Input VSDef(UiShapeVS, Semantic(u32, sv_vertexid)) ConstantBuffer sig = ui_shape_sig; StructuredBuffer verts = UniformResourceFromRid(sig.verts); UiShapeVert vert = verts[sv_vertexid]; - UiShapePS_Input output; - output.sv_position = mul(sig.projection, Vec4(vert.pos.xy, 0, 1)); - output.color_srgb = Vec4NormFromU32(vert.color_srgb); - return output; + UiShapePS_Input result; + result.sv_position = mul(sig.projection, Vec4(vert.pos.xy, 0, 1)); + result.color_srgb = Vec4NormFromU32(vert.color_srgb); + return result; } //- Pixel shader UiShapePS_Output PSDef(UiShapePS, UiShapePS_Input input) { - UiShapePS_Output output; - output.sv_target = input.color_srgb; - return output; + UiShapePS_Output result; + result.sv_target = input.color_srgb; + return result; } diff --git a/src/ui/ui.c b/src/ui/ui.c index 7ae4504c..2e810bcb 100644 --- a/src/ui/ui.c +++ b/src/ui/ui.c @@ -8,14 +8,11 @@ UI_FiberState *UI_GetFiberState(void) UI_FiberState *f = UI_shared_state.fiber_states[FiberId()]; if (!f) { - { - Arena *perm = PermArena(); - PushAlign(perm, CachelineSize); - f = PushStruct(perm, UI_FiberState); - UI_shared_state.fiber_states[FiberId()] = f; - PushAlign(perm, CachelineSize); - } - f->build_arena = AcquireArena(Gibi(64)); + Arena *perm = PermArena(); + PushAlign(perm, CachelineSize); + f = PushStruct(perm, UI_FiberState); + UI_shared_state.fiber_states[FiberId()] = f; + PushAlign(perm, CachelineSize); } return f; } @@ -23,26 +20,84 @@ UI_FiberState *UI_GetFiberState(void) //////////////////////////////// //~ Key helpers -UI_Key UI_KeyFromString(String str) +UI_Key UI_KeyFromString(u64 seed, String str) { - UI_Key key = ZI; - key.hash = HashFnv64(Fnv64Basis, str); - return key; + /* TOIMPL */ + if (seed == 0) + { + UI_FiberState *f = UI_GetFiberState(); + seed = RandU64FromSeeds(f->top_parent->box->key.hash, f->top_tag->hash); + } + UI_Key result = ZI; + result.hash = HashFnv64(seed, str); + return result; } //////////////////////////////// //~ Stack helpers +//- Tag + +void UI_PushTagFromHash(u64 hash) +{ + UI_FiberState *f = UI_GetFiberState(); + if (f->top_tag) + { + hash = RandU64FromSeeds(hash, f->top_tag->hash); + } + UI_Tag *tag = PushStruct(f->build_arena, UI_Tag); + StackPush(f->top_tag, tag); + tag->hash = hash; +} + +void UI_PushTagFromString(String str) +{ + UI_FiberState *f = UI_GetFiberState(); + u64 hash = Fnv64Basis; + if (f->top_tag) + { + hash = f->top_tag->hash; + } + hash = HashFnv64(hash, str); + UI_Tag *tag = PushStruct(f->build_arena, UI_Tag); + StackPush(f->top_tag, tag); + tag->hash = hash; +} + +void UI_PushTagF_(char *fmt_cstr, ...) +{ + TempArena scratch = BeginScratchNoConflict(); + String str = ZI; + { + va_list va; + va_start(va, fmt_cstr); + str = FormatStringV(scratch.arena, StringFromCstrNoLimit(fmt_cstr), va); + va_end(va); + } + UI_PushTagFromString(str); + EndScratch(scratch); +} + +void UI_PopTag(void) +{ + UI_FiberState *f = UI_GetFiberState(); + StackPop(f->top_tag); +} + +//- Parent + void UI_PushParent(UI_Box *box) { UI_FiberState *f = UI_GetFiberState(); + UI_Parent *parent = PushStruct(f->build_arena, UI_Parent); + parent->box = box; + StackPush(f->top_parent, parent); } -UI_Box *UI_PopParent(void) +void UI_PopParent(void) { UI_FiberState *f = UI_GetFiberState(); - UI_Box *box = 0; - return box; + StackPop(f->top_parent); } //////////////////////////////// @@ -50,39 +105,142 @@ UI_Box *UI_PopParent(void) UI_Box *UI_BuildBox(UI_Flag flags, UI_Key key) { - UI_Box *box = 0; + UI_FiberState *f = UI_GetFiberState(); + UI_BoxBin *bin = &f->box_bins[key.hash % UI_NumBoxLookupBins]; + UI_BoxBin *back_bin = &f->back_box_bins[key.hash % UI_NumBoxLookupBins]; + + UI_Box *box = PushStruct(f->build_arena, UI_Box); + if (key.hash != 0) + { + DllPushBackNP(bin->first, bin->last, box, next_in_bin, prev_in_bin); + } + + /* Find previous build's box from hash */ + UI_Box *back_box = 0; + if (key.hash != 0) + { + for (UI_Box *tmp = back_bin->first; tmp; tmp = tmp->next_in_bin) + { + if (tmp->key.hash == key.hash) + { + back_box = tmp; + break; + } + } + } + + if (back_box) + { + *box = *back_box; + } + + box->key = key; + box->flags = flags; + box->parent = f->top_parent->box; + DllPushBack(f->top_parent->box->first, f->top_parent->box->last, box); + return box; } //////////////////////////////// //~ Text -String UI_DisplayTextFromString(String str) -{ - /* Cap string at non-display pattern (e.g. "Hello##hiddentext" becomes "Hello") */ - u64 new_len = str.len; - if (str.len > 0) - { - b32 escaped = 0; - for (u64 i = 0; i < str.len - 1 && new_len == str.len; ++i) - { - u8 c = str.text[i]; - if (c == '\\') - { - escaped = !escaped; - } - else if (!escaped && c == '#' && str.text[i + 1] == '#') - { - new_len = i; - } - } - } - return STRING(new_len, str.text); -} - void UI_SetDisplayText(UI_Box *box, String str) { UI_FiberState *f = UI_GetFiberState(); - String text = PushString(f->build_arena, UI_DisplayTextFromString(str)); + String text = PushString(f->build_arena, str); box->display_text = text; } + +//////////////////////////////// +//~ Image + +void UI_SetDisplayImage(UI_Box *box, GPU_Resource *img) +{ + box->display_image = img; +} + +//////////////////////////////// +//~ Begin build + +void UI_BeginBuild(void) +{ + UI_FiberState *f = UI_GetFiberState(); + + /* Swap front & back build states */ + { + Arena *swp = f->build_arena; + f->build_arena = f->back_build_arena; + f->back_build_arena = swp; + } + f->back_box_bins = f->box_bins; + f->back_root_box = f->root_box; + + /* Reset front build state */ + if (!f->build_arena) + { + f->build_arena = AcquireArena(Gibi(64)); + } + ResetArena(f->build_arena); + + /* Init bins */ + f->box_bins = PushStructs(f->build_arena, UI_BoxBin, UI_NumBoxLookupBins); + + /* Init root box */ + f->root_box = PushStruct(f->build_arena, UI_Box); + f->root_box->key = UI_RootKey; + UI_BoxBin *bin = &f->box_bins[f->root_box->key.hash % UI_NumBoxLookupBins]; + DllPushBackNP(bin->first, bin->last, f->root_box, next_in_bin, prev_in_bin); + + /* Init stacks */ + UI_PushTagF("root"); + UI_PushParent(f->root_box); + + if (!f->back_build_arena) + { + /* Back buffer not initialized, swap again */ + UI_BeginBuild(); + } +} + +//////////////////////////////// +//~ End build + +GPU_Resource *UI_EndBuild(void) +{ + UI_FiberState *f = UI_GetFiberState(); + + /* TODO: Ensure root is parent */ + + GPU_QueueKind render_queue = GPU_QueueKind_Direct; + Fence *render_fence = GPU_FenceFromQueue(render_queue); + + /* TODO: Real size */ + Vec2I32 root_size = VEC2I32(500, 500); + + /* Acquire render target */ + if (f->render_target && !EqVec2I32(root_size, GPU_GetTextureSize2D(f->render_target))) + { + YieldOnFence(render_fence, f->render_fence_target); + GPU_ReleaseResource(f->render_target, GPU_ReleaseFlag_None); + f->render_target = 0; + } + if (!f->render_target) + { + GPU_ResourceDesc desc = ZI; + desc.kind = GPU_ResourceKind_Texture2D; + desc.flags = GPU_ResourceFlag_Renderable; + desc.texture.format = GPU_Format_R8G8B8A8_Unorm; + desc.texture.size = VEC3I32(root_size.x, root_size.y, 1); + f->render_target = GPU_AcquireResource(desc); + } + + /* Build command list */ + GPU_CommandList *cl = GPU_BeginCommandList(render_queue); + { + + } + f->render_fence_target = GPU_EndCommandList(cl); + + return f->render_target; +} diff --git a/src/ui/ui.h b/src/ui/ui.h index 0a74bfc1..b39acfc8 100644 --- a/src/ui/ui.h +++ b/src/ui/ui.h @@ -2,6 +2,7 @@ //~ Key types #define UI_NilKey ((UI_Key) { 0 }) +#define UI_RootKey ((UI_Key) { 0xa3deb3749ef35a7aUll }) Struct(UI_Key) { @@ -15,20 +16,63 @@ Enum(UI_Flag) { UI_Flag_None = 0, UI_Flag_DrawText = (1 << 0), + UI_Flag_DrawImage = (1 << 1), }; Struct(UI_Box) { + UI_Box *next_in_bin; + UI_Box *prev_in_bin; + + UI_Box *parent; + UI_Box *first; + UI_Box *last; + UI_Box *next; + UI_Box *prev; + + UI_Key key; UI_Flag flags; + String display_text; + GPU_Resource *display_image; }; +Struct(UI_BoxBin) +{ + UI_Box *first; + UI_Box *last; +}; + +//////////////////////////////// +//~ Stack types + +Struct(UI_Tag) { UI_Tag *next; u64 hash; }; +Struct(UI_Parent) { UI_Parent *next; UI_Box *box; }; + //////////////////////////////// //~ State types +#define UI_NumBoxLookupBins 16384 + Struct(UI_FiberState) { + //- Build state Arena *build_arena; + Arena *back_build_arena; + + UI_BoxBin *box_bins; + UI_BoxBin *back_box_bins; + + UI_Box *root_box; + UI_Box *back_root_box; + + //- Stack state + UI_Tag *top_tag; + UI_Parent *top_parent; + + //- Render state + GPU_Resource *render_target; + i64 render_fence_target; }; Struct(UI_SharedState) @@ -44,25 +88,44 @@ UI_FiberState *UI_GetFiberState(void); //////////////////////////////// //~ Key helpers -UI_Key UI_KeyFromString(String text); +UI_Key UI_KeyFromString(u64 seed, String str); //////////////////////////////// //~ Stack helpers +//- Tag +void UI_PushTagFromHash(u64 hash); +void UI_PushTagFromString(String str); +#define UI_PushTagF(fmt_cstr, ...) UI_PushTagF_(fmt_cstr, __VA_ARGS__, FmtEnd); +void UI_PushTagF_(char *fmt_cstr, ...); +void UI_PopTag(void); + +//- Parent void UI_PushParent(UI_Box *box); -UI_Box *UI_PopParent(void); +void UI_PopParent(void); //////////////////////////////// //~ Box UI_Box *UI_BuildBox(UI_Flag flags, UI_Key key); -//////////////////////////////// -//~ Text - -String UI_DisplayTextFromString(String str); void UI_SetDisplayText(UI_Box *box, String str); +//////////////////////////////// +//~ Image + +void UI_SetDisplayImage(UI_Box *box, GPU_Resource *img); + +//////////////////////////////// +//~ Begin build + +void UI_BeginBuild(void); + +//////////////////////////////// +//~ End build + +GPU_Resource *UI_EndBuild(void); + diff --git a/src/ui/ui.lay b/src/ui/ui.lay index 5743761a..b14a03c5 100644 --- a/src/ui/ui.lay +++ b/src/ui/ui.lay @@ -6,10 +6,14 @@ //- Api @IncludeC ui.h @IncludeC ui_widgets.h +@IncludeC ui_draw.h +@IncludeGpu ui_draw.h //- Impl @IncludeC ui.c @IncludeC ui_widgets.c +@IncludeGpu ui_draw.gpu -//- Startup -@startup UI_Startup +//- Shaders +@VertexShader UI_RectVS +@PixelShader UI_RectPS diff --git a/src/ui/ui_draw.gpu b/src/ui/ui_draw.gpu new file mode 100644 index 00000000..178583cd --- /dev/null +++ b/src/ui/ui_draw.gpu @@ -0,0 +1,49 @@ +ConstantBuffer UI_rect_sig : register (b0); + +//////////////////////////////// +//~ Rect + +Struct(UI_RectPS_Input) +{ + Semantic(Vec4, sv_position); +}; + +Struct(UI_RectPS_Output) +{ + Semantic(Vec4, sv_target0); +}; + +//- Vertex shader + +UI_RectPS_Input VSDef(UI_RectVS, Semantic(u32, sv_instanceid), Semantic(u32, sv_vertexid)) +{ + ConstantBuffer sig = UI_rect_sig; + static const Vec2 unit_quad_verts[4] = { + Vec2(-0.5f, -0.5f), + Vec2(0.5f, -0.5f), + Vec2(0.5f, 0.5f), + Vec2(-0.5f, 0.5f) + }; + + StructuredBuffer instances = UniformResourceFromRid(sig.instances); + UI_RectInstance instance = instances[sv_instanceid]; + Vec2 vert = unit_quad_verts[sv_vertexid]; + // Vec2 world_pos = mul(instance.xf, Vec3(vert, 1)).xy; + Vec2 world_pos = 0; + + UI_RectPS_Input result; + result.sv_position = mul(sig.projection, Vec4(world_pos, 0, 1)); + return result; +} + +//- Pixel shader + +UI_RectPS_Output PSDef(UI_RectPS, UI_RectPS_Input input) +{ + ConstantBuffer sig = UI_rect_sig; + f32 color = 0; + + UI_RectPS_Output result; + result.sv_target0 = color; + return result; +} diff --git a/src/ui/ui_draw.h b/src/ui/ui_draw.h new file mode 100644 index 00000000..ab70bce6 --- /dev/null +++ b/src/ui/ui_draw.h @@ -0,0 +1,23 @@ +//////////////////////////////// +//~ Rect types + +Struct(UI_RectSig) +{ + /* ----------------------------------------------------- */ + Mat4x4 projection; /* 16 consts */ + /* ----------------------------------------------------- */ + StructuredBufferRid instances; /* 01 consts */ + u32 _pad0; /* 01 consts (padding) */ + u32 _pad1; /* 01 consts (padding) */ + u32 _pad2; /* 01 consts (padding) */ + /* ----------------------------------------------------- */ +}; +AssertRootConst(UI_RectSig, 20); + +Struct(UI_RectInstance) +{ + i32 _; +}; +#define UI_DefaultRectInstance (UI_RectInstance) { \ + 0 \ +} diff --git a/src/ui/ui_widgets.c b/src/ui/ui_widgets.c index b4cbfa99..432ffd4f 100644 --- a/src/ui/ui_widgets.c +++ b/src/ui/ui_widgets.c @@ -3,7 +3,7 @@ UI_Box *UI_BuildLabel(String text) { - UI_Key key = UI_KeyFromString(text); + UI_Key key = UI_KeyFromString(0, text); UI_Box *box = UI_BuildBox(UI_Flag_DrawText, key); UI_SetDisplayText(box, text); return box; @@ -11,13 +11,15 @@ UI_Box *UI_BuildLabel(String text) UI_Box *UI_BuildLabelF_(char *fmt_cstr, ...) { - UI_FiberState *f = UI_GetFiberState(); TempArena scratch = BeginScratchNoConflict(); - va_list args; - va_start(args, fmt_cstr); - String text = FormatStringV(scratch.arena, StringFromCstrNoLimit(fmt_cstr), args); - UI_Box *box = UI_BuildLabel(text); - va_end(args); + String str = ZI; + { + va_list va; + va_start(va, fmt_cstr); + str = FormatStringV(scratch.arena, StringFromCstrNoLimit(fmt_cstr), va); + va_end(va); + } + UI_Box *box = UI_BuildLabel(str); EndScratch(scratch); return box; } diff --git a/src/ui/ui_widgets.h b/src/ui/ui_widgets.h index 2c38155b..b6f2e75d 100644 --- a/src/ui/ui_widgets.h +++ b/src/ui/ui_widgets.h @@ -2,8 +2,8 @@ //~ Label widget UI_Box *UI_BuildLabel(String text); -UI_Box *UI_BuildLabelF_(char *fmt_cstr, ...); #define UI_BuildLabelF(fmt_cstr, ...) UI_BuildLabelF_(fmt_cstr, __VA_ARGS__, FmtEnd) +UI_Box *UI_BuildLabelF_(char *fmt_cstr, ...); //////////////////////////////// //~ Separator widget