ogl_beamforming

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

Commit: 624474e12fd652fa54502ae39511f88577ecbdbd
Parent: 34ed5585c8ee66a1f734f7f9fe3c1b2fbf9b104c
Author: Randy Palamar
Date:   Fri, 21 Aug 2026 06:40:17 -0700

core/gpu: introduce helper for building gpu temp arena

there was a lot of fiddly math involved in using the gpu temp
arena with size calculation and pointer assignment happening in
different places in the code. furthermore it was very annoying to
assign one allocation to multiple shaders.

instead of that mess, introduce an immediate mode api which can
track all allocations during a building phase then go back and
assign all the pointers after allocating the GPU buffer. this is
much less error prone and nicer to use.

in time I will also migrate the other shader parameter allocations
into this temp arena as well.

Diffstat:
Mbase_types.h | 2--
Mbeamformer.c | 2+-
Mbeamformer.meta | 7++-----
Mbeamformer_core.c | 224+++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------------
Mbeamformer_internal.h | 5++---
Mgenerated/beamformer.c | 91+++++++++++++++++++++++++++++++++++--------------------------------------------
Mshaders/das.glsl | 6+++---
Mshaders/decode.glsl | 10++++------
Mui.c | 2+-
Mutil.c | 39---------------------------------------
Mvulkan.c | 18+++++++++---------
11 files changed, 223 insertions(+), 183 deletions(-)

