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:
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)) \