ogl_beamforming

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

Commit: 5117be241ed53337c4ec13dc0484038aa785f035
Parent: d9e7714d36ddced52a09bad992b052aa7a5cd2e5
Author: Randy Palamar
Date:   Tue,  7 Jul 2026 19:23:52 -0700

core/vulkan: replace buffer clear with vkCmdFillBuffer

I meant to do this when I found out about this function but it
slipped my mind. I knew that the buffer clear dispatch was going
to be too large but now that someone is actually hitting this case
I need to fix it.

fixes: #68

Diffstat:
Mbeamformer.c | 14+-------------
Mbeamformer.meta | 14--------------
Mbeamformer_core.c | 31++++++++-----------------------
Mbeamformer_internal.h | 3+--
Mgenerated/beamformer.meta.c | 55+++++++++++--------------------------------------------
Dshaders/buffer_clear.glsl | 11-----------
Mvulkan.c | 12++++++++++++
Mvulkan.h | 1+
8 files changed, 34 insertions(+), 107 deletions(-)

diff --git a/beamformer.c b/beamformer.c @@ -219,7 +219,7 @@ beamformer_init(BeamformerInput *input) VulkanTimeline timelines[] = {VulkanTimeline_Compute, VulkanTimeline_Graphics}; GPUBufferAllocateInfo allocate_info = { .size = trial_sizes[i], - .flags = VulkanUsageFlag_TransferSource|VulkanUsageFlag_HostReadWrite, + .flags = VulkanUsageFlag_TransferDestination|VulkanUsageFlag_TransferSource|VulkanUsageFlag_HostReadWrite, .timeline_count = countof(timelines), .timelines_used = timelines, .label = str8("BeamformedData"), @@ -339,18 +339,6 @@ beamformer_init(BeamformerInput *input) frc->shader_reload.shader = beamformer_reloadable_shader_kinds[index]; os_add_file_watch((char *)file.data, file.len, frc); } - - for EachElement(beamformer_reloadable_compute_internal_shader_info_indices, it) { - i32 index = beamformer_reloadable_compute_internal_shader_info_indices[it]; - Arena temp = scratch; - s8 file = push_s8_from_parts(&temp, os_path_separator(), s8("shaders"), - beamformer_reloadable_shader_files[index][0]); - BeamformerFileReloadContext *frc = push_struct(&memory, typeof(*frc)); - frc->kind = BeamformerFileReloadKind_ComputeInternalShader; - frc->shader_reload.shader = beamformer_reloadable_shader_kinds[index]; - frc->shader_reload.pipeline = cs->compute_internal_pipelines + it; - os_add_file_watch((char *)file.data, file.len, frc); - } } memory.end = scratch.end; diff --git a/beamformer.meta b/beamformer.meta @@ -464,20 +464,6 @@ } } -// NOTE: general compute shaders which do not need baking -@ShaderGroup ComputeInternal -{ - @Shader(buffer_clear.glsl) BufferClear - { - @PushConstants - { - [clear_v4 UV4] - [data U64] - [bins U32] - } - } -} - @ShaderGroup Render { @RenderShader RenderBeamformed diff --git a/beamformer_core.c b/beamformer_core.c @@ -1402,25 +1402,18 @@ complete_queue(BeamformerCtx *ctx, BeamformWorkQueue *q, Arena *arena) vk_command_timestamp(cmd); if (das_index >= 0) { + u64 frame_size = beamformer_frame_byte_size(frame->points, frame->data_kind); GPUBuffer *backlog = cs->backlog.buffer; - u32 subgroup_size = vk_gpu_info()->subgroup_size; - BeamformerBufferClearPushConstants pc = { - .data = backlog->gpu_pointer + frame->buffer_offset, - .clear_v4 = (uv4){{0}}, - .bins = beamformer_frame_byte_size(frame->points, frame->data_kind) / sizeof(uv4), - }; - u32 index = BeamformerShaderKind_BufferClear - BeamformerShaderKind_ComputeInternalFirst; - vk_command_bind_pipeline(cmd, cs->compute_internal_pipelines[index]); - vk_command_push_constants(cmd, 0, sizeof(pc), &pc); - vk_command_dispatch_compute(cmd, (uv3){{(u32)ceil_f32((f32)pc.bins / subgroup_size), 1, 1}}); + // TODO(rnp): this could be problematic if we support F16 output + assert((frame_size % 4) == 0); + assert((frame->buffer_offset % 4) == 0); + vk_command_clear_buffer(cmd, backlog, frame->buffer_offset, frame_size, 0); if (das_coherent) { - assert((pc.bins % beamformer_data_kind_element_count[frame->data_kind]) == 0); - pc.bins = pc.bins / beamformer_data_kind_element_count[frame->data_kind]; - pc.data = backlog->gpu_pointer + backlog->size - sizeof(uv4) * pc.bins; - vk_command_push_constants(cmd, 0, sizeof(pc), &pc); - vk_command_dispatch_compute(cmd, (uv3){{(u32)ceil_f32((f32)pc.bins / subgroup_size), 1, 1}}); + u64 coherent_size = frame_size / beamformer_data_kind_element_count[frame->data_kind]; + assert((coherent_size % 4) == 0); + vk_command_clear_buffer(cmd, backlog, backlog->size - coherent_size, coherent_size, 0); } } @@ -1679,14 +1672,6 @@ beamformer_process_input_events(BeamformerCtx *ctx, BeamformerInput *input, case BeamformerInputEventKind_ExecutableReload:{ ui_init(ctx, ctx->ui_backing_store); - - if (!vk_pipeline_valid(ctx->compute_context.compute_internal_pipelines[0])) { - for EachElement(ctx->compute_context.compute_internal_pipelines, it) { - beamformer_reload_compute_pipeline(ctx->compute_context.compute_internal_pipelines + it, - BeamformerShaderKind_ComputeInternalFirst + it, 0, - ctx->arena); - } - } }break; case BeamformerInputEventKind_FileEvent:{ diff --git a/beamformer_internal.h b/beamformer_internal.h @@ -179,6 +179,7 @@ DEBUG_IMPORT u64 vk_host_signal_timeline(VulkanTimeline timeline); DEBUG_IMPORT VulkanHandle vk_command_begin(VulkanTimeline timeline); DEBUG_IMPORT void vk_command_bind_pipeline(VulkanHandle command, VulkanHandle pipeline); DEBUG_IMPORT void vk_command_buffer_memory_barriers(VulkanHandle command, GPUMemoryBarrierInfo *barriers, u64 count); +DEBUG_IMPORT void vk_command_clear_buffer(VulkanHandle command, GPUBuffer *buffer, u64 offset, u64 size, u32 clear_word); DEBUG_IMPORT void vk_command_dispatch_compute(VulkanHandle command, uv3 dispatch); DEBUG_IMPORT void vk_command_push_constants(VulkanHandle command, u32 offset, u32 size, void *values); DEBUG_IMPORT void vk_command_timestamp(VulkanHandle command); @@ -428,8 +429,6 @@ typedef struct { BeamformerComputePlan *compute_plans[BeamformerMaxParameterBlocks]; BeamformerComputePlan *compute_plan_freelist; - VulkanHandle compute_internal_pipelines[BeamformerShaderKind_ComputeInternalCount]; - /* NOTE(rnp): used to ping pong data between compute stages. * * Allocate one extra slot for DAS output to allow overlap with the next diff --git a/generated/beamformer.meta.c b/generated/beamformer.meta.c @@ -106,22 +106,18 @@ typedef enum { BeamformerShaderKind_Hilbert = 6, BeamformerShaderKind_CoherencyWeighting = 7, BeamformerShaderKind_Reshape = 8, - BeamformerShaderKind_BufferClear = 9, - BeamformerShaderKind_RenderBeamformed = 10, + BeamformerShaderKind_RenderBeamformed = 9, BeamformerShaderKind_Count, - BeamformerShaderKind_ComputeFirst = BeamformerShaderKind_Decode, - BeamformerShaderKind_ComputeLast = BeamformerShaderKind_Hilbert, - BeamformerShaderKind_ComputeCount = 7, - BeamformerShaderKind_ComputeHelpersFirst = BeamformerShaderKind_CoherencyWeighting, - BeamformerShaderKind_ComputeHelpersLast = BeamformerShaderKind_Reshape, - BeamformerShaderKind_ComputeHelpersCount = 2, - BeamformerShaderKind_ComputeInternalFirst = BeamformerShaderKind_BufferClear, - BeamformerShaderKind_ComputeInternalLast = BeamformerShaderKind_BufferClear, - BeamformerShaderKind_ComputeInternalCount = 1, - BeamformerShaderKind_RenderFirst = BeamformerShaderKind_RenderBeamformed, - BeamformerShaderKind_RenderLast = BeamformerShaderKind_RenderBeamformed, - BeamformerShaderKind_RenderCount = 1, + BeamformerShaderKind_ComputeFirst = BeamformerShaderKind_Decode, + BeamformerShaderKind_ComputeLast = BeamformerShaderKind_Hilbert, + BeamformerShaderKind_ComputeCount = 7, + BeamformerShaderKind_ComputeHelpersFirst = BeamformerShaderKind_CoherencyWeighting, + BeamformerShaderKind_ComputeHelpersLast = BeamformerShaderKind_Reshape, + BeamformerShaderKind_ComputeHelpersCount = 2, + BeamformerShaderKind_RenderFirst = BeamformerShaderKind_RenderBeamformed, + BeamformerShaderKind_RenderLast = BeamformerShaderKind_RenderBeamformed, + BeamformerShaderKind_RenderCount = 1, } BeamformerShaderKind; typedef struct { @@ -241,12 +237,6 @@ typedef struct { } BeamformerReshapePushConstants; typedef struct { - uv4 clear_v4; - u64 data; - u32 bins; -} BeamformerBufferClearPushConstants; - -typedef struct { m4 mvp_matrix; u64 positions; u64 normals; @@ -541,7 +531,6 @@ read_only global s8 beamformer_shader_names[] = { s8_comp("Hilbert"), s8_comp("CoherencyWeighting"), s8_comp("Reshape"), - s8_comp("BufferClear"), s8_comp("RenderBeamformed"), }; @@ -553,7 +542,6 @@ read_only global BeamformerShaderKind beamformer_reloadable_shader_kinds[] = { BeamformerShaderKind_MinMax, BeamformerShaderKind_CoherencyWeighting, BeamformerShaderKind_Reshape, - BeamformerShaderKind_BufferClear, BeamformerShaderKind_RenderBeamformed, }; @@ -565,7 +553,6 @@ read_only global s8 *beamformer_reloadable_shader_files[] = { (s8 []){s8_comp("min_max.glsl")}, (s8 []){s8_comp("coherency_weighting.glsl")}, (s8 []){s8_comp("reshape.glsl")}, - (s8 []){s8_comp("buffer_clear.glsl")}, (s8 []){s8_comp("render_3d.vert.glsl"), s8_comp("render_3d.frag.glsl")}, }; @@ -580,7 +567,6 @@ read_only global i32 beamformer_shader_reloadable_index_by_shader[] = { 5, 6, 7, - 8, }; read_only global i32 beamformer_reloadable_compute_shader_info_indices[] = { @@ -596,12 +582,8 @@ read_only global i32 beamformer_reloadable_compute_helpers_shader_info_indices[] 6, }; -read_only global i32 beamformer_reloadable_compute_internal_shader_info_indices[] = { - 7, -}; - read_only global i32 beamformer_reloadable_render_shader_info_indices[] = { - 8, + 7, }; read_only global s8 beamformer_shader_global_header_strings[] = { @@ -706,13 +688,6 @@ read_only global s8 beamformer_shader_global_header_strings[] = { "\n"), s8_comp("" "layout(push_constant, std430) uniform PushConstants {\n" - " u32vec4 clear_v4;\n" - " uint64_t data;\n" - " uint32_t bins;\n" - "};\n" - "\n"), - s8_comp("" - "layout(push_constant, std430) uniform PushConstants {\n" " f32mat4 mvp_matrix;\n" " uint64_t positions;\n" " uint64_t normals;\n" @@ -738,7 +713,6 @@ read_only global b8 beamformer_shader_has_primitive[] = { 0, 0, 0, - 0, 1, }; @@ -750,7 +724,6 @@ read_only global b8 beamformer_shader_primitive_is_vertex[] = { 0, 0, 0, - 0, 1, }; @@ -763,7 +736,6 @@ read_only global i32 *beamformer_shader_header_vectors[] = { (i32 []){12}, (i32 []){13}, (i32 []){14}, - (i32 []){15}, }; read_only global i32 beamformer_shader_header_vector_lengths[] = { @@ -775,7 +747,6 @@ read_only global i32 beamformer_shader_header_vector_lengths[] = { 1, 1, 1, - 1, }; read_only global s8 *beamformer_shader_bake_parameter_names[] = { @@ -846,7 +817,6 @@ read_only global s8 *beamformer_shader_bake_parameter_names[] = { s8_comp("Deinterleave"), }, 0, - 0, }; read_only global u32 beamformer_shader_bake_parameter_float_bits[] = { @@ -858,7 +828,6 @@ read_only global u32 beamformer_shader_bake_parameter_float_bits[] = { 0x00000000UL, 0x00000000UL, 0x00000000UL, - 0x00000000UL, }; read_only global u8 beamformer_shader_bake_parameter_counts[] = { @@ -870,7 +839,6 @@ read_only global u8 beamformer_shader_bake_parameter_counts[] = { 0, 11, 0, - 0, }; read_only global u8 beamformer_shader_push_constant_sizes[] = { @@ -881,7 +849,6 @@ read_only global u8 beamformer_shader_push_constant_sizes[] = { 0, sizeof(BeamformerCoherencyWeightingPushConstants), sizeof(BeamformerReshapePushConstants), - sizeof(BeamformerBufferClearPushConstants), sizeof(BeamformerRenderBeamformedPushConstants), }; diff --git a/shaders/buffer_clear.glsl b/shaders/buffer_clear.glsl @@ -1,11 +0,0 @@ -/* See LICENSE for license details. */ -layout(std430, buffer_reference, buffer_reference_align = 32) restrict writeonly buffer Buffer { - u32vec4 x[]; -}; - -void main() -{ - u32 index = gl_GlobalInvocationID.x; - if (index < bins) - Buffer(data).x[index] = clear_v4; -} diff --git a/vulkan.c b/vulkan.c @@ -2542,6 +2542,18 @@ vk_command_buffer_memory_barriers(VulkanHandle command, GPUMemoryBarrierInfo *ba } DEBUG_IMPORT void +vk_command_clear_buffer(VulkanHandle command, GPUBuffer *buffer, u64 offset, u64 size, u32 clear_word) +{ + assert((offset % 4) == 0); + assert((size % 4) == 0); + if ValidVulkanHandle(command) { + VulkanBuffer *vb = vk_entity_data(buffer->handle, VulkanEntityKind_Buffer); + VkCommandBuffer cmd = vk_command_buffer(command); + vkCmdFillBuffer(cmd, vb->buffer, offset, size, clear_word); + } +} + +DEBUG_IMPORT void vk_command_dispatch_compute(VulkanHandle command, uv3 dispatch) { assert(dispatch.x <= U16_MAX); diff --git a/vulkan.h b/vulkan.h @@ -3154,6 +3154,7 @@ typedef struct { X(vkCmdDispatch, void, (VkCommandBuffer commandBuffer, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ)) \ X(vkCmdDrawIndexed, void, (VkCommandBuffer commandBuffer, uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, int32_t vertexOffset, uint32_t firstInstance)) \ X(vkCmdEndRendering, void, (VkCommandBuffer commandBuffer)) \ + X(vkCmdFillBuffer, void, (VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize size, uint32_t data)) \ X(vkCmdPipelineBarrier2, void, (VkCommandBuffer commandBuffer, const VkDependencyInfo *pDependencyInfo)) \ X(vkCmdPushConstants, void, (VkCommandBuffer commandBuffer, VkPipelineLayout layout, VkShaderStageFlags stageFlags, uint32_t offset, uint32_t size, const void *pValues)) \ X(vkCmdResetQueryPool, void, (VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount)) \