ogl_beamforming

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

Commit: 868f1629b9c073e243b093942112542b8da7296d
Parent: c8af5968f1b5fe9ea82759c147b893254f4d4649
Author: Randy Palamar
Date:   Tue, 11 Aug 2026 06:24:36 -0700

gpu: cleanup overcomplicated barrier usage

There are no GPU drivers that care about this, it is all just
vulkan pedantics. These all just boil down to a single barrier
that invalidates the GPU's L2 so that subsequent stages can see
the results of previous stages. Partial L2 invalidation is not
something that is implemented anywhere because it would be way too
complex (you are going to track which threads are using which
portion of the L2 in hardware?)

Diffstat:
Mbeamformer_core.c | 112+++++--------------------------------------------------------------------------
Mbeamformer_internal.h | 8+-------
Mvulkan.c | 53+++++++++++++++--------------------------------------
3 files changed, 22 insertions(+), 151 deletions(-)

diff --git a/beamformer_core.c b/beamformer_core.c @@ -1139,26 +1139,7 @@ do_compute_shader(BeamformerCtx *ctx, GPUCommandList cmd, BeamformerComputePlan if ((shader_slot + 1) == das_index) pc.output_buffer = pp_das_pointer; else pc.output_buffer = pp_output_pointer; - GPUMemoryBarrierInfo memory_barriers[]= { - // NOTE(rnp): first pass or last stage output - { - .gpu_buffer = &cc->ping_pong_buffer, - .offset = pp_input_pointer - cc->ping_pong_buffer.gpu_pointer, - .size = pp_size, - }, - // NOTE(rnp): output for DAS - { - .gpu_buffer = &cc->ping_pong_buffer, - .offset = pp_das_pointer - cc->ping_pong_buffer.gpu_pointer, - .size = pp_size, - }, - }; - - u32 barrier_count = 1; - if (shader_slot + 1 == das_index) - barrier_count++; - - gpu_command_buffer_memory_barriers(cmd, memory_barriers, barrier_count); + gpu_command_pipeline_barrier(cmd); gpu_command_push_constants(cmd, 0, sizeof(pc), &pc); gpu_command_dispatch_compute(cmd, dispatch); @@ -1186,33 +1167,8 @@ do_compute_shader(BeamformerCtx *ctx, GPUCommandList cmd, BeamformerComputePlan if ((shader_slot + 1) == das_index) pc.output_element_offset = das_output_index * pp_size / element_size; - GPUMemoryBarrierInfo memory_barriers[] = { - // NOTE(rnp): last stage output - { - .gpu_buffer = &cc->ping_pong_buffer, - .offset = pp_input_pointer - cc->ping_pong_buffer.gpu_pointer, - .size = pp_size, - }, - // NOTE(rnp): output for DAS - { - .gpu_buffer = &cc->ping_pong_buffer, - .offset = pp_das_pointer - cc->ping_pong_buffer.gpu_pointer, - .size = pp_size, - }, - }; - GPUMemoryBarrierInfo *barriers = memory_barriers; - - u32 barrier_count = 2; - if (shader_slot == 0) { - barriers++; - barrier_count--; - } - - if ((shader_slot + 1) != das_index) - barrier_count--; - - if (barrier_count) - gpu_command_buffer_memory_barriers(cmd, barriers, barrier_count); + if (shader_slot != 0 || (shader_slot + 1) == das_index) + gpu_command_pipeline_barrier(cmd); gpu_command_push_constants(cmd, 0, sizeof(pc), &pc); gpu_command_dispatch_compute(cmd, dispatch); @@ -1245,31 +1201,7 @@ do_compute_shader(BeamformerCtx *ctx, GPUCommandList cmd, BeamformerComputePlan memory_copy(pc.voxel_transform.E, cp->das_voxel_transform.E, sizeof(pc.voxel_transform)); memory_copy(pc.xdc_transform.E, cp->xdc_transform.E, sizeof(pc.xdc_transform)); - b32 coherent = (cp->shader_descriptors[shader_slot].compile_flags & BeamformerDASCompileFlags_CoherencyWeighting) != 0; - - GPUMemoryBarrierInfo barrier_infos[] = { - { - .gpu_buffer = &cc->ping_pong_buffer, - .offset = pp_das_pointer - cc->ping_pong_buffer.gpu_pointer, - .size = pp_size, - }, - // NOTE(rnp): output clearing pipeline barriers or last DAS pipeline write barriers - { - .gpu_buffer = b, - .offset = frame->buffer_offset, - .size = frame_size, - }, - { - .gpu_buffer = b, - .offset = pc.incoherent_frame - b->gpu_pointer, - .size = iframe_size, - }, - }; - - u32 barrier_count = countof(barrier_infos); - if (!coherent) barrier_count--; - - gpu_command_buffer_memory_barriers(cmd, barrier_infos, barrier_count); + gpu_command_pipeline_barrier(cmd); gpu_command_push_constants(cmd, 0, sizeof(pc), &pc); gpu_command_dispatch_compute(cmd, dispatch); }break; @@ -1289,20 +1221,7 @@ do_compute_shader(BeamformerCtx *ctx, GPUCommandList cmd, BeamformerComputePlan .output_size_z = cp->output_points.z, }; - GPUMemoryBarrierInfo memory_barriers[] = { - { - .gpu_buffer = b, - .offset = frame->buffer_offset, - .size = frame_size, - }, - { - .gpu_buffer = b, - .offset = pc.right_side_buffer - b->gpu_pointer, - .size = iframe_size, - }, - }; - - gpu_command_buffer_memory_barriers(cmd, memory_barriers, countof(memory_barriers)); + gpu_command_pipeline_barrier(cmd); gpu_command_push_constants(cmd, 0, sizeof(pc), &pc); gpu_command_dispatch_compute(cmd, dispatch); }break; @@ -1320,26 +1239,7 @@ do_compute_shader(BeamformerCtx *ctx, GPUCommandList cmd, BeamformerComputePlan if ((shader_slot + 1) == das_index) pc.output_buffer = pp_das_pointer; else pc.output_buffer = pp_output_pointer; - GPUMemoryBarrierInfo memory_barriers[]= { - // NOTE(rnp): first pass or last stage output - { - .gpu_buffer = &cc->ping_pong_buffer, - .offset = pp_input_pointer - cc->ping_pong_buffer.gpu_pointer, - .size = pp_size, - }, - // NOTE(rnp): output for DAS - { - .gpu_buffer = &cc->ping_pong_buffer, - .offset = pp_das_pointer - cc->ping_pong_buffer.gpu_pointer, - .size = pp_size, - }, - }; - - u32 barrier_count = 1; - if (shader_slot + 1 == das_index) - barrier_count++; - - gpu_command_buffer_memory_barriers(cmd, memory_barriers, barrier_count); + gpu_command_pipeline_barrier(cmd); gpu_command_push_constants(cmd, 0, sizeof(pc), &pc); gpu_command_dispatch_compute(cmd, dispatch); diff --git a/beamformer_internal.h b/beamformer_internal.h @@ -124,12 +124,6 @@ typedef struct { } GPUBufferAllocateInfo; typedef struct { - GPUBuffer *gpu_buffer; - u64 offset; - u64 size; -} GPUMemoryBarrierInfo; - -typedef struct { GPUBuffer model; u32 vertex_count; u32 normals_offset; @@ -187,7 +181,7 @@ DEBUG_IMPORT GPUCommandList gpu_command_list_begin(GPUTimeline timeline); DEBUG_IMPORT u64 gpu_command_list_end(GPUCommandList command, VulkanHandle wait_semaphore, VulkanHandle finished_semaphore); DEBUG_IMPORT void gpu_command_bind_pipeline(GPUCommandList command, VulkanHandle pipeline); -DEBUG_IMPORT void gpu_command_buffer_memory_barriers(GPUCommandList command, GPUMemoryBarrierInfo *barriers, u64 count); +DEBUG_IMPORT void gpu_command_pipeline_barrier(GPUCommandList command); DEBUG_IMPORT void gpu_command_clear_buffer(GPUCommandList command, GPUBuffer *buffer, u64 offset, u64 size, u32 clear_word); DEBUG_IMPORT void gpu_command_dispatch_compute(GPUCommandList command, uv3 dispatch); DEBUG_IMPORT void gpu_command_push_constants(GPUCommandList command, u32 offset, u32 size, void *values); diff --git a/vulkan.c b/vulkan.c @@ -2533,51 +2533,28 @@ gpu_command_bind_pipeline(GPUCommandList command, VulkanHandle pipeline) } } -function VkDependencyInfo -vk_dependency_info_from_memory_barrier_info(Arena *arena, VulkanQueue *vq, GPUMemoryBarrierInfo *barriers, u64 count) -{ - u64 valid_count = 0; - VkBufferMemoryBarrier2 *memory_barriers = push_array(arena, VkBufferMemoryBarrier2, count); - for (u64 it = 0; it < count; it++) { - if ValidVulkanHandle(barriers[it].gpu_buffer->handle) { - u32 index = valid_count++; - VulkanBuffer *vb = vk_entity_data(barriers[it].gpu_buffer->handle.value[0], VulkanEntityKind_Buffer); - memory_barriers[index].sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2; - memory_barriers[index].srcStageMask = vq->pipeline_stage_flags; - memory_barriers[index].srcAccessMask = VK_ACCESS_2_MEMORY_WRITE_BIT; - memory_barriers[index].dstStageMask = vq->pipeline_stage_flags; - memory_barriers[index].dstAccessMask = VK_ACCESS_2_MEMORY_READ_BIT; - memory_barriers[index].srcQueueFamilyIndex = vq->queue_family; - memory_barriers[index].dstQueueFamilyIndex = vq->queue_family; - memory_barriers[index].buffer = vb->buffer; - memory_barriers[index].offset = barriers[it].offset; - memory_barriers[index].size = barriers[it].size; - } - } - - VkDependencyInfo result = { - .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO, - .bufferMemoryBarrierCount = valid_count, - .pBufferMemoryBarriers = memory_barriers, - }; - return result; -} - DEBUG_IMPORT void -gpu_command_buffer_memory_barriers(GPUCommandList command, GPUMemoryBarrierInfo *barriers, u64 count) +gpu_command_pipeline_barrier(GPUCommandList command) { if (command.value) { VulkanContext *vk = vulkan_context; VulkanCommandBuffer *vcb = vk_entity_data(command.value, VulkanEntityKind_CommandBuffer); VulkanQueue *vq = vk->queues[vcb->timeline]; - Temp scratch; - DeferLoop(take_lock(&vk->arena_lock, -1), release_lock(&vk->arena_lock)) - DeferLoop(scratch = temp_begin(vk->arena), temp_end(scratch)) - { - VkDependencyInfo dependancy_info = vk_dependency_info_from_memory_barrier_info(scratch.arena, vq, barriers, count); - vkCmdPipelineBarrier2(vk_command_buffer(command), &dependancy_info); - } + VkMemoryBarrier2 memory_barrier = { + .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2, + .srcStageMask = vq->pipeline_stage_flags, + .srcAccessMask = VK_ACCESS_2_MEMORY_WRITE_BIT, + .dstStageMask = vq->pipeline_stage_flags, + .dstAccessMask = VK_ACCESS_2_MEMORY_READ_BIT, + }; + + VkDependencyInfo dependency_info = { + .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO, + .pMemoryBarriers = &memory_barrier, + .memoryBarrierCount = 1, + }; + vkCmdPipelineBarrier2(vk_command_buffer(command), &dependency_info); } }