ogl_beamforming

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

Commit: 20ab88cdec5da5c429ac14b297e54076564a6692
Parent: 4a9c90ccc3db2c8ab66292e5bbfbe881c53d1270
Author: Randy Palamar
Date:   Wed,  2 Jul 2025 20:29:06 -0600

ui: enable MSAA for 3D views

Diffstat:
Mbeamformer.h | 8+++++---
Mstatic.c | 13+++++++++++--
Mui.c | 35++++++++++++++++++++++-------------
3 files changed, 38 insertions(+), 18 deletions(-)

diff --git a/beamformer.h b/beamformer.h @@ -72,10 +72,12 @@ typedef struct { #define FRAME_VIEW_BB_COLOUR 0.92, 0.88, 0.78, 1.0 #define FRAME_VIEW_BB_FRACTION 0.007f +#define FRAME_VIEW_RENDER_TARGET_SIZE 1024, 1024 + typedef struct { - /* NOTE(rnp): shaders[0] -> 2D render, shader[1] -> 3D render */ - u32 shaders[2]; - u32 framebuffer; + u32 shaders[2]; /* [0] -> 2D render, [1] -> 3D render */ + u32 framebuffers[2]; /* [0] -> multisample target, [1] -> normal target for resolving */ + u32 renderbuffers[2]; /* only used for 3D views, size is fixed */ u32 vao; u32 vbo; b32 updated; diff --git a/static.c b/static.c @@ -381,8 +381,17 @@ setup_beamformer(BeamformerCtx *ctx, BeamformerInput *input, Arena *memory) os_wake_waiters(&worker->sync_variable); FrameViewRenderContext *fvr = &ctx->frame_view_render_context; - glCreateFramebuffers(1, &fvr->framebuffer); - LABEL_GL_OBJECT(GL_FRAMEBUFFER, fvr->framebuffer, s8("Frame View Render Framebuffer")); + glCreateFramebuffers(countof(fvr->framebuffers), fvr->framebuffers); + LABEL_GL_OBJECT(GL_FRAMEBUFFER, fvr->framebuffers[0], s8("Frame View Framebuffer")); + LABEL_GL_OBJECT(GL_FRAMEBUFFER, fvr->framebuffers[1], s8("Frame View Resolving Framebuffer")); + + glCreateRenderbuffers(countof(fvr->renderbuffers), fvr->renderbuffers); + i32 msaa_samples = ctx->gl.vendor_id == GL_VENDOR_ARM? 4 : 8; + glNamedRenderbufferStorageMultisample(fvr->renderbuffers[0], msaa_samples, GL_RGBA8, + FRAME_VIEW_RENDER_TARGET_SIZE); + glNamedRenderbufferStorageMultisample(fvr->renderbuffers[1], msaa_samples, GL_DEPTH_COMPONENT24, + FRAME_VIEW_RENDER_TARGET_SIZE); + f32 vertices[] = { -1, 1, 0, 0, -1, -1, 0, 1, diff --git a/ui.c b/ui.c @@ -1,6 +1,5 @@ /* See LICENSE for license details. */ /* TODO(rnp): - * [ ]: MSAA for 3D views * [ ]: refactor: render_2d.frag should be merged into render_3d.frag * [ ]: refactor: ui should be in its own thread and that thread should only be concerned with the ui * [ ]: refactor: ui shouldn't fully destroy itself on hot reload @@ -775,15 +774,15 @@ table_end_subtable(Table *table) } function void -resize_frame_view(BeamformerFrameView *view, uv2 dim) +resize_frame_view(BeamformerFrameView *view, uv2 dim, b32 depth) { glDeleteTextures(countof(view->textures), view->textures); - glCreateTextures(GL_TEXTURE_2D, countof(view->textures), view->textures); + glCreateTextures(GL_TEXTURE_2D, countof(view->textures) - !!depth, view->textures); view->texture_dim = dim; view->texture_mipmaps = ctz_u32(MAX(dim.x, dim.y)) + 1; glTextureStorage2D(view->textures[0], view->texture_mipmaps, GL_RGBA8, dim.x, dim.y); - glTextureStorage2D(view->textures[1], 1, GL_DEPTH_COMPONENT24, dim.x, dim.y); + if (depth) glTextureStorage2D(view->textures[1], 1, GL_DEPTH_COMPONENT24, dim.x, dim.y); glGenerateTextureMipmap(view->textures[0]); @@ -1094,7 +1093,9 @@ add_beamformer_frame_view(BeamformerUI *ui, Variable *parent, Arena *arena, switch (kind) { case BeamformerFrameViewKind_3DXPlane:{ - resize_frame_view(bv, (uv2){{1024, 1024}}); + resize_frame_view(bv, (uv2){{FRAME_VIEW_RENDER_TARGET_SIZE}}, 0); + glTextureParameteri(bv->textures[0], GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTextureParameteri(bv->textures[0], GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); fill_variable(bv->x_plane_shifts + 0, var, s8("XZ Shift"), V_INPUT|V_IMAGING_PARAM, VT_X_PLANE_SHIFT, ui->small_font); fill_variable(bv->x_plane_shifts + 1, var, s8("YZ Shift"), V_INPUT|V_IMAGING_PARAM, @@ -1277,7 +1278,7 @@ ui_copy_frame(BeamformerUI *ui, Variable *view, RegionSplitDirection direction) bv->frame->dim.x, bv->frame->dim.y, bv->frame->dim.z); glMemoryBarrier(GL_TEXTURE_UPDATE_BARRIER_BIT); /* TODO(rnp): x vs y here */ - resize_frame_view(bv, (uv2){.x = bv->frame->dim.x, .y = bv->frame->dim.z}); + resize_frame_view(bv, (uv2){.x = bv->frame->dim.x, .y = bv->frame->dim.z}, 1); } function v3 @@ -1461,7 +1462,7 @@ view_update(BeamformerUI *ui, BeamformerFrameView *view) view->kind != BeamformerFrameViewKind_3DXPlane && !uv2_equal(current, target) && !uv2_equal(target, (uv2){0})) { - resize_frame_view(view, target); + resize_frame_view(view, target, 1); view->needs_update = 1; } @@ -1479,7 +1480,7 @@ update_frame_views(BeamformerUI *ui, Rect window) if (view_update(ui, view)) { if (!fbo_bound) { fbo_bound = 1; - glBindFramebuffer(GL_FRAMEBUFFER, ctx->framebuffer); + glBindFramebuffer(GL_FRAMEBUFFER, ctx->framebuffers[0]); glUseProgram(ctx->shaders[0]); glEnable(GL_DEPTH_TEST); } @@ -1490,11 +1491,7 @@ update_frame_views(BeamformerUI *ui, Rect window) if ( shader_3d) { glUseProgram(ctx->shaders[0]); shader_3d = 0; } } - glNamedFramebufferTexture(ctx->framebuffer, GL_COLOR_ATTACHMENT0, view->textures[0], 0); - glNamedFramebufferTexture(ctx->framebuffer, GL_DEPTH_ATTACHMENT, view->textures[1], 0); - glClearNamedFramebufferfv(ctx->framebuffer, GL_COLOR, 0, (f32 []){0, 0, 0, 0}); - glClearNamedFramebufferfv(ctx->framebuffer, GL_DEPTH, 0, (f32 []){1}); - + u32 fb = ctx->framebuffers[0]; u32 program = ctx->shaders[shader_3d]; glViewport(0, 0, view->texture_dim.w, view->texture_dim.h); glProgramUniform1f(program, FRAME_VIEW_THRESHOLD_LOC, view->threshold.real32); @@ -1503,8 +1500,20 @@ update_frame_views(BeamformerUI *ui, Rect window) glProgramUniform1ui(program, FRAME_VIEW_LOG_SCALE_LOC, view->log_scale->bool32); if (view->kind == BeamformerFrameViewKind_3DXPlane) { + glNamedFramebufferRenderbuffer(fb, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, ctx->renderbuffers[0]); + glNamedFramebufferRenderbuffer(fb, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, ctx->renderbuffers[1]); + glClearNamedFramebufferfv(fb, GL_COLOR, 0, (f32 []){0, 0, 0, 0}); + glClearNamedFramebufferfv(fb, GL_DEPTH, 0, (f32 []){1}); render_3D_xplane(ui, view, ctx->shaders[1]); + /* NOTE(rnp): resolve multisampled scene */ + glNamedFramebufferTexture(ctx->framebuffers[1], GL_COLOR_ATTACHMENT0, view->textures[0], 0); + glBlitNamedFramebuffer(fb, ctx->framebuffers[1], 0, 0, FRAME_VIEW_RENDER_TARGET_SIZE, + 0, 0, FRAME_VIEW_RENDER_TARGET_SIZE, GL_COLOR_BUFFER_BIT, GL_NEAREST); } else { + glNamedFramebufferTexture(fb, GL_COLOR_ATTACHMENT0, view->textures[0], 0); + glNamedFramebufferTexture(fb, GL_DEPTH_ATTACHMENT, view->textures[1], 0); + glClearNamedFramebufferfv(fb, GL_COLOR, 0, (f32 []){0, 0, 0, 0}); + glClearNamedFramebufferfv(fb, GL_DEPTH, 0, (f32 []){1}); glBindVertexArray(ctx->vao); glBindTextureUnit(0, view->frame->texture); glDrawArrays(GL_TRIANGLES, 0, 6);