diff --git a/base_types.h b/base_types.h @@ -119,8 +119,6 @@ typedef union { f32 E[16]; } m4; -typedef struct {u8 *start, *end;} BumpArena; - typedef enum { ArenaFlag_NoChain = 1 << 0, diff --git a/beamformer.c b/beamformer.c @@ -218,7 +218,7 @@ beamformer_init(BeamformerInput *input) .timelines_used = timelines, .label = str8("BeamformedData"), }; - gpu_buffer_allocate(cs->backlog.buffer, &allocate_info); + gpu_buffer_allocate(cs->backlog.buffer, allocate_info); if (cs->backlog.buffer->size > 0) break; } diff --git a/beamformer.meta b/beamformer.meta @@ -6,7 +6,6 @@ @Constant(16) MaxComputeShaderStages @Constant(16) MaxParameterBlocks @Constant(3) MaxRawDataFramesInFlight -@Constant(65536) MaxHadamardElements @Enumeration ShaderResourceKind { @@ -272,8 +271,6 @@ [FocalVectors focal_vectors V2 MaxChannelCount] [SparseElements sparse_elements S16 MaxChannelCount] [TransmitReceiveOrientations transmit_receive_orientations U16 MaxChannelCount] - [DASHadamard das_hadamard F16 MaxHadamardElements] - [DecodeHadamard decode_hadamard F16 MaxHadamardElements] } @Expand(ComputeArrayParametersTable) @Enumeration(`$(name_upper)`) ComputeArrayParametersField @@ -360,7 +357,7 @@ @Bake { - [HadamardBuffer U64] + [Hadamard U64] [DecodeMode U32] [OutputChannelStride U32] [OutputSampleStride U32] @@ -420,7 +417,6 @@ @Shader(das.glsl) DAS { @Constant MaxChannelCount - @Constant MaxHadamardElements @Enumeration AcquisitionKind @Enumeration InterpolationMode @@ -439,6 +435,7 @@ { [ArrayParameters U64] [IncoherentFrame U64] + [Hadamard U64] [AcquisitionKind U32] [Sparse B32] [AcquisitionCount S32] diff --git a/beamformer_core.c b/beamformer_core.c @@ -101,6 +101,36 @@ typedef struct { u64 count; } BeamformerComputeGraph; +#define GPU_RESOURCE_HASH_TABLE_COUNT 256 +typedef struct U64ReferenceNode U64ReferenceNode; +struct U64ReferenceNode {u64 *v; U64ReferenceNode *next;}; + +typedef struct GPUResource GPUResource; +struct GPUResource { + str8 name; + u64 size; + u64 offset; + u64 alignment; + + void *data; + + u64 hash; + + U64ReferenceNode *pointer_store_list; + + GPUResource *next; + GPUResource *hash_next, *hash_prev; +}; +typedef struct {GPUResource *first, *last;} GPUResourceHashBucket; + +typedef struct { + Arena *arena; + u64 position; + + GPUResource *resource_list; + GPUResourceHashBucket hash_table[GPU_RESOURCE_HASH_TABLE_COUNT]; +} GPUResourceBuilder; + read_only global BeamformerFrame beamformer_nil_frame; read_only global BeamformerComputePlan beamformer_nil_compute_plan; @@ -204,6 +234,7 @@ beamformer_compute_plan_release(BeamformerComputeContext *cc, u32 block) BeamformerComputePlan *cp = cc->compute_plans[block]; if (cp) { gpu_buffer_release(&cp->array_parameters); + gpu_buffer_release(&cp->gpu_temp_arena); for (u32 i = 0; i < countof(cp->filters); i++) gpu_buffer_release(&cp->filters[i].buffer); cc->compute_plans[block] = 0; @@ -211,6 +242,99 @@ beamformer_compute_plan_release(BeamformerComputeContext *cc, u32 block) } } +function GPUResource * +gpu_resource_from_hash(GPUResourceBuilder *rb, u64 hash) +{ + GPUResource *result = 0; + + GPUResourceHashBucket *hb = rb->hash_table + (hash % GPU_RESOURCE_HASH_TABLE_COUNT); + for (GPUResource *r = hb->first; r; r = r->hash_next) { + if (hash == r->hash) { + result = r; + break; + } + } + + return result; +} + +typedef struct { + str8 name; + u64 align; + u64 size; + u64 *store; + void *data; +} GPUResourcePushInfo; +#define gpu_resource_push(rb, t, count, ...) gpu_resource_push_(rb, (GPUResourcePushInfo){\ + .align = Max(alignof(t), 16), \ + .size = sizeof(t) * count, \ + __VA_ARGS__}) + +function void +gpu_resource_push_(GPUResourceBuilder *rb, GPUResourcePushInfo info) +{ + assert(info.store && info.size > 0 && info.name.length > 0 && IsPowerOfTwo(info.align)); + + u64 hash = u64_hash_from_str8(info.name); + GPUResource *r = gpu_resource_from_hash(rb, hash); + if (!r) { + r = push_struct(rb->arena, GPUResource); + GPUResourceHashBucket *hb = rb->hash_table + (hash % GPU_RESOURCE_HASH_TABLE_COUNT); + DLLInsert(0, hb->first, hb->last, r, hash_next, hash_prev); + SLLStackPush(rb->resource_list, r, next); + } + + r->hash = hash; + r->name = info.name; + r->alignment = Max(16, info.align); + r->offset = AlignUpPowerOfTwo(rb->position, r->alignment); + r->size = info.size; + + // NOTE(rnp): if this is a new resource and no data is provided it is likely + // a temporary GPU side buffer. if this is not a new resource and no data + // is provided then maybe it is shared and someone else already provided it + if (info.data) r->data = info.data; + + U64ReferenceNode *output = push_struct(rb->arena, U64ReferenceNode); + output->v = info.store; + SLLStackPush(r->pointer_store_list, output, next); + + rb->position = r->offset + r->size; +} + +function GPUResourceBuilder * +gpu_resource_build_begin(Arena *arena) +{ + GPUResourceBuilder *result = push_struct(arena, GPUResourceBuilder); + result->arena = arena; + return result; +} + +function void +gpu_resource_build_end(GPUResourceBuilder *rb, GPUBuffer *buffer) +{ + u64 size = gpu_round_up_to_sync_size(rb->position, 64); + if (size != (u64)buffer->size) { + gpu_buffer_allocate(buffer, (GPUBufferAllocateInfo){ + .size = size, + .flags = VulkanUsageFlag_HostReadWrite|VulkanUsageFlag_TransferDestination, + .label = push_str8_f(rb->arena, "GPU Temp Arena [%p]", buffer), + }); + } + + ////////////////////////////////////// + // NOTE(rnp): fill in pointer outputs + for (GPUResource *r = rb->resource_list; r; r = r->next) + for (U64ReferenceNode *op = r->pointer_store_list; op; op = op->next) + *op->v = buffer->gpu_pointer + r->offset; + + ////////////////////////////////////// + // NOTE(rnp): upload data + for (GPUResource *r = rb->resource_list; r; r = r->next) + if (r->data) + gpu_buffer_range_upload(buffer, r->data, r->offset, r->size, 0); +} + function BeamformerComputePlan * beamformer_compute_plan_for_block(BeamformerComputeContext *cc, u32 block, Arena *arena) { @@ -234,7 +358,7 @@ beamformer_compute_plan_for_block(BeamformerComputeContext *cc, u32 block, Arena .flags = VulkanUsageFlag_HostReadWrite, .label = stream_to_str8(&label), }; - gpu_buffer_allocate(&result->array_parameters, &allocate_info); + gpu_buffer_allocate(&result->array_parameters, allocate_info); assert((result->array_parameters.gpu_pointer & 63) == 0); } return result; @@ -288,7 +412,7 @@ beamformer_filter_update(BeamformerFilter *f, BeamformerFilterParameters fp, u32 .flags = VulkanUsageFlag_HostReadWrite, .label = label, }; - gpu_buffer_allocate(&f->buffer, &allocate_info); + gpu_buffer_allocate(&f->buffer, allocate_info); } gpu_buffer_range_upload(&f->buffer, filter, 0, byte_size, 0); @@ -305,19 +429,6 @@ das_valid_points(iv3 points) return result; } -function void -beamformer_update_hadamard(BeamformerComputePlan *cp, BeamformerComputeArrayParametersField output_field, - i32 order, b32 row_major, Arena *arena) -{ - f16 *hadamard = make_hadamard_transpose(arena, order, row_major); - if (hadamard) { - u64 offset = beamformer_compute_array_parameter_offsets[output_field]; - u64 size = beamformer_compute_array_parameter_sizes[output_field] / BeamformerMaxHadamardElements; - size *= order * order; - gpu_buffer_range_upload(&cp->array_parameters, hadamard, offset, size, 0); - } -} - function GPUBuffer * beamformer_gpu_buffer_from_frame(BeamformerFrame *frame) { @@ -518,10 +629,7 @@ plan_compute_pipeline(BeamformerComputePlan *cp, BeamformerParameterBlock *pb, A }; ////////////////////////////////////// - // NOTE(rnp): First Pass: build initial graph and insert hard layout constraints. - // We can also calculate any temporary space we need so we can patch pointers into - // bake parameters in the final pass. - i64 temporary_buffer_space = 0; + // NOTE(rnp): First Pass: build initial graph and insert hard layout constraints BeamformerComputeGraph graph = {0}; BeamformerComputeGraphNode *root_node = push_compute_graph_node(&graph, BeamformerShaderKind_Count, scratch); root_node->input_data_kind = input_data_kind; @@ -588,11 +696,8 @@ plan_compute_pipeline(BeamformerComputePlan *cp, BeamformerParameterBlock *pb, A node->output_data_kind = das_data_kind; // NOTE(rnp): insert implicit CoherencyWeighting node - if (pb->parameters.coherency_weighting) { - temporary_buffer_space = gpu_round_up_to_sync_size(temporary_buffer_space, 64); - temporary_buffer_space += beamformer_incoherent_frame_byte_size(cp->output_points, node->output_data_kind); + if (pb->parameters.coherency_weighting) node = push_compute_graph_node(&graph, BeamformerShaderKind_CoherencyWeighting, scratch); - } }break; default:{}break; @@ -661,24 +766,7 @@ plan_compute_pipeline(BeamformerComputePlan *cp, BeamformerParameterBlock *pb, A cp->first_image_shader_index = 0; cp->pipeline.shader_count = 0; - // NOTE(rnp): realloc temporary buffer if needed. we do want this to shrink - // when it can but if we get here and the size didn't change save some time - if (temporary_buffer_space != cp->gpu_temp_arena.size) { - gpu_buffer_allocate(&cp->gpu_temp_arena, &(GPUBufferAllocateInfo){ - .size = temporary_buffer_space, - .flags = VulkanUsageFlag_TransferDestination, - .label = push_str8_f(scratch, "GPU Temp Arena [%p]", cp), - }); - } - - BumpArena gpu_arena = bump_arena_from_buffer((void *)cp->gpu_temp_arena.gpu_pointer, cp->gpu_temp_arena.size); - u64 incoherent_buffer = 0; - if (pb->parameters.coherency_weighting) { - incoherent_buffer = (u64)gpu_arena_alloc(&gpu_arena, - .size = beamformer_incoherent_frame_byte_size(cp->output_points, das_data_kind), - .align = gpu_round_up_to_sync_size(1, 64)); - } - + GPUResourceBuilder *resource_builder = gpu_resource_build_begin(scratch); for (BeamformerComputeGraphNode *node = root_node->next; node; node = node->next) { assert(node->prev->output_data_kind == node->input_data_kind); assert(bv3_all(iv3_equal(node->prev->output_stride, node->input_stride))); @@ -694,9 +782,6 @@ plan_compute_pipeline(BeamformerComputePlan *cp, BeamformerParameterBlock *pb, A case BeamformerShaderKind_Decode:{ BeamformerDecodeBakeParameters *db = &sd->bake.Decode; - db->HadamardBuffer = cp->array_parameters.gpu_pointer - + offsetof(BeamformerComputeArrayParameters, decode_hadamard); - u32 decode_sample_count = input_sample_count; db->DecodeMode = pb->parameters.decode_mode; db->TransmitCount = pb->parameters.acquisition_count; @@ -752,6 +837,12 @@ plan_compute_pipeline(BeamformerComputePlan *cp, BeamformerParameterBlock *pb, A sd->dispatch.y = (u32)ceil_f32((f32)chunk_channel_count / (f32)sd->layout.y); sd->dispatch.z = 1; } + + u32 order = pb->parameters.acquisition_count; + gpu_resource_push(resource_builder, f16, order * order, + .data = make_hadamard_transpose(scratch, order, use_coop_matrix), + .name = str8("hadamard"), + .store = &db->Hadamard); }break; case BeamformerShaderKind_Demodulate: @@ -825,14 +916,11 @@ plan_compute_pipeline(BeamformerComputePlan *cp, BeamformerParameterBlock *pb, A db->FocusDepth = pb->parameters.focal_vector.E[1]; db->ReadiGroupCount = pb->parameters.readi_group_count; db->ArrayParameters = cp->array_parameters.gpu_pointer; - db->IncoherentFrame = incoherent_buffer; db->OutputSizeX = cp->output_points.x; db->OutputSizeY = cp->output_points.y; db->OutputSizeZ = cp->output_points.z; db->TransmitReceiveOrientation = pb->parameters.transmit_receive_orientation; - cp->readi_group = pb->parameters.readi_group; - // NOTE(rnp): old gcc will miscompile an assignment memory_copy(cp->xdc_transform.E, pb->parameters.xdc_transform.E, sizeof(cp->xdc_transform)); @@ -852,6 +940,22 @@ plan_compute_pipeline(BeamformerComputePlan *cp, BeamformerParameterBlock *pb, A sd->compile_flags |= BeamformerDASCompileFlags_CoherencyWeighting * pb->parameters.coherency_weighting; sd->layout = layout_for_output(cp->output_points); sd->dispatch = dispatch_for_output(sd->layout, cp->output_points); + + if (pb->parameters.coherency_weighting) { + gpu_resource_push(resource_builder, u32, 0, + .store = &db->IncoherentFrame, + .size = beamformer_incoherent_frame_byte_size(cp->output_points, das_data_kind), + .name = str8("incoherent_buffer")); + } + + cp->readi_group = pb->parameters.readi_group; + if (db->ReadiGroupCount > 1) { + u32 order = db->ReadiGroupCount; + gpu_resource_push(resource_builder, f16, order * order, + .store = &db->Hadamard, + .data = make_hadamard_transpose(scratch, order, 0), + .name = str8("readi_hadamard")); + } }break; case BeamformerShaderKind_CoherencyWeighting:{ @@ -861,9 +965,12 @@ plan_compute_pipeline(BeamformerComputePlan *cp, BeamformerParameterBlock *pb, A sd->dispatch = dispatch_for_output(sd->layout, cp->output_points); BeamformerCoherencyWeightingBakeParameters *cw = &sd->bake.CoherencyWeighting; - cw->Scale = 1.f; - cw->OutputVoxels = cp->output_points.x * cp->output_points.y * cp->output_points.z; - cw->IncoherentSum = incoherent_buffer; + cw->Scale = 1.f; + cw->OutputVoxels = cp->output_points.x * cp->output_points.y * cp->output_points.z; + gpu_resource_push(resource_builder, u32, 0, + .store = &cw->IncoherentSum, + .size = beamformer_incoherent_frame_byte_size(cp->output_points, das_data_kind), + .name = str8("incoherent_buffer")); }break; case BeamformerShaderKind_Reshape:{ @@ -920,6 +1027,8 @@ plan_compute_pipeline(BeamformerComputePlan *cp, BeamformerParameterBlock *pb, A if (cp->first_image_shader_index == 0) cp->first_image_shader_index = cp->pipeline.shader_count; + + gpu_resource_build_end(resource_builder, &cp->gpu_temp_arena); } function void @@ -1143,7 +1252,7 @@ beamformer_commit_parameter_block(BeamformerCtx *ctx, BeamformerComputePlan *cp, .export = cuda ? &ctx->compute_context.ping_pong_export_handle : 0, .label = str8("PingPongBuffer"), }; - gpu_buffer_allocate(&ctx->compute_context.ping_pong_buffer, &allocate_info); + gpu_buffer_allocate(&ctx->compute_context.ping_pong_buffer, allocate_info); BeamformerShaderResourceInfo shader_resource_infos[] = { { @@ -1160,17 +1269,6 @@ beamformer_commit_parameter_block(BeamformerCtx *ctx, BeamformerComputePlan *cp, if (cuda) { } } - - if (pb->parameters.decode_mode != BeamformerDecodeMode_None && - cp->hadamard_order != (i32)cp->acquisition_count) - { - beamformer_update_hadamard(cp, BeamformerComputeArrayParametersField_DecodeHadamard, - cp->acquisition_count, gpu_info()->cooperative_matrix, scratch); - if (pb->parameters.readi_group_count > 1) - beamformer_update_hadamard(cp, BeamformerComputeArrayParametersField_DASHadamard, - pb->parameters.readi_group_count, 0, scratch); - cp->hadamard_order = cp->acquisition_count; - } }break; case BeamformerParameterBlockRegion_ChannelMapping:{ @@ -1703,7 +1801,7 @@ DEBUG_EXPORT BEAMFORMER_RF_UPLOAD_FN(beamformer_rf_upload) .flags = VulkanUsageFlag_HostReadWrite, .label = str8("RawRFBuffer"), }; - gpu_buffer_allocate(&rf->buffer, &allocate_info); + gpu_buffer_allocate(&rf->buffer, allocate_info); } u64 slot = rf->insertion_index % countof(rf->upload_complete_values); diff --git a/beamformer_internal.h b/beamformer_internal.h @@ -116,8 +116,8 @@ typedef struct { VulkanUsageFlags flags; // NOTE(rnp): only required if buffer will be used on multiple timelines - GPUTimeline *timelines_used; u32 timeline_count; + GPUTimeline *timelines_used; OSHandle *export; @@ -145,7 +145,7 @@ DEBUG_IMPORT void vk_load(OSLibrary vulkan, Stream *error); DEBUG_IMPORT GPUInfo *gpu_info(void); -DEBUG_IMPORT void gpu_buffer_allocate(GPUBuffer *, GPUBufferAllocateInfo *info); +DEBUG_IMPORT void gpu_buffer_allocate(GPUBuffer *, GPUBufferAllocateInfo info); DEBUG_IMPORT void gpu_buffer_release(GPUBuffer *); DEBUG_IMPORT void gpu_buffer_range_upload(GPUBuffer *, void *data, u64 offset, u64 size, b32 non_temporal); DEBUG_IMPORT void gpu_buffer_range_download(void *output, GPUBuffer *, u64 source_offset, u64 size, b32 non_temporal); @@ -299,7 +299,6 @@ struct BeamformerComputePlan { BeamformerContrastMode contrast_mode; u32 rf_size; - i32 hadamard_order; b32 iq_pipeline; m4 ui_voxel_transform; diff --git a/generated/beamformer.c b/generated/beamformer.c @@ -11,7 +11,6 @@ #define BeamformerMaxComputeShaderStages (16) #define BeamformerMaxParameterBlocks (16) #define BeamformerMaxRawDataFramesInFlight (3) -#define BeamformerMaxHadamardElements (65536) typedef enum { BeamformerShaderResourceKind_Buffer = 0, @@ -118,8 +117,6 @@ typedef enum { BeamformerComputeArrayParametersField_FocalVectors = 0, BeamformerComputeArrayParametersField_SparseElements = 1, BeamformerComputeArrayParametersField_TransmitReceiveOrientations = 2, - BeamformerComputeArrayParametersField_DASHadamard = 3, - BeamformerComputeArrayParametersField_DecodeHadamard = 4, BeamformerComputeArrayParametersField_Count, } BeamformerComputeArrayParametersField; @@ -177,7 +174,7 @@ typedef enum { } BeamformerShaderKind; typedef struct { - u64 HadamardBuffer; + u64 Hadamard; u32 DecodeMode; u32 OutputChannelStride; u32 OutputSampleStride; @@ -209,6 +206,7 @@ typedef struct { typedef struct { u64 ArrayParameters; u64 IncoherentFrame; + u64 Hadamard; u32 AcquisitionKind; b32 Sparse; i32 AcquisitionCount; @@ -466,8 +464,6 @@ typedef struct { v2 focal_vectors[BeamformerMaxChannelCount]; i16 sparse_elements[BeamformerMaxChannelCount]; u16 transmit_receive_orientations[BeamformerMaxChannelCount]; - f16 das_hadamard[BeamformerMaxHadamardElements]; - f16 decode_hadamard[BeamformerMaxHadamardElements]; } BeamformerComputeArrayParameters; typedef union { @@ -482,16 +478,12 @@ read_only global u32 beamformer_compute_array_parameter_sizes[] = { sizeof(v2) * BeamformerMaxChannelCount, sizeof(i16) * BeamformerMaxChannelCount, sizeof(u16) * BeamformerMaxChannelCount, - sizeof(f16) * BeamformerMaxHadamardElements, - sizeof(f16) * BeamformerMaxHadamardElements, }; read_only global u32 beamformer_compute_array_parameter_offsets[] = { offsetof(BeamformerComputeArrayParameters, focal_vectors), offsetof(BeamformerComputeArrayParameters, sparse_elements), offsetof(BeamformerComputeArrayParameters, transmit_receive_orientations), - offsetof(BeamformerComputeArrayParameters, das_hadamard), - offsetof(BeamformerComputeArrayParameters, decode_hadamard), }; read_only global u8 beamformer_data_kind_element_size[] = { @@ -651,29 +643,30 @@ read_only global MetaStructMember *meta_struct_members_by_id[] = { {18, 52, 1, 0}, }, (MetaStructMember []){ - {17, 0, 1, 0}, - {17, 8, 1, 0}, - {18, 16, 1, 0}, - {14, 20, 1, 0}, - {10, 24, 1, 0}, - {10, 28, 1, 0}, - {10, 32, 1, 0}, - {10, 36, 1, 0}, - {8, 40, 1, 0}, - {8, 44, 1, 0}, - {8, 48, 1, 0}, - {8, 52, 1, 0}, - {18, 56, 1, 0}, - {8, 60, 1, 0}, - {14, 64, 1, 0}, - {18, 68, 1, 0}, - {14, 72, 1, 0}, - {8, 76, 1, 0}, - {8, 80, 1, 0}, - {18, 84, 1, 0}, - {18, 88, 1, 0}, - {18, 92, 1, 0}, - {18, 96, 1, 0}, + {17, 0, 1, 0}, + {17, 8, 1, 0}, + {17, 16, 1, 0}, + {18, 24, 1, 0}, + {14, 28, 1, 0}, + {10, 32, 1, 0}, + {10, 36, 1, 0}, + {10, 40, 1, 0}, + {10, 44, 1, 0}, + {8, 48, 1, 0}, + {8, 52, 1, 0}, + {8, 56, 1, 0}, + {8, 60, 1, 0}, + {18, 64, 1, 0}, + {8, 68, 1, 0}, + {14, 72, 1, 0}, + {18, 76, 1, 0}, + {14, 80, 1, 0}, + {8, 84, 1, 0}, + {8, 88, 1, 0}, + {18, 92, 1, 0}, + {18, 96, 1, 0}, + {18, 100, 1, 0}, + {18, 104, 1, 0}, }, (MetaStructMember []){ {17, 0, 1, 0}, @@ -695,7 +688,7 @@ read_only global MetaStructMember *meta_struct_members_by_id[] = { read_only global str8 *meta_struct_member_names_by_id[] = { (str8 []){ - str8_comp("HadamardBuffer"), + str8_comp("Hadamard"), str8_comp("DecodeMode"), str8_comp("OutputChannelStride"), str8_comp("OutputSampleStride"), @@ -725,6 +718,7 @@ read_only global str8 *meta_struct_member_names_by_id[] = { (str8 []){ str8_comp("ArrayParameters"), str8_comp("IncoherentFrame"), + str8_comp("Hadamard"), str8_comp("AcquisitionKind"), str8_comp("Sparse"), str8_comp("AcquisitionCount"), @@ -768,7 +762,7 @@ read_only global str8 *meta_struct_member_names_by_id[] = { read_only global MetaStructInfo meta_struct_info_by_id[] = { {str8_comp("DecodeBakeParameters"), 11, 48, 0}, {str8_comp("FilterBakeParameters"), 13, 56, 0}, - {str8_comp("DASBakeParameters"), 23, 100, 0}, + {str8_comp("DASBakeParameters"), 24, 108, 0}, {str8_comp("CoherencyWeightingBakeParameters"), 3, 16, 0}, {str8_comp("ReshapeBakeParameters"), 9, 36, 0}, }; @@ -871,7 +865,6 @@ read_only global str8 beamformer_shader_global_header_strings[] = { "};\n" "\n"), str8_comp("#define MaxChannelCount (256)\n\n"), - str8_comp("#define MaxHadamardElements (65536)\n\n"), str8_comp("" "#define AcquisitionKind_FORCES 0\n" "#define AcquisitionKind_UFORCES 1\n" @@ -899,18 +892,14 @@ read_only global str8 beamformer_shader_global_header_strings[] = { "\n"), str8_comp("" "struct ComputeArrayParameters {\n" - " f32vec2 focal_vectors[MaxChannelCount];\n" - " int16_t sparse_elements[MaxChannelCount];\n" - " uint16_t transmit_receive_orientations[MaxChannelCount];\n" - " float16_t das_hadamard[MaxHadamardElements];\n" - " float16_t decode_hadamard[MaxHadamardElements];\n" + " f32vec2 focal_vectors[MaxChannelCount];\n" + " int16_t sparse_elements[MaxChannelCount];\n" + " uint16_t transmit_receive_orientations[MaxChannelCount];\n" "};\n" "layout(std430, buffer_reference) buffer ComputeArrayParametersReference {\n" - " f32vec2 focal_vectors[MaxChannelCount];\n" - " int16_t sparse_elements[MaxChannelCount];\n" - " uint16_t transmit_receive_orientations[MaxChannelCount];\n" - " float16_t das_hadamard[MaxHadamardElements];\n" - " float16_t decode_hadamard[MaxHadamardElements];\n" + " f32vec2 focal_vectors[MaxChannelCount];\n" + " int16_t sparse_elements[MaxChannelCount];\n" + " uint16_t transmit_receive_orientations[MaxChannelCount];\n" "};\n" "\n"), str8_comp("" @@ -995,18 +984,18 @@ read_only global b8 beamformer_shader_primitive_is_vertex[] = { read_only global i32 *beamformer_shader_header_vectors[] = { (i32 []){0, 1, 2}, (i32 []){3, 4, 5, 6}, - (i32 []){7, 8, 9, 10, 11, 3, 4, 12, 13, 14}, - (i32 []){15}, - (i32 []){16, 17}, + (i32 []){7, 8, 9, 10, 3, 4, 11, 12, 13}, + (i32 []){14}, + (i32 []){15, 16}, 0, + (i32 []){17}, (i32 []){18}, - (i32 []){19}, }; read_only global i32 beamformer_shader_header_vector_lengths[] = { 3, 4, - 10, + 9, 1, 2, 0, diff --git a/shaders/das.glsl b/shaders/das.glsl @@ -43,6 +43,8 @@ layout(std430, buffer_reference) buffer IncoherentOutput { f32 x[]; }; +layout(std430, buffer_reference) buffer F16 { f16 x[]; }; + #define RX_ORIENTATION(tx_rx) bitfieldExtract((tx_rx), 0, 4) #define TX_ORIENTATION(tx_rx) bitfieldExtract((tx_rx), 4, 4) @@ -322,8 +324,6 @@ RESULT_TYPE READI_FORCES(const vec3 xdc_world_point) { RESULT_TYPE result = RESULT_TYPE(0); - ComputeArrayParametersReference dp = ComputeArrayParametersReference(ArrayParameters); - float z_delta_squared = xdc_world_point.z * xdc_world_point.z; float transmit_y_delta = xdc_world_point.y - xdc_element_pitch.y * ChannelCount / 2; float transmit_yz_squared = transmit_y_delta * transmit_y_delta + z_delta_squared; @@ -347,7 +347,7 @@ RESULT_TYPE READI_FORCES(const vec3 xdc_world_point) // sequential elements. The first element in each group is beamformed using the first // acquisition, the second element in each group is beamformed using the second acquisition, etc. for (s32 tx_group = 0; tx_group < s32(ReadiGroupCount); tx_group++) { - f32 group_apodization = apodization * dp.das_hadamard[hadamard_offset + tx_group]; + f32 group_apodization = apodization * F16(Hadamard).x[hadamard_offset + tx_group]; s32 rf_offset = channel_rf_offset; for (f32 tx_event = 0; tx_event < f32(AcquisitionCount); tx_event += 1.f) { diff --git a/shaders/decode.glsl b/shaders/decode.glsl @@ -13,9 +13,7 @@ layout(std430, buffer_reference, buffer_reference_align = 64) restrict writeonly OutputDataType x[]; }; -layout(std430, buffer_reference, buffer_reference_align = 64) restrict readonly buffer Hadamard { - f16 x[]; -}; +layout(std430, buffer_reference) buffer F16 { f16 x[]; }; OutputDataType sample_rf_data(u32 index) { @@ -50,7 +48,7 @@ void run_decode_large(void) for (s32 i = 0; i < ToProcess; i++) result[i] = OutputDataType(0); - Hadamard h = Hadamard(HadamardBuffer); + F16 h = F16(Hadamard); for (s32 j = 0; j < TransmitCount; j++) { OutputDataType s = OutputDataType(rf[gl_LocalInvocationID.y][j]); for (s32 i = 0; i < ToProcess; i++) @@ -94,7 +92,7 @@ void run_decode_coop(void) u32 offset = ChunkChannelCount * TransmitCount * time_sample; - Hadamard h = Hadamard(HadamardBuffer); + F16 h = F16(Hadamard); for (u32 k = 0; k < TransmitCount; k += CooperativeMatrixK) { u32 rf_tile_row = CooperativeMatrixM * tile_index.y; u32 rf_tile_col = k; @@ -133,7 +131,7 @@ void run_decode_small(void) for (s32 j = 0; j < TransmitCount; j++) result[j] = OutputDataType(0); - Hadamard h = Hadamard(HadamardBuffer); + F16 h = F16(Hadamard); for (s32 i = 0; i < TransmitCount; i++) { OutputDataType s = OutputDataType(rf[i]); for (s32 j = 0; j < TransmitCount; j++) { diff --git a/ui.c b/ui.c @@ -851,7 +851,7 @@ beamformer_ui_frame_view_copy_frame(BeamformerFrameView *new, BeamformerFrameVie .flags = VulkanUsageFlag_TransferDestination, .label = stream_to_str8(&sb), }; - gpu_buffer_allocate(&new->copy_buffer, &allocate_info); + gpu_buffer_allocate(&new->copy_buffer, allocate_info); GPUBuffer *buffer = beamformer_gpu_buffer_from_frame(&old->frame); assert(buffer); diff --git a/util.c b/util.c @@ -120,22 +120,6 @@ round_up_to(i64 value, i64 multiple) return result; } -function BumpArena -bump_arena_from_buffer(void *base, i64 size) -{ - BumpArena result = {.start = base}; - result.end = result.start + size; - return result; -} - -function void * -bump_arena_aligned_start(BumpArena a, u64 alignment) -{ - u64 padding = -(u64)a.start & (alignment - 1); - u8 *result = a.start + padding; - return result; -} - typedef enum { ArenaAllocateFlags_NoZero = 1 << 0, } ArenaAllocateFlags; @@ -147,29 +131,6 @@ typedef struct { ArenaAllocateFlags flags; } ArenaAllocateInfo; -#define bump_arena_alloc(a, ...) bump_arena_alloc_(a, (ArenaAllocateInfo){.align = 8, .count = 1, __VA_ARGS__}) -#define gpu_arena_alloc(a, ...) bump_arena_alloc_(a, (ArenaAllocateInfo){.flags = ArenaAllocateFlags_NoZero, .align = 8, .count = 1, __VA_ARGS__}) -#define bump_push_array(a, t, n, ...) (t *)bump_arena_alloc(a, .size = sizeof(t), .align = alignof(t), .count = n, __VA_ARGS__) -#define bump_push_array_no_zero(a, t, n, ...) (t *)bump_arena_alloc(a, .size = sizeof(t), .align = alignof(t), .count = n, .flags = ArenaAllocateFlags_NoZero, __VA_ARGS__) -#define bump_push_struct(a, t, ...) bump_push_array(a, t, 1, __VA_ARGS__) -#define bump_push_struct_no_zero(a, t, ...) bump_push_array_no_zero(a, t, 1, __VA_ARGS__) - -function void * -bump_arena_alloc_(BumpArena *a, ArenaAllocateInfo info) -{ - void *result = 0; - if (a->start) { - u8 *start = bump_arena_aligned_start(*a, info.align); - i64 available = a->end - start; - assert((available >= 0 && info.count <= available / info.size)); - a->start = start + info.count * info.size; - result = start; - if ((info.flags & ArenaAllocateFlags_NoZero) == 0) - result = memory_clear(start, 0, info.count * info.size); - } - return result; -} - function u8 * arena_commit(Arena *a, i64 size) { diff --git a/vulkan.c b/vulkan.c @@ -1980,28 +1980,28 @@ gpu_buffer_release(GPUBuffer *b) } DEBUG_IMPORT void -gpu_buffer_allocate(GPUBuffer *b, GPUBufferAllocateInfo *info) +gpu_buffer_allocate(GPUBuffer *b, GPUBufferAllocateInfo info) { VulkanContext *vk = vulkan_context; gpu_buffer_release(b); - assert(info->size >= 0); + assert(info.size >= 0); - if (info->size > 0) { + if (info.size > 0) { VulkanEntity *e = vk_entity_allocate(VulkanEntityKind_Buffer); VulkanBufferAllocateInfo vulkan_buffer_allocate_info = { .gpu_buffer = b, - .size = (u64)info->size, - .flags = info->flags, + .size = (u64)info.size, + .flags = info.flags, .index_type = VK_INDEX_TYPE_NONE_KHR, - .label = info->label, - .export = info->export, + .label = info.label, + .export = info.export, }; u32 queue_index_hit_count[VulkanQueueKind_Count] = {0}; - for (u32 it = 0; it < info->timeline_count; it++) - queue_index_hit_count[vk->queue_indices[info->timelines_used[it]]]++; + for (u32 it = 0; it < info.timeline_count; it++) + queue_index_hit_count[vk->queue_indices[info.timelines_used[it]]]++; for EachElement(queue_index_hit_count, it) { if (queue_index_hit_count[it] > 0) {