ogl_beamforming

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

Commit: b5aca30273a410da0b2109f2bde09ad5b0a127df
Parent: 12f83e155798d5f4c2d40619a8dd7a16172568e5
Author: Randy Palamar
Date:   Wed,  2 Oct 2024 12:12:00 -0600

initial pass of runtime modification based on GPU limits

For now we only use the max 3D texture dimension and assert that
the max UBO size is large enough.

Diffstat:
Mbeamformer.c | 13+++++++------
Mbeamformer.h | 13++++++++++++-
Mmain.c | 69+++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------
Mui.c | 6+++---
4 files changed, 77 insertions(+), 24 deletions(-)

diff --git a/beamformer.c b/beamformer.c @@ -16,9 +16,10 @@ alloc_output_image(BeamformerCtx *ctx) BeamformerParameters *bp = &ctx->params->raw; ComputeShaderCtx *cs = &ctx->csctx; - ctx->out_data_dim.x = round_down_power_of_2(ORONE(bp->output_points.x)); - ctx->out_data_dim.y = round_down_power_of_2(ORONE(bp->output_points.y)); - ctx->out_data_dim.z = round_down_power_of_2(ORONE(bp->output_points.z)); + u32 max_3d_dim = ctx->gl.max_3d_texture_dim; + ctx->out_data_dim.x = CLAMP(round_down_power_of_2(ORONE(bp->output_points.x)), 1, max_3d_dim); + ctx->out_data_dim.y = CLAMP(round_down_power_of_2(ORONE(bp->output_points.y)), 1, max_3d_dim); + ctx->out_data_dim.z = CLAMP(round_down_power_of_2(ORONE(bp->output_points.z)), 1, max_3d_dim); ctx->out_data_dim.w = CLAMP(bp->output_points.w, 0, ARRAY_COUNT(cs->sum_textures)); bp->output_points = ctx->out_data_dim; @@ -75,7 +76,7 @@ alloc_shader_storage(BeamformerCtx *ctx, Arena a) glCreateBuffers(ARRAY_COUNT(cs->rf_data_ssbos), cs->rf_data_ssbos); i32 storage_flags = GL_DYNAMIC_STORAGE_BIT; - switch (ctx->gl_vendor_id) { + switch (ctx->gl.vendor_id) { case GL_VENDOR_INTEL: case GL_VENDOR_AMD: if (cs->raw_data_ssbo) @@ -95,7 +96,7 @@ alloc_shader_storage(BeamformerCtx *ctx, Arena a) glNamedBufferStorage(cs->rf_data_ssbos[i], rf_decoded_size, 0, 0); i32 map_flags = GL_MAP_WRITE_BIT|GL_MAP_PERSISTENT_BIT|GL_MAP_UNSYNCHRONIZED_BIT; - switch (ctx->gl_vendor_id) { + switch (ctx->gl.vendor_id) { case GL_VENDOR_INTEL: case GL_VENDOR_AMD: cs->raw_data_arena.beg = glMapNamedBufferRange(cs->raw_data_ssbo, 0, @@ -402,7 +403,7 @@ do_beamformer(BeamformerCtx *ctx, Arena arena) ctx->partial_transfer_count++; } else { ctx->flags |= DO_COMPUTE; - switch (ctx->gl_vendor_id) { + switch (ctx->gl.vendor_id) { case GL_VENDOR_INTEL: /* TODO: intel complains about this buffer being busy even with * MAP_UNSYNCHRONIZED_BIT */ diff --git a/beamformer.h b/beamformer.h @@ -230,9 +230,20 @@ typedef struct { } ExportCtx; typedef struct { + enum gl_vendor_ids vendor_id; + i32 version_major; + i32 version_minor; + i32 max_2d_texture_dim; + i32 max_3d_texture_dim; + i32 max_ssbo_size; + i32 max_ubo_size; +} GLParams; + +typedef struct { + GLParams gl; + uv2 window_size; u32 flags; - enum gl_vendor_ids gl_vendor_id; f32 dt; diff --git a/main.c b/main.c @@ -58,6 +58,55 @@ gl_debug_logger(u32 src, u32 type, u32 id, u32 lvl, i32 len, const char *msg, co fputc('\n', stderr); } +static void +get_gl_params(GLParams *gl) +{ + const u8 *vendor = glGetString(GL_VENDOR); + if (!vendor) + die("Failed to determine GL Vendor\n"); + switch (vendor[0]) { + case 'A': gl->vendor_id = GL_VENDOR_AMD; break; + case 'I': gl->vendor_id = GL_VENDOR_INTEL; break; + case 'N': gl->vendor_id = GL_VENDOR_NVIDIA; break; + default: die("Unknown GL Vendor: %s\n", vendor); break; + } + + glGetIntegerv(GL_MAJOR_VERSION, &gl->version_major); + glGetIntegerv(GL_MINOR_VERSION, &gl->version_minor); + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &gl->max_2d_texture_dim); + glGetIntegerv(GL_MAX_3D_TEXTURE_SIZE, &gl->max_3d_texture_dim); + glGetIntegerv(GL_MAX_SHADER_STORAGE_BLOCK_SIZE, &gl->max_ssbo_size); + glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &gl->max_ubo_size); +} + +static void +validate_gl_requirements(GLParams *gl) +{ + ASSERT(gl->max_ubo_size >= sizeof(BeamformerParameters)); + if (gl->version_major < 4 || (gl->version_major == 4 && gl->version_minor < 5)) + die("Only OpenGL Versions 4.5 or newer are supported!\n"); +} + +static void +dump_gl_params(GLParams *gl) +{ + (void)gl; +#ifdef _DEBUG + fputs("---- GL Parameters ----\n", stdout); + switch (gl->vendor_id) { + case GL_VENDOR_AMD: fputs("Vendor: AMD\n", stdout); break; + case GL_VENDOR_INTEL: fputs("Vendor: Intel\n", stdout); break; + case GL_VENDOR_NVIDIA: fputs("Vendor: nVidia\n", stdout); break; + } + printf("Version: %d.%d\n", gl->version_major, gl->version_minor); + printf("Max 1D/2D Texture Dimension: %d\n", gl->max_2d_texture_dim); + printf("Max 3D Texture Dimension: %d\n", gl->max_3d_texture_dim); + printf("Max SSBO Size: %d\n", gl->max_ssbo_size); + printf("Max UBO Size: %d\n", gl->max_ubo_size); + fputs("-----------------------\n", stdout); +#endif +} + static u32 compile_shader(Arena a, u32 type, s8 shader) { @@ -188,6 +237,11 @@ main(void) SetWindowState(FLAG_WINDOW_RESIZABLE); SetWindowMinSize(INFO_COLUMN_WIDTH * 2, ctx.window_size.h); + /* NOTE: Gather information about the GPU */ + get_gl_params(&ctx.gl); + dump_gl_params(&ctx.gl); + validate_gl_requirements(&ctx.gl); + /* TODO: build these into the binary */ ctx.font = LoadFontEx("assets/IBMPlexSans-Bold.ttf", 28, 0, 0); ctx.small_font = LoadFontEx("assets/IBMPlexSans-Bold.ttf", 22, 0, 0); @@ -210,19 +264,6 @@ main(void) ctx.params->compute_stages[3] = CS_MIN_MAX; ctx.params->compute_stages_count = 4; - /* NOTE: Determine which graphics vendor we are running on */ - { - const u8 *vendor = glGetString(GL_VENDOR); - if (!vendor) - die("Failed to determine GL Vendor\n"); - switch (vendor[0]) { - case 'A': ctx.gl_vendor_id = GL_VENDOR_AMD; break; - case 'I': ctx.gl_vendor_id = GL_VENDOR_INTEL; break; - case 'N': ctx.gl_vendor_id = GL_VENDOR_NVIDIA; break; - default: die("Unknown GL Vendor: %s\n", vendor); break; - } - } - /* NOTE: make sure function pointers are valid even if we are not using the cuda lib */ validate_cuda_lib(&ctx.cuda_lib); @@ -245,7 +286,7 @@ main(void) while(!WindowShouldClose()) { do_debug(); - if (ctx.gl_vendor_id == GL_VENDOR_NVIDIA) + if (ctx.gl.vendor_id == GL_VENDOR_NVIDIA) check_and_load_cuda_lib(&ctx.cuda_lib); if (ctx.flags & RELOAD_SHADERS) { diff --git a/ui.c b/ui.c @@ -542,17 +542,17 @@ draw_settings_ui(BeamformerCtx *ctx, Arena arena, Rect r, v2 mouse) draw_r.size.y -= 2 * LISTING_LINE_PAD; bmv = (BPModifiableValue){&ctx->export_ctx.volume_dim.x, MV_INT|MV_POWER_OF_TWO, 1, - .ilimits = (iv2){.x = 1, .y = 2048}}; + .ilimits = (iv2){.x = 1, .y = ctx->gl.max_3d_texture_dim}}; draw_r = do_text_input_listing(s8("Export Dimension X:"), s8(""), bmv, ctx, arena, draw_r, mouse, hover_t + idx++); bmv = (BPModifiableValue){&ctx->export_ctx.volume_dim.y, MV_INT|MV_POWER_OF_TWO, 1, - .ilimits = (iv2){.x = 1, .y = 2048}}; + .ilimits = (iv2){.x = 1, .y = ctx->gl.max_3d_texture_dim}}; draw_r = do_text_input_listing(s8("Export Dimension Y:"), s8(""), bmv, ctx, arena, draw_r, mouse, hover_t + idx++); bmv = (BPModifiableValue){&ctx->export_ctx.volume_dim.z, MV_INT|MV_POWER_OF_TWO, 1, - .ilimits = (iv2){.x = 1, .y = 2048}}; + .ilimits = (iv2){.x = 1, .y = ctx->gl.max_3d_texture_dim}}; draw_r = do_text_input_listing(s8("Export Dimension Z:"), s8(""), bmv, ctx, arena, draw_r, mouse, hover_t + idx++);