Commit: 5d25b3e6c3e82a494d8711fcf387fab9fe9e8fb7
Parent: a4c7561750ffdfaf52ef28da28e44f3756d8b254
Author: Tyler Henry
Date: Fri, 31 Jul 2026 14:13:02 -0600
lib: add bulk frame export
closes #49
Diffstat:
4 files changed, 48 insertions(+), 15 deletions(-)
diff --git a/beamformer_core.c b/beamformer_core.c
@@ -1432,18 +1432,26 @@ complete_queue(BeamformerCtx *ctx, BeamformWorkQueue *q, Arena *arena)
BeamformerExportContext *ec = &work->export_context;
switch (ec->kind) {
case BeamformerExportKind_BeamformedData:{
- BeamformerFrame *f = ctx->latest_frame;
- if (f) {
+ BeamformerFrameBacklog *bl = &ctx->compute_context.backlog;
+ u32 req_count = Clamp(ec->count, 1, bl->counter);
+ u32 frame_idx = bl->counter - req_count;
+ u8 *sm_output = beamformer_shared_memory_scratch_arena(sm, ctx->shared_memory_size).beg;
+ u64 exported_size = 0;
+ for (u32 export_count = 0; export_count < req_count; export_count++, frame_idx++) {
+ BeamformerFrame *f = bl->frames + frame_idx % countof(bl->frames);
u64 frame_size = beamformer_frame_byte_size(f->points, f->data_kind);
assert((frame_size & 63) == 0);
- if (frame_size <= ec->size) {
+ // NOTE(tkh) we don't want to assume that all req_count frames are the same size,
+ // so we either need to count the total size of all requested frames first or
+ // just fill up as much as possible.
+ if (exported_size + frame_size <= ec->size) {
vk_host_wait_timeline(VulkanTimeline_Compute, f->timeline_valid_value, -1ULL);
- vk_buffer_range_download(beamformer_shared_memory_scratch_arena(sm, ctx->shared_memory_size).beg,
- ctx->compute_context.backlog.buffer, f->buffer_offset,
- frame_size, 1);
+ vk_buffer_range_download(sm_output + exported_size, bl->buffer, f->buffer_offset, frame_size, 1);
+ exported_size += frame_size;
}
}
}break;
+
case BeamformerExportKind_Stats:{
ComputeTimingTable *table = ctx->compute_timing_table;
/* NOTE(rnp): do a little spin to let this finish updating */
diff --git a/beamformer_shared_memory.c b/beamformer_shared_memory.c
@@ -1,5 +1,5 @@
/* See LICENSE for license details. */
-#define BEAMFORMER_SHARED_MEMORY_VERSION (32UL)
+#define BEAMFORMER_SHARED_MEMORY_VERSION (33UL)
typedef enum {
BeamformerWorkKind_Compute,
@@ -23,7 +23,8 @@ typedef enum {
typedef struct {
BeamformerExportKind kind;
- u32 size;
+ u32 count; /* Number of items to export */
+ u64 size; /* Total expected size of the exported data */
} BeamformerExportContext;
#define BEAMFORMER_SHARED_MEMORY_LOCKS \
diff --git a/lib/ogl_beamformer_lib.c b/lib/ogl_beamformer_lib.c
@@ -689,6 +689,17 @@ beamformer_export(BeamformerExportContext export, void *out, i32 timeout_ms)
return result;
}
+BEAMFORMER_LIB_EXPORT b32
+beamformer_get_last_frames(void *out_data, u64 out_data_size, u32 count)
+{
+ BeamformerExportContext export = {0};
+ export.kind = BeamformerExportKind_BeamformedData;
+ export.count = count;
+ export.size = out_data_size;
+ b32 result = out_data && out_data_size && count && beamformer_export(export, out_data, g_beamformer_library_context.timeout_ms);
+ return result;
+}
+
b32
beamformer_beamform_data(BeamformerSimpleParameters *bp, void *data, uint32_t data_size,
void *out_data, int32_t timeout_ms)
@@ -715,12 +726,8 @@ beamformer_beamform_data(BeamformerSimpleParameters *bp, void *data, uint32_t da
if (result) {
result = beamformer_push_data_with_compute(data, data_size, 0, 0);
- if (result && out_data) {
- BeamformerExportContext export;
- export.kind = BeamformerExportKind_BeamformedData;
- export.size = (u32)output_size;
- result = beamformer_export(export, out_data, timeout_ms);
- }
+ if (result && out_data)
+ result = beamformer_get_last_frames(out_data, output_size, 1);
}
}
return result;
@@ -734,7 +741,7 @@ beamformer_compute_timings(BeamformerComputeStatsTable *output, i32 timeout_ms)
Arena scratch = beamformer_shared_memory_scratch_arena(g_beamformer_library_context.bp,
g_beamformer_library_context.shared_memory_size);
if (lib_error_check((i64)sizeof(*output) <= arena_capacity(&scratch, u8), ExportSpaceOverflow)) {
- BeamformerExportContext export;
+ BeamformerExportContext export = {0};
export.kind = BeamformerExportKind_Stats;
export.size = sizeof(*output);
result = beamformer_export(export, output, timeout_ms);
diff --git a/lib/ogl_beamformer_lib_base.h b/lib/ogl_beamformer_lib_base.h
@@ -85,6 +85,23 @@ BEAMFORMER_LIB_EXPORT uint32_t beamformer_push_data_with_compute(void *data, uin
uint32_t image_plane_tag,
uint32_t parameter_slot);
+
+/* Returns the last N beamformed frames, ordered from oldest to newest.
+ * out_data: Preallocated output buffer.
+ * out_data_size: Total output buffer size.
+ * count: Number of frames to return.
+ *
+ * NOTE:
+ * - Individual frame sizes are rounded up to 64 byte alignment prior to export
+ *
+ * - Frame size is not guarenteed to be consistent between frames,
+ * it is the callers responsibility to know the correct dimensions of each frame.
+ *
+ * - The buffer will be filled one frame at a time from oldest to newest,
+ * if the output buffer is too small the most recent frames will be dropped.
+ */
+BEAMFORMER_LIB_EXPORT uint32_t beamformer_get_last_frames(void *out_data, uint64_t out_data_size, uint32_t count);
+
///////////////////////////
// Parameter Configuration
BEAMFORMER_LIB_EXPORT uint32_t beamformer_reserve_parameter_blocks(uint32_t count);