ogl_beamforming

Ultrasound Beamforming Implemented with OpenGL
git clone anongit@rnpnr.xyz:ogl_beamforming.git
Log | Files | Refs | Feed | Submodules | LICENSE

Commit: d3cfaa359b247baae041f266ecdb03d3874da76c
Parent: ea6a876212d30d4c6b91a6edb11b44ef94f5cf7e
Author: Randy Palamar
Date:   Fri,  2 May 2025 07:56:19 -0600

util: rework arena string building

Diffstat:
Mbeamformer.c | 73+++++++++++++++++++++++++++++++++----------------------------------------
Mbuild.c | 15+++++++--------
Mmain_linux.c | 4+---
Mos_linux.c | 15++++++---------
Mos_win32.c | 10++++------
Mstatic.c | 46++++++++++++++++++++--------------------------
Mui.c | 74++++++++++++++++++++++++++++++++++----------------------------------------
Mutil.c | 64++++++++++++++++++++++++++++++++++++++--------------------------
Mutil_gl.c | 13+++++--------
9 files changed, 148 insertions(+), 166 deletions(-)

diff --git a/beamformer.c b/beamformer.c @@ -89,7 +89,7 @@ alloc_beamform_frame(GLParams *gp, BeamformFrame *out, ComputeShaderStats *out_s u32 max_dim = MAX(out->dim.x, MAX(out->dim.y, out->dim.z)); out->mips = ctz_u32(max_dim) + 1; - Stream label = arena_stream(&arena); + Stream label = arena_stream(arena); stream_append_s8(&label, name); stream_append_byte(&label, '['); stream_append_hex_u64(&label, out->id); @@ -126,14 +126,13 @@ alloc_shader_storage(BeamformerCtx *ctx, u32 rf_raw_size, Arena a) LABEL_GL_OBJECT(GL_BUFFER, cs->raw_data_ssbo, s8("Raw_RF_SSBO")); iz rf_decoded_size = 2 * sizeof(f32) * cs->dec_data_dim.x * cs->dec_data_dim.y * cs->dec_data_dim.z; - Stream label = stream_alloc(&a, 256); + Stream label = arena_stream(a); stream_append_s8(&label, s8("Decoded_RF_SSBO_")); u32 s_widx = label.widx; for (u32 i = 0; i < ARRAY_COUNT(cs->rf_data_ssbos); i++) { glNamedBufferStorage(cs->rf_data_ssbos[i], rf_decoded_size, 0, 0); stream_append_u64(&label, i); - s8 rf_label = stream_to_s8(&label); - LABEL_GL_OBJECT(GL_BUFFER, cs->rf_data_ssbos[i], rf_label); + LABEL_GL_OBJECT(GL_BUFFER, cs->rf_data_ssbos[i], stream_to_s8(&label)); stream_reset(&label, s_widx); } @@ -392,57 +391,55 @@ do_compute_shader(BeamformerCtx *ctx, Arena arena, BeamformComputeFrame *frame, function s8 push_compute_shader_header(Arena *a, b32 parameters, ComputeShaderID shader) { - s8 result = {.data = a->beg}; + Stream sb = arena_stream(*a); - push_s8(a, s8("#version 460 core\n\n")); + stream_append_s8(&sb, s8("#version 460 core\n\n")); #define X(name, type, size, gltype, glsize, comment) "\t" #gltype " " #name #glsize "; " comment "\n" if (parameters) { - push_s8(a, s8("layout(std140, binding = 0) uniform parameters {\n" - BEAMFORMER_PARAMS_HEAD - BEAMFORMER_UI_PARAMS - BEAMFORMER_PARAMS_TAIL - "};\n\n")); + stream_append_s8(&sb, s8("layout(std140, binding = 0) uniform parameters {\n" + BEAMFORMER_PARAMS_HEAD + BEAMFORMER_UI_PARAMS + BEAMFORMER_PARAMS_TAIL + "};\n\n")); } #undef X switch (shader) { case CS_DAS: { - push_s8(a, s8("layout(" - "local_size_x = " str(DAS_LOCAL_SIZE_X) ", " - "local_size_y = " str(DAS_LOCAL_SIZE_Y) ", " - "local_size_z = " str(DAS_LOCAL_SIZE_Z) ") " - "in;\n\n")); - - push_s8(a, s8("layout(location = " str(DAS_VOXEL_OFFSET_UNIFORM_LOC) ") uniform ivec3 u_voxel_offset;\n")); - push_s8(a, s8("layout(location = " str(DAS_CYCLE_T_UNIFORM_LOC) ") uniform uint u_cycle_t;\n\n")); - #define X(type, id, pretty, fixed_tx) push_s8(a, s8("#define DAS_ID_" #type " " #id "\n")); + #define X(type, id, pretty, fixed_tx) "#define DAS_ID_" #type " " #id "\n" + stream_append_s8(&sb, s8("" + "layout(local_size_x = " str(DAS_LOCAL_SIZE_X) ", " + "local_size_y = " str(DAS_LOCAL_SIZE_Y) ", " + "local_size_z = " str(DAS_LOCAL_SIZE_Z) ") in;\n\n" + "layout(location = " str(DAS_VOXEL_OFFSET_UNIFORM_LOC) ") uniform ivec3 u_voxel_offset;\n" + "layout(location = " str(DAS_CYCLE_T_UNIFORM_LOC) ") uniform uint u_cycle_t;\n\n" DAS_TYPES + )); #undef X } break; case CS_DECODE_FLOAT: case CS_DECODE_FLOAT_COMPLEX: { - if (shader == CS_DECODE_FLOAT) push_s8(a, s8("#define INPUT_DATA_TYPE_FLOAT\n\n")); - else push_s8(a, s8("#define INPUT_DATA_TYPE_FLOAT_COMPLEX\n\n")); + if (shader == CS_DECODE_FLOAT) stream_append_s8(&sb, s8("#define INPUT_DATA_TYPE_FLOAT\n\n")); + else stream_append_s8(&sb, s8("#define INPUT_DATA_TYPE_FLOAT_COMPLEX\n\n")); } /* FALLTHROUGH */ case CS_DECODE: { - #define X(type, id, pretty) push_s8(a, s8("#define DECODE_MODE_" #type " " #id "\n")); + #define X(type, id, pretty) stream_append_s8(&sb, s8("#define DECODE_MODE_" #type " " #id "\n")); DECODE_TYPES #undef X } break; case CS_MIN_MAX: { - push_s8(a, s8("layout(location = " str(CS_MIN_MAX_MIPS_LEVEL_UNIFORM_LOC) - ") uniform int u_mip_map;\n\n")); + stream_append_s8(&sb, s8("layout(location = " str(CS_MIN_MAX_MIPS_LEVEL_UNIFORM_LOC) + ") uniform int u_mip_map;\n\n")); } break; case CS_SUM: { - push_s8(a, s8("layout(location = " str(CS_SUM_PRESCALE_UNIFORM_LOC) - ") uniform float u_sum_prescale = 1.0;\n\n")); + stream_append_s8(&sb, s8("layout(location = " str(CS_SUM_PRESCALE_UNIFORM_LOC) + ") uniform float u_sum_prescale = 1.0;\n\n")); } break; default: break; } - s8 end = push_s8(a, s8("\n#line 1\n")); - result.len = end.data + end.len - result.data; - return result; + stream_append_s8(&sb, s8("\n#line 1\n")); + return arena_stream_commit(a, &sb); } static b32 @@ -458,10 +455,9 @@ reload_compute_shader(BeamformerCtx *ctx, s8 path, s8 extra, ComputeShaderReload shader_text.len += header.len; if (shader_text.data == header.data) { - s8 info = {.data = tmp.beg}; - push_s8(&tmp, path); - push_s8(&tmp, extra); - info.len = tmp.beg - info.data; + Stream sb = arena_stream(tmp); + stream_append_s8s(&sb, path, extra); + s8 info = arena_stream_commit(&tmp, &sb); u32 new_program = load_shader(&ctx->os, tmp, 1, (s8){0}, (s8){0}, shader_text, info, csr->label); if (new_program) { @@ -471,12 +467,9 @@ reload_compute_shader(BeamformerCtx *ctx, s8 path, s8 extra, ComputeShaderReload glBindBufferBase(GL_UNIFORM_BUFFER, 0, cs->shared_ubo); } } else { - Stream buf = arena_stream(&tmp); - stream_append_s8(&buf, s8("failed to load: ")); - stream_append_s8(&buf, path); - stream_append_s8(&buf, extra); - stream_append_byte(&buf, '\n'); - ctx->os.write_file(ctx->os.stderr, stream_to_s8(&buf)); + Stream sb = arena_stream(tmp); + stream_append_s8s(&sb, s8("failed to load: "), path, extra, s8("\n")); + ctx->os.write_file(ctx->os.stderr, stream_to_s8(&sb)); } return result; diff --git a/build.c b/build.c @@ -314,22 +314,21 @@ check_rebuild_self(Arena arena, i32 argc, char *argv[]) { char *binary = shift(argv, argc); if (needs_rebuild(binary, BUILD_DEPS)) { - Stream name = stream_alloc(&arena, KB(1)); - stream_append_s8(&name, c_str_to_s8(binary)); - stream_append_s8(&name, s8(".old")); - stream_append_byte(&name, 0); + Stream name_buffer = arena_stream(arena); + stream_append_s8s(&name_buffer, c_str_to_s8(binary), s8(".old")); + char *old_name = (char *)arena_stream_commit_zero(&arena, &name_buffer).data; - if (!os_rename_file(binary, (char *)name.data)) - die("failed to move: %s -> %s\n", binary, (char *)name.data); + if (!os_rename_file(binary, old_name)) + die("failed to move: %s -> %s\n", binary, old_name); CommandList c = {0}; cmd_append(&arena, &c, BUILD_COMMAND(binary, __FILE__)); cmd_append(&arena, &c, "-O3", "-Wno-unused-function", (void *)0); if (!run_synchronous(arena, &c)) { - os_rename_file((char *)name.data, binary); + os_rename_file(old_name, binary); die("failed to rebuild self\n"); } - os_remove_file((char *)name.data); + os_remove_file(old_name); c.count = 0; cmd_append(&arena, &c, binary); diff --git a/main_linux.c b/main_linux.c @@ -43,9 +43,7 @@ dispatch_file_watch_events(OS *os, Arena arena) for (u32 i = 0; i < dir->file_watch_count; i++) { FileWatch *fw = dir->file_watches + i; if (fw->hash == hash) { - stream_append_s8(&path, dir->name); - stream_append_byte(&path, '/'); - stream_append_s8(&path, file); + stream_append_s8s(&path, dir->name, s8("/"), file); stream_append_byte(&path, 0); stream_commit(&path, -1); fw->callback(os, stream_to_s8(&path), diff --git a/os_linux.c b/os_linux.c @@ -26,9 +26,8 @@ os_get_module(char *name, Stream *e) { void *result = dlopen(name, RTLD_NOW|RTLD_LOCAL|RTLD_NOLOAD); if (!result && e) { - s8 errs[] = {s8("os_get_module(\""), c_str_to_s8(name), s8("\"): "), - c_str_to_s8(dlerror()), s8("\n")}; - stream_append_s8_array(e, errs, ARRAY_COUNT(errs)); + stream_append_s8s(e, s8("os_get_module(\""), c_str_to_s8(name), s8("\"): "), + c_str_to_s8(dlerror()), s8("\n")); } return result; } @@ -192,9 +191,8 @@ os_load_library(char *name, char *temp_name, Stream *e) void *result = dlopen(name, RTLD_NOW|RTLD_LOCAL); if (!result && e) { - s8 errs[] = {s8("os_load_library(\""), c_str_to_s8(name), s8("\"): "), - c_str_to_s8(dlerror()), s8("\n")}; - stream_append_s8_array(e, errs, ARRAY_COUNT(errs)); + stream_append_s8s(e, s8("os_load_library(\""), c_str_to_s8(name), s8("\"): "), + c_str_to_s8(dlerror()), s8("\n")); } if (temp_name) @@ -210,9 +208,8 @@ os_lookup_dynamic_symbol(void *h, char *name, Stream *e) if (h) { result = dlsym(h, name); if (!result && e) { - s8 errs[] = {s8("os_lookup_dynamic_symbol(\""), c_str_to_s8(name), - s8("\"): "), c_str_to_s8(dlerror()), s8("\n")}; - stream_append_s8_array(e, errs, ARRAY_COUNT(errs)); + stream_append_s8s(e, s8("os_lookup_dynamic_symbol(\""), c_str_to_s8(name), + s8("\"): "), c_str_to_s8(dlerror()), s8("\n")); } } return result; diff --git a/os_win32.c b/os_win32.c @@ -126,8 +126,7 @@ os_get_module(char *name, Stream *e) { void *result = GetModuleHandleA(name); if (!result && e) { - s8 errs[] = {s8("os_get_module(\""), c_str_to_s8(name), s8("\"): ")}; - stream_append_s8_array(e, errs, ARRAY_COUNT(errs)); + stream_append_s8s(e, s8("os_get_module(\""), c_str_to_s8(name), s8("\"): ")); stream_append_i64(e, GetLastError()); stream_append_byte(e, '\n'); } @@ -269,8 +268,7 @@ os_load_library(char *name, char *temp_name, Stream *e) void *result = LoadLibraryA(name); if (!result && e) { - s8 errs[] = {s8("os_load_library(\""), c_str_to_s8(name), s8("\"): ")}; - stream_append_s8_array(e, errs, ARRAY_COUNT(errs)); + stream_append_s8s(e, s8("os_load_library(\""), c_str_to_s8(name), s8("\"): ")); stream_append_i64(e, GetLastError()); stream_append_byte(e, '\n'); } @@ -288,8 +286,8 @@ os_lookup_dynamic_symbol(void *h, char *name, Stream *e) if (h) { result = GetProcAddress(h, name); if (!result && e) { - s8 errs[] = {s8("os_lookup_dynamic_symbol(\""), c_str_to_s8(name), s8("\"): ")}; - stream_append_s8_array(e, errs, ARRAY_COUNT(errs)); + stream_append_s8s(e, s8("os_lookup_dynamic_symbol(\""), c_str_to_s8(name), + s8("\"): ")); stream_append_i64(e, GetLastError()); stream_append_byte(e, '\n'); } diff --git a/static.c b/static.c @@ -18,10 +18,10 @@ static void *debug_lib; DEBUG_ENTRY_POINTS #undef X -static FILE_WATCH_CALLBACK_FN(debug_reload) +function FILE_WATCH_CALLBACK_FN(debug_reload) { BeamformerInput *input = (BeamformerInput *)user_data; - Stream err = arena_stream(&tmp); + Stream err = arena_stream(tmp); /* NOTE(rnp): spin until compute thread finishes its work (we will probably * never reload while compute is in progress but just incase). */ @@ -48,8 +48,7 @@ debug_init(OS *os, iptr input, Arena *arena) os->add_file_watch(os, arena, s8(OS_DEBUG_LIB_NAME), debug_reload, input); debug_reload(os, (s8){0}, input, *arena); - Arena tmp = *arena; - Stream err = arena_stream(&tmp); + Stream err = arena_stream(*arena); void *rdoc = os_get_module(OS_RENDERDOC_SONAME, 0); if (rdoc) { renderdoc_get_api_fn *get_api = os_lookup_dynamic_symbol(rdoc, "RENDERDOC_GetAPI", &err); @@ -114,9 +113,7 @@ get_gl_params(GLParams *gl, Stream *err) /* NOTE(rnp): Microsoft Corporation - weird win32 thing (microsoft is just using mesa for the driver) */ case 'M': gl->vendor_id = GL_VENDOR_ARM; break; default: - stream_append_s8(err, s8("Unknown GL Vendor: ")); - stream_append_s8(err, c_str_to_s8(vendor)); - stream_append_byte(err, '\n'); + stream_append_s8s(err, s8("Unknown GL Vendor: "), c_str_to_s8(vendor), s8("\n")); os_fatal(stream_to_s8(err)); } @@ -131,10 +128,10 @@ get_gl_params(GLParams *gl, Stream *err) gl->version_minor = 5; } -static void +function void validate_gl_requirements(GLParams *gl, Arena a) { - Stream s = arena_stream(&a); + Stream s = arena_stream(a); if (gl->max_ubo_size < sizeof(BeamformerParameters)) { stream_append_s8(&s, s8("GPU must support UBOs of at least ")); @@ -160,9 +157,8 @@ dump_gl_params(GLParams *gl, Arena a, OS *os) #undef X max_width++; - Stream s = arena_stream(&a); - stream_append_s8(&s, s8("---- GL Parameters ----\n")); - stream_append_s8(&s, vendor); + Stream s = arena_stream(a); + stream_append_s8s(&s, s8("---- GL Parameters ----\n"), vendor); stream_pad(&s, ' ', max_width - vendor.len); switch (gl->vendor_id) { case GL_VENDOR_AMD: stream_append_s8(&s, s8("AMD\n")); break; @@ -202,19 +198,17 @@ function FILE_WATCH_CALLBACK_FN(reload_render_shader) "\tgl_Position = vec4(vertex_position, 0, 1);\n" "}\n"); - Arena *a = &tmp; - s8 header = {.data = a->beg}; - push_s8(a, s8("#version 460 core\n\n")); - push_s8(a, s8("layout(location = 0) in vec2 fragment_texture_coordinate;\n")); - push_s8(a, s8("layout(location = 0) out vec4 v_out_colour;\n\n")); - push_s8(a, s8("layout(location = " str(FRAME_VIEW_RENDER_DYNAMIC_RANGE_LOC) ") uniform float u_db_cutoff = 60;\n")); - push_s8(a, s8("layout(location = " str(FRAME_VIEW_RENDER_THRESHOLD_LOC) ") uniform float u_threshold = 40;\n")); - push_s8(a, s8("layout(location = " str(FRAME_VIEW_RENDER_GAMMA_LOC) ") uniform float u_gamma = 1;\n")); - push_s8(a, s8("layout(location = " str(FRAME_VIEW_RENDER_LOG_SCALE_LOC) ") uniform bool u_log_scale;\n")); - push_s8(a, s8("\n#line 1\n")); - header.len = a->beg - header.data; - - s8 fragment = os->read_whole_file(a, (c8 *)path.data); + s8 header = push_s8(&tmp, s8("" + "#version 460 core\n\n" + "layout(location = 0) in vec2 fragment_texture_coordinate;\n" + "layout(location = 0) out vec4 v_out_colour;\n\n" + "layout(location = " str(FRAME_VIEW_RENDER_DYNAMIC_RANGE_LOC) ") uniform float u_db_cutoff = 60;\n" + "layout(location = " str(FRAME_VIEW_RENDER_THRESHOLD_LOC) ") uniform float u_threshold = 40;\n" + "layout(location = " str(FRAME_VIEW_RENDER_GAMMA_LOC) ") uniform float u_gamma = 1;\n" + "layout(location = " str(FRAME_VIEW_RENDER_LOG_SCALE_LOC) ") uniform bool u_log_scale;\n" + "\n#line 1\n")); + + s8 fragment = os->read_whole_file(&tmp, (c8 *)path.data); fragment.data -= header.len; fragment.len += header.len; ASSERT(fragment.data == header.data); @@ -248,7 +242,7 @@ static FILE_WATCH_CALLBACK_FN(load_cuda_lib) CudaLib *cl = (CudaLib *)user_data; b32 result = os_file_exists((c8 *)path.data); if (result) { - Stream err = arena_stream(&tmp); + Stream err = arena_stream(tmp); stream_append_s8(&err, s8("loading CUDA lib: " OS_CUDA_LIB_NAME "\n")); os_unload_library(cl->lib); diff --git a/ui.c b/ui.c @@ -654,11 +654,9 @@ function TableCell table_variable_cell(Arena *a, Variable *var) { TableCell result = {.var = var, .kind = TCK_VARIABLE}; - Arena tmp = *a; - Stream text = arena_stream(&tmp); + Stream text = arena_stream(*a); stream_append_variable(&text, var); - result.text = stream_to_s8(&text); - arena_commit(a, text.widx); + result.text = arena_stream_commit(a, &text); return result; } @@ -1487,8 +1485,9 @@ draw_title_bar(BeamformerUI *ui, Arena arena, Variable *ui_view, Rect r, v2 mous s8 title = ui_view->name; if (view->flags & UI_VIEW_CUSTOM_TEXT) { - Stream buf = arena_stream(&arena); - title = push_custom_view_title(&buf, ui_view->u.group.first); + Stream buf = arena_stream(arena); + push_custom_view_title(&buf, ui_view->u.group.first); + title = arena_stream_commit(&arena, &buf); } Rect result, title_rect; @@ -1539,7 +1538,7 @@ draw_title_bar(BeamformerUI *ui, Arena arena, Variable *ui_view, Rect r, v2 mous /* TODO(rnp): once this has more callers decide if it would be better for this to take * an orientation rather than force CCW/right-handed */ function void -draw_ruler(BeamformerUI *ui, Stream *buf, v2 start_point, v2 end_point, +draw_ruler(BeamformerUI *ui, Arena arena, v2 start_point, v2 end_point, f32 start_value, f32 end_value, f32 *markers, u32 marker_count, u32 segments, s8 suffix, v4 marker_colour, v4 txt_colour) { @@ -1556,6 +1555,7 @@ draw_ruler(BeamformerUI *ui, Stream *buf, v2 start_point, v2 end_point, f32 value_inc = (end_value - start_value) / segments; f32 value = start_value; + Stream buf = arena_stream(arena); v2 sp = {0}, ep = {.y = RULER_TICK_LENGTH}; v2 tp = {.x = ui->small_font.baseSize / 2, .y = ep.y + RULER_TEXT_PAD}; TextSpec text_spec = {.font = &ui->small_font, .rotation = 90, .colour = txt_colour, .flags = TF_ROTATED}; @@ -1563,11 +1563,11 @@ draw_ruler(BeamformerUI *ui, Stream *buf, v2 start_point, v2 end_point, for (u32 j = 0; j <= segments; j++) { DrawLineEx(sp.rl, ep.rl, 3, rl_txt_colour); - stream_reset(buf, 0); - if (draw_plus && value > 0) stream_append_byte(buf, '+'); - stream_append_f64(buf, value, 10); - stream_append_s8(buf, suffix); - draw_text(stream_to_s8(buf), tp, &text_spec); + stream_reset(&buf, 0); + if (draw_plus && value > 0) stream_append_byte(&buf, '+'); + stream_append_f64(&buf, value, 10); + stream_append_s8(&buf, suffix); + draw_text(stream_to_s8(&buf), tp, &text_spec); value += value_inc; sp.x += inc; @@ -1589,7 +1589,7 @@ draw_ruler(BeamformerUI *ui, Stream *buf, v2 start_point, v2 end_point, } function void -do_scale_bar(BeamformerUI *ui, Stream *buf, Variable *scale_bar, v2 mouse, Rect draw_rect, +do_scale_bar(BeamformerUI *ui, Arena arena, Variable *scale_bar, v2 mouse, Rect draw_rect, f32 start_value, f32 end_value, s8 suffix) { ASSERT(scale_bar->type == VT_SCALE_BAR); @@ -1628,11 +1628,11 @@ do_scale_bar(BeamformerUI *ui, Stream *buf, Variable *scale_bar, v2 mouse, Rect if (hover_var(ui, mouse, tick_rect, scale_bar)) marker_count = 2; - draw_ruler(ui, buf, start_pos, end_pos, start_value, end_value, markers, marker_count, + draw_ruler(ui, arena, start_pos, end_pos, start_value, end_value, markers, marker_count, tick_count, suffix, RULER_COLOUR, lerp_v4(FG_COLOUR, HOVERED_COLOUR, scale_bar->hover_t)); } -static v2 +function v2 draw_radio_button(BeamformerUI *ui, Variable *var, v2 at, v2 mouse, v4 base_colour, f32 size) { ASSERT(var->type == VT_B32 || var->type == VT_BEAMFORMER_VARIABLE); @@ -1665,9 +1665,10 @@ draw_variable(BeamformerUI *ui, Arena arena, Variable *var, v2 at, v2 mouse, v4 if (var->flags & V_RADIO_BUTTON) { result = draw_radio_button(ui, var, at, mouse, base_colour, text_spec.font->baseSize); } else { - Stream buf = arena_stream(&arena); + Stream buf = arena_stream(arena); stream_append_variable(&buf, var); - result = measure_text(*text_spec.font, stream_to_s8(&buf)); + s8 text = arena_stream_commit(&arena, &buf); + result = measure_text(*text_spec.font, text); if (var->flags & V_INPUT) { Rect text_rect = {.pos = at, .size = result}; @@ -1677,7 +1678,7 @@ draw_variable(BeamformerUI *ui, Arena arena, Variable *var, v2 at, v2 mouse, v4 text_spec.colour = lerp_v4(base_colour, HOVERED_COLOUR, var->hover_t); } - draw_text(stream_to_s8(&buf), at, &text_spec); + draw_text(text, at, &text_spec); } return result; } @@ -1823,9 +1824,7 @@ draw_beamformer_frame_view(BeamformerUI *ui, Arena a, Variable *var, Rect displa start_pos.y += vr.size.y; if (vr.size.w > 0 && view->lateral_scale_bar_active->u.b32) { - Arena tmp = a; - Stream buf = arena_stream(&tmp); - do_scale_bar(ui, &buf, &view->lateral_scale_bar, mouse, + do_scale_bar(ui, a, &view->lateral_scale_bar, mouse, (Rect){.pos = start_pos, .size = vr.size}, *view->lateral_scale_bar.u.scale_bar.min_value * 1e3, *view->lateral_scale_bar.u.scale_bar.max_value * 1e3, s8(" mm")); @@ -1835,9 +1834,7 @@ draw_beamformer_frame_view(BeamformerUI *ui, Arena a, Variable *var, Rect displa start_pos.x += vr.size.x; if (vr.size.h > 0 && view->axial_scale_bar_active->u.b32) { - Arena tmp = a; - Stream buf = arena_stream(&tmp); - do_scale_bar(ui, &buf, &view->axial_scale_bar, mouse, + do_scale_bar(ui, a, &view->axial_scale_bar, mouse, (Rect){.pos = start_pos, .size = vr.size}, *view->axial_scale_bar.u.scale_bar.max_value * 1e3, *view->axial_scale_bar.u.scale_bar.min_value * 1e3, s8(" mm")); @@ -1855,8 +1852,7 @@ draw_beamformer_frame_view(BeamformerUI *ui, Arena a, Variable *var, Rect displa v2 world = screen_point_to_world_2d(mouse, vr.pos, add_v2(vr.pos, vr.size), XZ(view->min_coordinate), XZ(view->max_coordinate)); - Arena tmp = a; - Stream buf = arena_stream(&tmp); + Stream buf = arena_stream(a); stream_append_v2(&buf, scale_v2(world, 1e3)); text_spec.limits.size.w -= 4; @@ -1871,8 +1867,7 @@ draw_beamformer_frame_view(BeamformerUI *ui, Arena a, Variable *var, Rect displa } { - Arena tmp = a; - Stream buf = arena_stream(&tmp); + Stream buf = arena_stream(a); s8 shader = push_das_shader_id(&buf, frame->das_shader_id, frame->compound_count); text_spec.font = &ui->font; text_spec.limits.size.w -= 16; @@ -1910,8 +1905,7 @@ draw_beamformer_frame_view(BeamformerUI *ui, Arena a, Variable *var, Rect displa DrawLineEx(end_p.rl, start_p.rl, 2, rl_colour); DrawCircleV(end_p.rl, 3, rl_colour); - Arena tmp = a; - Stream buf = arena_stream(&tmp); + Stream buf = arena_stream(a); stream_append_f64(&buf, 1e3 * magnitude_v2(m_delta), 100); stream_append_s8(&buf, s8(" mm")); @@ -1974,24 +1968,26 @@ draw_compute_stats_view(BeamformerCtx *ctx, Arena arena, ComputeShaderStats *sta u32 stages = ctx->shared_memory->compute_stages_count; TextSpec text_spec = {.font = &ui->font, .colour = FG_COLOUR, .flags = TF_LIMITED}; - Stream sb = stream_alloc(&arena, 256); Table *table = table_new(&arena, stages + 1, 3, (TextAlignment []){TA_LEFT, TA_LEFT, TA_LEFT}); for (u32 i = 0; i < stages; i++) { - u32 index = ctx->shared_memory->compute_stages[i]; + TableCell *cells = table_push_row(table, &arena, TRK_CELLS)->data; + + Stream sb = arena_stream(arena); + u32 index = ctx->shared_memory->compute_stages[i]; compute_time_sum += stats->times[index]; stream_append_f64_e(&sb, stats->times[index]); - TableCell *cells = table_push_row(table, &arena, TRK_CELLS)->data; cells[0].text = labels[index]; - cells[1].text = stream_chop_head(&sb); + cells[1].text = arena_stream_commit(&arena, &sb); cells[2].text = s8("[s]"); } - stream_append_f64_e(&sb, compute_time_sum); TableCell *cells = table_push_row(table, &arena, TRK_CELLS)->data; + Stream sb = arena_stream(arena); + stream_append_f64_e(&sb, compute_time_sum); cells[0].text = s8("Compute Total:"); - cells[1].text = stream_chop_head(&sb); + cells[1].text = arena_stream_commit(&arena, &sb); cells[2].text = s8("[s]"); table_extent(table, arena, text_spec.font); @@ -2042,8 +2038,7 @@ draw_ui_view_listing(BeamformerUI *ui, Variable *group, Arena arena, Rect r, v2 /* NOTE(rnp): assume the suffix is the same for all elements */ if (v) cells[2].text = v->u.beamformer_variable.suffix; - Arena tmp = arena; - Stream sb = arena_stream(&tmp); + Stream sb = arena_stream(arena); switch (g->type) { case VG_LIST: break; case VG_V2: @@ -2057,9 +2052,8 @@ draw_ui_view_listing(BeamformerUI *ui, Variable *group, Arena arena, Rect r, v2 stream_append_s8(&sb, s8("}")); } break; } - arena_commit(&arena, sb.widx); cells[1].kind = TCK_VARIABLE_GROUP; - cells[1].text = stream_to_s8(&sb); + cells[1].text = arena_stream_commit(&arena, &sb); cells[1].var = var; var = var->next; diff --git a/util.c b/util.c @@ -204,17 +204,7 @@ utf16_encode(u16 *out, u32 cp) return result; } -static Stream -arena_stream(Arena *a) -{ - Stream result = {0}; - result.data = a->beg; - result.cap = a->end - a->beg; - a->beg = a->end; - return result; -} - -static Stream +function Stream stream_alloc(Arena *a, iz cap) { Stream result = {.cap = cap}; @@ -222,20 +212,11 @@ stream_alloc(Arena *a, iz cap) return result; } -static s8 -stream_to_s8(Stream *s) -{ - s8 result = {.len = s->widx, .data = s->data}; - return result; -} - function s8 -stream_chop_head(Stream *s) +stream_to_s8(Stream *s) { - s8 result = stream_to_s8(s); - s->cap -= s->widx; - s->data += s->widx; - s->widx = 0; + s8 result = {0}; + if (!s->errors) result = (s8){.len = s->widx, .data = s->data}; return result; } @@ -283,8 +264,10 @@ stream_append_s8(Stream *s, s8 str) stream_append(s, str.data, str.len); } -static void -stream_append_s8_array(Stream *s, s8 *strs, iz count) +#define stream_append_s8s(s, ...) stream_append_s8s_(s, (s8 []){__VA_ARGS__}, \ + sizeof((s8 []){__VA_ARGS__}) / sizeof(s8)) +function void +stream_append_s8s_(Stream *s, s8 *strs, iz count) { for (iz i = 0; i < count; i++) stream_append(s, strs[i].data, strs[i].len); @@ -400,8 +383,37 @@ stream_append_v2(Stream *s, v2 v) stream_append_byte(s, '}'); } +function Stream +arena_stream(Arena a) +{ + Stream result = {0}; + result.data = a.beg; + result.cap = a.end - a.beg; + return result; +} + +function s8 +arena_stream_commit(Arena *a, Stream *s) +{ + ASSERT(s->data == a->beg); + s8 result = stream_to_s8(s); + arena_commit(a, result.len); + return result; +} + +function s8 +arena_stream_commit_zero(Arena *a, Stream *s) +{ + b32 error = s->errors || s->widx == s->cap; + if (!error) + s->data[s->widx] = 0; + s8 result = stream_to_s8(s); + arena_commit(a, result.len + 1); + return result; +} + /* NOTE(rnp): FNV-1a hash */ -static u64 +function u64 s8_hash(s8 v) { u64 h = 0x3243f6a8885a308d; /* digits of pi */ diff --git a/util_gl.c b/util_gl.c @@ -10,9 +10,8 @@ compile_shader(OS *os, Arena a, u32 type, s8 shader, s8 name) glGetShaderiv(sid, GL_COMPILE_STATUS, &res); if (res == GL_FALSE) { - Stream buf = arena_stream(&a); - stream_append_s8(&buf, name); - stream_append_s8(&buf, s8(": failed to compile\n")); + Stream buf = arena_stream(a); + stream_append_s8s(&buf, name, s8(": failed to compile\n")); i32 len = 0, out_len = 0; glGetShaderiv(sid, GL_INFO_LOG_LENGTH, &len); @@ -38,7 +37,7 @@ link_program(OS *os, Arena a, u32 *shader_ids, u32 shader_id_count) glGetProgramiv(result, GL_LINK_STATUS, &success); if (success == GL_FALSE) { i32 len = 0; - Stream buf = arena_stream(&a); + Stream buf = arena_stream(a); stream_append_s8(&buf, s8("shader link error: ")); glGetProgramInfoLog(result, buf.cap - buf.widx, &len, (c8 *)(buf.data + buf.widx)); stream_reset(&buf, len); @@ -67,10 +66,8 @@ load_shader(OS *os, Arena arena, b32 compute, s8 vs_text, s8 fs_text, s8 cs_text } if (result) { - Stream buf = arena_stream(&arena); - stream_append_s8(&buf, s8("loaded: ")); - stream_append_s8(&buf, info_name); - stream_append_byte(&buf, '\n'); + Stream buf = arena_stream(arena); + stream_append_s8s(&buf, s8("loaded: "), info_name, s8("\n")); os->write_file(os->stderr, stream_to_s8(&buf)); LABEL_GL_OBJECT(GL_PROGRAM, result, label); }