ui layer testing

This commit is contained in:
jacob 2025-10-19 15:23:49 -05:00
parent 2fdf891d49
commit b74927602c
12 changed files with 496 additions and 175 deletions

View File

@ -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
{

View File

@ -990,95 +990,98 @@ JobDef(Build, _, __)
ret = errors.count > 0;
////////////////////////////////
//~ Compile
StepParams params_array[3] = ZI;
StepResult results_array[3] = ZI;
StepParams *program_params = &params_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 = &params_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 = &params_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 = &params_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 = &params_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 = &params_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

View File

@ -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;

View File

@ -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);
}

View File

@ -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<MaterialSig> 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<UiBlitSig> sig = ui_blit_sig;
SamplerState sampler = UniformSamplerFromRid(sig.sampler);
UiBlitPS_Output output;
UiBlitPS_Output result;
Texture2D<Vec4> 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<UiRectSig> 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<UiShapeSig> sig = ui_shape_sig;
StructuredBuffer<UiShapeVert> 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;
}

View File

@ -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;
}

View File

@ -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);

View File

@ -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

49
src/ui/ui_draw.gpu Normal file
View File

@ -0,0 +1,49 @@
ConstantBuffer<UI_RectSig> 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<UI_RectSig> 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<UI_RectInstance> 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<UI_RectSig> sig = UI_rect_sig;
f32 color = 0;
UI_RectPS_Output result;
result.sv_target0 = color;
return result;
}

23
src/ui/ui_draw.h Normal file
View File

@ -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 \
}

View File

@ -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;
}

View File

@ -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