Commit: c8af5968f1b5fe9ea82759c147b893254f4d4649
Parent: 69799d54a9fddad0670eb6b776f79926282775c6
Author: Randy Palamar
Date: Mon, 10 Aug 2026 05:43:08 -0700
gpu: rename interface from vk to gpu
This isn't really meant to be exclusively for vulkan from the
beamformer's perspective.
Diffstat:
| M | beamformer.c | | | 6 | +++--- |
| M | beamformer_core.c | | | 85 | +++++++++++++++++++++++++++++++++++++++---------------------------------------- |
| M | beamformer_internal.h | | | 65 | ++++++++++++++++++++++++++++++++++------------------------------- |
| M | ui.c | | | 46 | +++++++++++++++++++++++----------------------- |
| M | vulkan.c | | | 309 | ++++++++++++++++++++++++++++++++++++++++--------------------------------------- |
| M | vulkan.h | | | 2 | ++ |
6 files changed, 260 insertions(+), 253 deletions(-)
diff --git a/beamformer.c b/beamformer.c
@@ -96,7 +96,7 @@ beamformer_load_cuda_library(BeamformerCtx *ctx, OSLibrary cuda, Arena *scratch)
/* TODO(rnp): (25.10.30) registering the rf buffer with CUDA is currently
* causing a major performance regression. for now we are disabling its use
* altogether. it will be reenabled once the issue can be fixed */
- b32 result = 0 && vk_gpu_info()->vendor == GPUVendor_NVIDIA && ValidHandle(cuda);
+ b32 result = 0 && gpu_info()->vendor == GPUVendor_NVIDIA && ValidHandle(cuda);
if (result) {
Stream err = arena_stream(scratch);
@@ -194,7 +194,7 @@ beamformer_init(BeamformerInput *input)
// NOTE(rnp): allocate beamformed image ring buffer
{
- u64 gpu_heap_size = vk_gpu_info()->gpu_heap_size;
+ u64 gpu_heap_size = gpu_info()->gpu_heap_size;
u64 trial_sizes[] = {
GB(4),
GB(2),
@@ -211,7 +211,7 @@ beamformer_init(BeamformerInput *input)
for (u32 i = base_index; i < countof(trial_sizes); i++) {
// TODO(rnp): it may be better to download data from this using the transfer queue
- VulkanTimeline timelines[] = {VulkanTimeline_Compute, VulkanTimeline_Graphics};
+ GPUTimeline timelines[] = {GPUTimeline_Compute, GPUTimeline_Graphics};
GPUBufferAllocateInfo allocate_info = {
.size = trial_sizes[i],
.flags = VulkanUsageFlag_TransferDestination|VulkanUsageFlag_TransferSource|VulkanUsageFlag_HostReadWrite,
diff --git a/beamformer_core.c b/beamformer_core.c
@@ -325,7 +325,7 @@ layout_for_output(iv3 points)
b32 has_y = points.y > 1;
b32 has_z = points.z > 1;
- u32 subgroup_size = vk_gpu_info()->subgroup_size;
+ u32 subgroup_size = gpu_info()->subgroup_size;
u32 grid_3d_z_size = Max(1, subgroup_size / (4 * 4));
u32 grid_2d_y_size = Max(1, subgroup_size / 8);
@@ -488,7 +488,7 @@ plan_compute_pipeline(BeamformerComputePlan *cp, BeamformerParameterBlock *pb, A
switch (pb->pipeline.shaders[it]) {
case BeamformerShaderKind_Decode:{
b32 low_precision = beamformer_data_kind_element_size[input_data_kind] < 4;
- b32 use_coop_matrix = vk_gpu_info()->cooperative_matrix &&
+ b32 use_coop_matrix = gpu_info()->cooperative_matrix &&
low_precision &&
(acquisition_count % 16 == 0) &&
(chunk_channel_count % 16 == 0);
@@ -584,7 +584,7 @@ plan_compute_pipeline(BeamformerComputePlan *cp, BeamformerParameterBlock *pb, A
graph.last->output_data_kind = graph.last->input_data_kind;
f32 time_offset = pb->parameters.time_offset;
- u32 subgroup_size = vk_gpu_info()->subgroup_size;
+ u32 subgroup_size = gpu_info()->subgroup_size;
cp->first_image_shader_index = 0;
cp->pipeline.shader_count = 0;
@@ -616,7 +616,7 @@ plan_compute_pipeline(BeamformerComputePlan *cp, BeamformerParameterBlock *pb, A
db->ToProcess = 1;
- b32 use_coop_matrix = vk_gpu_info()->cooperative_matrix &&
+ b32 use_coop_matrix = gpu_info()->cooperative_matrix &&
node->input_data_kind == BeamformerDataKind_Float16 &&
(db->TransmitCount % 16 == 0) &&
(chunk_channel_count % 16 == 0);
@@ -978,7 +978,7 @@ beamformer_reload_compute_pipeline(VulkanHandle *pipeline, BeamformerShaderKind
BeamformerShaderDescriptor *shader_descriptor, Arena *scratch)
{
i32 index = beamformer_shader_reloadable_index_by_shader[shader];
- uv3 layout = shader_descriptor ? shader_descriptor->layout : (uv3){{vk_gpu_info()->subgroup_size, 1, 1}};
+ uv3 layout = shader_descriptor ? shader_descriptor->layout : (uv3){{gpu_info()->subgroup_size, 1, 1}};
BeamformerShaderReloadInfo info = {
.shader = shader,
.shader_kind = VulkanShaderKind_Compute,
@@ -1058,7 +1058,7 @@ beamformer_commit_parameter_block(BeamformerCtx *ctx, BeamformerComputePlan *cp,
cp->hadamard_order != (i32)cp->acquisition_count)
{
beamformer_update_hadamard(cp, BeamformerComputeArrayParametersField_DecodeHadamard,
- cp->acquisition_count, vk_gpu_info()->cooperative_matrix, scratch);
+ 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);
@@ -1108,8 +1108,8 @@ beamformer_commit_parameter_block(BeamformerCtx *ctx, BeamformerComputePlan *cp,
}
function void
-do_compute_shader(BeamformerCtx *ctx, VulkanHandle cmd, BeamformerComputePlan *cp, BeamformerFrame *frame,
- u32 shader_slot, u32 channel_offset, u64 rf_pointer)
+do_compute_shader(BeamformerCtx *ctx, GPUCommandList cmd, BeamformerComputePlan *cp,
+ BeamformerFrame *frame, u32 shader_slot, u32 channel_offset, u64 rf_pointer)
{
BeamformerComputeContext *cc = &ctx->compute_context;
@@ -1126,7 +1126,7 @@ do_compute_shader(BeamformerCtx *ctx, VulkanHandle cmd, BeamformerComputePlan *c
uv3 dispatch = cp->shader_descriptors[shader_slot].dispatch;
- vk_command_bind_pipeline(cmd, cp->vulkan_pipelines[shader_slot]);
+ gpu_command_bind_pipeline(cmd, cp->vulkan_pipelines[shader_slot]);
switch (cp->pipeline.shaders[shader_slot]) {
@@ -1158,9 +1158,9 @@ do_compute_shader(BeamformerCtx *ctx, VulkanHandle cmd, BeamformerComputePlan *c
if (shader_slot + 1 == das_index)
barrier_count++;
- vk_command_buffer_memory_barriers(cmd, memory_barriers, barrier_count);
- vk_command_push_constants(cmd, 0, sizeof(pc), &pc);
- vk_command_dispatch_compute(cmd, dispatch);
+ gpu_command_buffer_memory_barriers(cmd, memory_barriers, barrier_count);
+ gpu_command_push_constants(cmd, 0, sizeof(pc), &pc);
+ gpu_command_dispatch_compute(cmd, dispatch);
cc->ping_pong_input_index = !cc->ping_pong_input_index;
}break;
@@ -1212,10 +1212,10 @@ do_compute_shader(BeamformerCtx *ctx, VulkanHandle cmd, BeamformerComputePlan *c
barrier_count--;
if (barrier_count)
- vk_command_buffer_memory_barriers(cmd, barriers, barrier_count);
+ gpu_command_buffer_memory_barriers(cmd, barriers, barrier_count);
- vk_command_push_constants(cmd, 0, sizeof(pc), &pc);
- vk_command_dispatch_compute(cmd, dispatch);
+ gpu_command_push_constants(cmd, 0, sizeof(pc), &pc);
+ gpu_command_dispatch_compute(cmd, dispatch);
cc->ping_pong_input_index = !cc->ping_pong_input_index;
}break;
@@ -1247,8 +1247,7 @@ do_compute_shader(BeamformerCtx *ctx, VulkanHandle cmd, BeamformerComputePlan *c
b32 coherent = (cp->shader_descriptors[shader_slot].compile_flags & BeamformerDASCompileFlags_CoherencyWeighting) != 0;
- GPUMemoryBarrierInfo memory_barriers[] = {
- // NOTE(rnp): last stage data output barrier
+ GPUMemoryBarrierInfo barrier_infos[] = {
{
.gpu_buffer = &cc->ping_pong_buffer,
.offset = pp_das_pointer - cc->ping_pong_buffer.gpu_pointer,
@@ -1267,12 +1266,12 @@ do_compute_shader(BeamformerCtx *ctx, VulkanHandle cmd, BeamformerComputePlan *c
},
};
- u32 barrier_count = countof(memory_barriers);
+ u32 barrier_count = countof(barrier_infos);
if (!coherent) barrier_count--;
- vk_command_buffer_memory_barriers(cmd, memory_barriers, barrier_count);
- vk_command_push_constants(cmd, 0, sizeof(pc), &pc);
- vk_command_dispatch_compute(cmd, dispatch);
+ gpu_command_buffer_memory_barriers(cmd, barrier_infos, barrier_count);
+ gpu_command_push_constants(cmd, 0, sizeof(pc), &pc);
+ gpu_command_dispatch_compute(cmd, dispatch);
}break;
case BeamformerShaderKind_CoherencyWeighting:{
@@ -1303,9 +1302,9 @@ do_compute_shader(BeamformerCtx *ctx, VulkanHandle cmd, BeamformerComputePlan *c
},
};
- vk_command_buffer_memory_barriers(cmd, memory_barriers, countof(memory_barriers));
- vk_command_push_constants(cmd, 0, sizeof(pc), &pc);
- vk_command_dispatch_compute(cmd, dispatch);
+ gpu_command_buffer_memory_barriers(cmd, memory_barriers, countof(memory_barriers));
+ gpu_command_push_constants(cmd, 0, sizeof(pc), &pc);
+ gpu_command_dispatch_compute(cmd, dispatch);
}break;
case BeamformerShaderKind_Reshape:{
@@ -1340,9 +1339,9 @@ do_compute_shader(BeamformerCtx *ctx, VulkanHandle cmd, BeamformerComputePlan *c
if (shader_slot + 1 == das_index)
barrier_count++;
- vk_command_buffer_memory_barriers(cmd, memory_barriers, barrier_count);
- vk_command_push_constants(cmd, 0, sizeof(pc), &pc);
- vk_command_dispatch_compute(cmd, dispatch);
+ gpu_command_buffer_memory_barriers(cmd, memory_barriers, barrier_count);
+ gpu_command_push_constants(cmd, 0, sizeof(pc), &pc);
+ gpu_command_dispatch_compute(cmd, dispatch);
cc->ping_pong_input_index = !cc->ping_pong_input_index;
}break;
@@ -1437,7 +1436,7 @@ complete_queue(BeamformerCtx *ctx, BeamformWorkQueue *q, Arena *arena)
// 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);
+ gpu_host_wait_timeline(GPUTimeline_Compute, f->timeline_valid_value, -1ULL);
vk_buffer_range_download(sm_output + exported_size, bl->buffer, f->buffer_offset, frame_size, 1);
exported_size += frame_size;
}
@@ -1531,17 +1530,17 @@ complete_queue(BeamformerCtx *ctx, BeamformWorkQueue *q, Arena *arena)
frame->view_plane_tag = work->compute_context.view_plane;
memory_copy(frame->voxel_transform.E, cp->voxel_transform.E, sizeof(cp->voxel_transform));
- VulkanHandle cmd = vk_command_begin(VulkanTimeline_Compute);
- vk_command_timestamp(cmd);
+ GPUCommandList cmd = gpu_command_list_begin(GPUTimeline_Compute);
+ gpu_command_timestamp(cmd);
if (das_index >= 0) {
u64 frame_size = beamformer_frame_byte_size(frame->points, frame->data_kind);
GPUBuffer *backlog = cs->backlog.buffer;
- vk_command_clear_buffer(cmd, backlog, frame->buffer_offset, frame_size, 0);
+ gpu_command_clear_buffer(cmd, backlog, frame->buffer_offset, frame_size, 0);
if (das_coherent) {
u64 coherent_size = frame_size / beamformer_data_kind_element_count[frame->data_kind];
- vk_command_clear_buffer(cmd, backlog, backlog->size - coherent_size, coherent_size, 0);
+ gpu_command_clear_buffer(cmd, backlog, backlog->size - coherent_size, coherent_size, 0);
}
}
@@ -1557,7 +1556,7 @@ complete_queue(BeamformerCtx *ctx, BeamformWorkQueue *q, Arena *arena)
/* NOTE(rnp): if the GPU supports BAR there may be no need to synchronize
* other than the above spin */
if (vk_buffer_needs_sync(&rf->buffer))
- vk_command_wait_timeline(cmd, VulkanTimeline_Transfer, rf->upload_complete_values[slot]);
+ gpu_command_wait_timeline(cmd, GPUTimeline_Transfer, rf->upload_complete_values[slot]);
} else {
slot = (rf->compute_index - 1) % countof(rf->upload_complete_values);
}
@@ -1570,16 +1569,15 @@ complete_queue(BeamformerCtx *ctx, BeamformWorkQueue *q, Arena *arena)
rf_pointer += cp->raw_channel_byte_stride * channel_offset;
for (u32 i = 0; i < cp->first_image_shader_index; i++) {
do_compute_shader(ctx, cmd, cp, frame, i, channel_offset, rf_pointer);
- vk_command_timestamp(cmd);
+ gpu_command_timestamp(cmd);
}
}
for (u32 i = cp->first_image_shader_index; i < cp->pipeline.shader_count; i++) {
do_compute_shader(ctx, cmd, cp, frame, i, 0, 0);
- vk_command_timestamp(cmd);
+ gpu_command_timestamp(cmd);
}
-
- u64 end_timeline_value = vk_command_end(cmd, (VulkanHandle){0}, (VulkanHandle){0});
+ u64 end_timeline_value = gpu_command_list_end(cmd, (VulkanHandle){0}, (VulkanHandle){0});
if (work->kind == BeamformerWorkKind_ComputeIndirect) {
atomic_store_u64(rf->compute_complete_values + slot, end_timeline_value);
atomic_add_u64(&rf->compute_index, 1);
@@ -1591,14 +1589,15 @@ complete_queue(BeamformerCtx *ctx, BeamformWorkQueue *q, Arena *arena)
DeferLoop(scratch = temp_begin(arena), temp_end(scratch))
{
/* NOTE(rnp): this blocks until work completes */
- u64 *timestamps = vk_command_read_timestamps(VulkanTimeline_Compute, arena);
+ u64 count = 0;
+ u64 *timestamps = gpu_read_timestamps(GPUTimeline_Compute, &count, arena);
i32 steps = ((i32)cp->channel_count / BeamformerChunkChannelCount) - 1;
i32 step = 0;
u32 shader_index = 0;
- u64 last_time = timestamps[0] > 0 ? timestamps[1] : 0;
+ u64 last_time = count > 0 ? timestamps[0] : 0;
- for (u64 i = 2; i < timestamps[0] + 1; i++) {
+ for (u64 i = 1; i < count; i++) {
push_compute_timing_info(ctx->compute_timing_table, (ComputeTimingInfo){
.kind = ComputeTimingInfoKind_Shader,
.shader = cp->pipeline.shaders[shader_index],
@@ -1650,7 +1649,7 @@ coalesce_timing_table(ComputeTimingTable *t, ComputeShaderStats *stats)
u32 stats_index = stats->latest_frame_index;
b32 has_rf = 0;
- f32 gpu_clocks_to_nano = 1.0e-9f * vk_gpu_info()->timestamp_period_ns;
+ f32 gpu_clocks_to_nano = 1.0e-9f * gpu_info()->timestamp_period_ns;
// NOTE(rnp): not equal (the index may wrap)
while (t->read_index != target) {
@@ -1741,7 +1740,7 @@ DEBUG_EXPORT BEAMFORMER_RF_UPLOAD_FN(beamformer_rf_upload)
/* NOTE(rnp): don't overwrite slot if the compute thread hasn't processed it */
spin_wait(atomic_load_u64(&rf->compute_index) < rf->insertion_index);
- vk_host_wait_timeline(VulkanTimeline_Compute, rf->compute_complete_values[slot], -1ULL);
+ gpu_host_wait_timeline(GPUTimeline_Compute, rf->compute_complete_values[slot], -1ULL);
vk_buffer_range_upload(&rf->buffer, beamformer_shared_memory_data_pointer(sm, ctx->shared_memory_size),
slot * rf->active_rf_size, rf->active_rf_size, 1);
@@ -1750,7 +1749,7 @@ DEBUG_EXPORT BEAMFORMER_RF_UPLOAD_FN(beamformer_rf_upload)
beamformer_shared_memory_release_lock(ctx->shared_memory, (i32)scratch_lock);
post_sync_barrier(ctx->shared_memory, upload_lock);
- atomic_store_u64(rf->upload_complete_values + slot, vk_host_signal_timeline(VulkanTimeline_Transfer));
+ atomic_store_u64(rf->upload_complete_values + slot, gpu_host_signal_timeline(GPUTimeline_Transfer));
atomic_add_u64(&rf->insertion_index, 1);
os_wake_all_waiters(ctx->compute_worker_sync);
diff --git a/beamformer_internal.h b/beamformer_internal.h
@@ -18,14 +18,17 @@
#define os_path_separator() (str8){.data = &os_system_info()->path_separator_byte, .length = 1}
+typedef struct { u64 value; } GPUCommandList;
+typedef struct { u64 value; } GPUSplitBarrier;
+
typedef struct { u64 value[1]; } VulkanHandle;
typedef enum {
- VulkanTimeline_Graphics,
- VulkanTimeline_Compute,
- VulkanTimeline_Transfer,
- VulkanTimeline_Count,
-} VulkanTimeline;
+ GPUTimeline_Graphics,
+ GPUTimeline_Compute,
+ GPUTimeline_Transfer,
+ GPUTimeline_Count,
+} GPUTimeline;
typedef enum {
VulkanShaderKind_Vertex,
@@ -112,7 +115,7 @@ typedef struct {
VulkanUsageFlags flags;
// NOTE(rnp): only required if buffer will be used on multiple timelines
- VulkanTimeline *timelines_used;
+ GPUTimeline *timelines_used;
u32 timeline_count;
OSHandle *export;
@@ -146,7 +149,7 @@ typedef struct {
// NOTE: vulkan layer API
DEBUG_IMPORT void vk_load(OSLibrary vulkan, Stream *error);
-DEBUG_IMPORT GPUInfo *vk_gpu_info(void);
+DEBUG_IMPORT GPUInfo *gpu_info(void);
DEBUG_IMPORT void vk_buffer_allocate(GPUBuffer *, GPUBufferAllocateInfo *info);
DEBUG_IMPORT void vk_buffer_release(GPUBuffer *);
@@ -176,31 +179,31 @@ DEBUG_IMPORT b32 vk_buffer_needs_sync(GPUBuffer *);
DEBUG_IMPORT VulkanHandle vk_create_semaphore(OSHandle *export);
-DEBUG_IMPORT b32 vk_host_wait_timeline(VulkanTimeline timeline, u64 value, u64 timeout_ns);
-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);
-DEBUG_IMPORT void vk_command_wait_timeline(VulkanHandle command, VulkanTimeline timeline, u64 value);
-// NOTE: extra semaphores only exist for synchronization with OpenGL and will be removed in the future
-DEBUG_IMPORT u64 vk_command_end(VulkanHandle command, VulkanHandle wait_semaphore, VulkanHandle finished_semaphore);
-
-DEBUG_IMPORT void vk_command_begin_rendering(VulkanHandle command, GPUImage *restrict colour, GPUImage *restrict depth, GPUImage *restrict resolve);
-DEBUG_IMPORT void vk_command_draw(VulkanHandle command, GPUBuffer *model);
-DEBUG_IMPORT void vk_command_scissor(VulkanHandle command, u32 width, u32 height, u32 x_offset, u32 y_offset);
-DEBUG_IMPORT void vk_command_viewport(VulkanHandle command, f32 width, f32 height, f32 x_offset, f32 y_offset, f32 min_depth, f32 max_depth);
-DEBUG_IMPORT void vk_command_end_rendering(VulkanHandle command);
+DEBUG_IMPORT b32 gpu_host_wait_timeline(GPUTimeline timeline, u64 value, u64 timeout_ns);
+DEBUG_IMPORT u64 gpu_host_signal_timeline(GPUTimeline timeline);
-DEBUG_IMPORT void vk_command_copy_buffer(VulkanHandle command, GPUBuffer *restrict destination, GPUBuffer *restrict source, u64 source_offset, i64 size);
-
-// NOTE: returns array of valid timestamps + 1, first element is the count.
-// Calling thread may stall until results available.
-DEBUG_IMPORT u64 * vk_command_read_timestamps(VulkanTimeline timeline, Arena *arena);
+DEBUG_IMPORT GPUCommandList gpu_command_list_begin(GPUTimeline timeline);
+// NOTE: extra semaphores only exist for synchronization with OpenGL and will be removed in the future
+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_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);
+DEBUG_IMPORT void gpu_command_timestamp(GPUCommandList command);
+DEBUG_IMPORT void gpu_command_wait_timeline(GPUCommandList command, GPUTimeline timeline, u64 value);
+
+DEBUG_IMPORT void gpu_command_begin_rendering(GPUCommandList command, GPUImage *restrict colour, GPUImage *restrict depth, GPUImage *restrict resolve);
+DEBUG_IMPORT void gpu_command_draw(GPUCommandList command, GPUBuffer *model);
+DEBUG_IMPORT void gpu_command_scissor(GPUCommandList command, u32 width, u32 height, u32 x_offset, u32 y_offset);
+DEBUG_IMPORT void gpu_command_viewport(GPUCommandList command, f32 width, f32 height, f32 x_offset, f32 y_offset, f32 min_depth, f32 max_depth);
+DEBUG_IMPORT void gpu_command_end_rendering(GPUCommandList command);
+
+DEBUG_IMPORT void gpu_command_copy_buffer(GPUCommandList command, GPUBuffer *restrict destination, GPUBuffer *restrict source, u64 source_offset, i64 size);
+
+// NOTE: returns array of valid timestamps. Calling thread may stall until results available.
+DEBUG_IMPORT u64 * gpu_read_timestamps(GPUTimeline timeline, u64 *count, Arena *arena);
#if BEAMFORMER_RENDERDOC_HOOKS
DEBUG_IMPORT void * vk_renderdoc_instance_handle(void);
diff --git a/ui.c b/ui.c
@@ -854,10 +854,10 @@ beamformer_ui_frame_view_copy_frame(BeamformerFrameView *new, BeamformerFrameVie
vk_buffer_allocate(&new->copy_buffer, &allocate_info);
GPUBuffer *backlog = beamformer_context->compute_context.backlog.buffer;
- VulkanHandle cmd = vk_command_begin(VulkanTimeline_Compute);
- vk_command_wait_timeline(cmd, VulkanTimeline_Compute, old->frame.timeline_valid_value);
- vk_command_copy_buffer(cmd, &new->copy_buffer, backlog, old->frame.buffer_offset, frame_size);
- new->frame.timeline_valid_value = vk_command_end(cmd, (VulkanHandle){0}, (VulkanHandle){0});
+ GPUCommandList cmd = gpu_command_list_begin(GPUTimeline_Compute);
+ gpu_command_wait_timeline(cmd, GPUTimeline_Compute, old->frame.timeline_valid_value);
+ gpu_command_copy_buffer(cmd, &new->copy_buffer, backlog, old->frame.buffer_offset, frame_size);
+ new->frame.timeline_valid_value = gpu_command_list_end(cmd, (VulkanHandle){0}, (VulkanHandle){0});
}
function BeamformerFrameView *
@@ -1001,7 +1001,7 @@ x_plane_raycast(BeamformerFrameView *view, BeamformerFrame *frame, v2 uv)
function void
render_single_xplane(BeamformerFrameView *view, BeamformerFrame *frame, v3 translate, f32 rotation_turns,
- VulkanHandle command, BeamformerRenderBeamformedPushConstants *pc, m4 vp_m, b32 drag_plane)
+ GPUCommandList command, BeamformerRenderBeamformedPushConstants *pc, m4 vp_m, b32 drag_plane)
{
GPUBuffer *beamformed_buffer = beamformer_context->compute_context.backlog.buffer;
pc->input_data = frame->timeline_valid_value ? beamformed_buffer->gpu_pointer + frame->buffer_offset : 0;
@@ -1011,9 +1011,9 @@ render_single_xplane(BeamformerFrameView *view, BeamformerFrame *frame, v3 trans
pc->data_kind = frame->data_kind;
pc->mvp_matrix = m4_mul(vp_m, y_aligned_volume_transform(x_plane_display_size(frame), translate, rotation_turns));
- vk_command_wait_timeline(command, VulkanTimeline_Compute, frame->timeline_valid_value);
- vk_command_push_constants(command, 0, sizeof(*pc), pc);
- vk_command_draw(command, &ui_context->unit_cube_model.model);
+ gpu_command_wait_timeline(command, GPUTimeline_Compute, frame->timeline_valid_value);
+ gpu_command_push_constants(command, 0, sizeof(*pc), pc);
+ gpu_command_draw(command, &ui_context->unit_cube_model.model);
v3 xp_delta = v3_sub(view->hit_test_point, view->hit_start_point);
if (drag_plane && !f32_equal(v3_magnitude_squared(xp_delta), 0)) {
@@ -1026,13 +1026,13 @@ render_single_xplane(BeamformerFrameView *view, BeamformerFrame *frame, v3 trans
pc->bounding_box_fraction = 1.0f;
pc->input_data = 0;
- vk_command_push_constants(command, 0, sizeof(*pc), pc);
- vk_command_draw(command, &ui_context->unit_cube_model.model);
+ gpu_command_push_constants(command, 0, sizeof(*pc), pc);
+ gpu_command_draw(command, &ui_context->unit_cube_model.model);
}
}
function void
-render_3d_xplane(BeamformerFrameView *view, VulkanHandle command, BeamformerRenderBeamformedPushConstants *pc)
+render_3d_xplane(BeamformerFrameView *view, GPUCommandList command, BeamformerRenderBeamformedPushConstants *pc)
{
if (view->demo) {
view->rotation += dt_for_frame * 0.125f;
@@ -1068,7 +1068,7 @@ render_3d_xplane(BeamformerFrameView *view, VulkanHandle command, BeamformerRend
}
function void
-render_2d_plane(BeamformerFrameView *view, VulkanHandle command, BeamformerRenderBeamformedPushConstants *pc)
+render_2d_plane(BeamformerFrameView *view, GPUCommandList command, BeamformerRenderBeamformedPushConstants *pc)
{
m4 view_m = m4_identity();
m4 model = m4_scale((v3){{2.0f, 2.0f, 0.0f}});
@@ -1082,9 +1082,9 @@ render_2d_plane(BeamformerFrameView *view, VulkanHandle command, BeamformerRende
pc->input_size_z = view->frame.points.z;
pc->data_kind = view->frame.data_kind;
- vk_command_wait_timeline(command, VulkanTimeline_Compute, view->frame.timeline_valid_value);
- vk_command_push_constants(command, 0, sizeof(*pc), pc);
- vk_command_draw(command, &ui_context->unit_cube_model.model);
+ gpu_command_wait_timeline(command, GPUTimeline_Compute, view->frame.timeline_valid_value);
+ gpu_command_push_constants(command, 0, sizeof(*pc), pc);
+ gpu_command_draw(command, &ui_context->unit_cube_model.model);
}
function b32
@@ -1128,18 +1128,18 @@ update_frame_views(BeamformerUI *ui, Rect window)
glSignalSemaphoreEXT(ui->render_semaphores_gl[0], 0, 0, 1, &view->texture, (GLenum []){GL_NONE});
- VulkanHandle cmd = vk_command_begin(VulkanTimeline_Graphics);
- vk_command_bind_pipeline(cmd, ui->pipelines[BeamformerShaderKind_RenderBeamformed - BeamformerShaderKind_RenderFirst]);
- vk_command_begin_rendering(cmd, &ui->render_3d_image, &ui->render_3d_depth_image, &view->colour_image);
- vk_command_viewport(cmd, view->colour_image.width, view->colour_image.height, 0, 0, 0.0f, 1.0f);
- vk_command_scissor(cmd, view->colour_image.width, view->colour_image.height, 0, 0);
+ GPUCommandList cmd = gpu_command_list_begin(GPUTimeline_Graphics);
+ gpu_command_bind_pipeline(cmd, ui->pipelines[BeamformerShaderKind_RenderBeamformed - BeamformerShaderKind_RenderFirst]);
+ gpu_command_begin_rendering(cmd, &ui->render_3d_image, &ui->render_3d_depth_image, &view->colour_image);
+ gpu_command_viewport(cmd, view->colour_image.width, view->colour_image.height, 0, 0, 0.0f, 1.0f);
+ gpu_command_scissor(cmd, view->colour_image.width, view->colour_image.height, 0, 0);
if (view->kind == BeamformerFrameViewKind_3DXPlane) {
render_3d_xplane(view, cmd, &pc);
} else {
render_2d_plane(view, cmd, &pc);
}
- vk_command_end_rendering(cmd);
- vk_command_end(cmd, ui->render_semaphores[0], ui->render_semaphores[1]);
+ gpu_command_end_rendering(cmd);
+ gpu_command_list_end(cmd, ui->render_semaphores[0], ui->render_semaphores[1]);
glWaitSemaphoreEXT(ui->render_semaphores_gl[1], 0, 0, 1, &view->texture, (GLenum[]){GL_LAYOUT_COLOR_ATTACHMENT_EXT});
@@ -5124,7 +5124,7 @@ ui_init(BeamformerCtx *ctx, Arena *store)
}
}
- u32 samples = vk_gpu_info()->max_msaa_samples;
+ u32 samples = gpu_info()->max_msaa_samples;
vk_image_allocate(&ui->render_3d_image, FRAME_VIEW_RENDER_TARGET_SIZE, 1, samples, VulkanImageUsage_Colour, 0, 0, str8("Render Target Colour"));
vk_image_allocate(&ui->render_3d_depth_image, FRAME_VIEW_RENDER_TARGET_SIZE, 1, samples, VulkanImageUsage_DepthStencil, 0, 0, str8("Render Target Depth"));
diff --git a/vulkan.c b/vulkan.c
@@ -15,7 +15,7 @@
#define ValidVulkanHandle(h) ((h).value[0] != 0)
-#define MaxCommandBuffersInFlight BeamformerMaxRawDataFramesInFlight
+#define MaxCommandBuffersInFlight (3)
#define MaxCommandBufferTimestamps (1024)
typedef enum {
@@ -63,9 +63,8 @@ typedef struct {
} VulkanSemaphore;
typedef struct {
- VulkanTimeline timeline;
- u32 buffer_index;
-
+ GPUTimeline timeline;
+ u32 buffer_index;
// NOTE(rnp): since there may not be QueueKind_Count queues, when putting values into this
// array you must be careful to map through the queue_indices array in the vulkan_context.
u64 in_flight_wait_values[VulkanQueueKind_Count];
@@ -108,16 +107,16 @@ static_assert(alignof(VulkanQueue) == 64, "VulkanQueue must be placed on its own
typedef alignas(64) struct {
i32 lock;
- u32 next_index;
+ u32 next_command_buffer_index;
VulkanPipeline *bound_pipeline;
+ u64 last_submission_values[MaxCommandBuffersInFlight];
+ u64 timestamp_counts[MaxCommandBuffersInFlight];
+
VkCommandPool handle;
VkQueryPool query_pool;
VkCommandBuffer buffers[MaxCommandBuffersInFlight];
-
- u64 submission_values[MaxCommandBuffersInFlight];
- u32 queries_occupied[MaxCommandBuffersInFlight];
} VulkanCommandPool;
typedef struct {
@@ -150,8 +149,8 @@ typedef struct {
static_assert(VK_MAX_MEMORY_TYPES < U8_MAX, "");
} memory_info;
- VulkanCommandPool * command_pools[VulkanTimeline_Count];
- VulkanQueue * queues[VulkanQueueKind_Count];
+ VulkanCommandPool *command_pools[GPUTimeline_Count];
+ VulkanQueue *queues[VulkanQueueKind_Count];
// NOTE(rnp): there are a few places in the code where simply going through the queues map
// is not sufficient. those places need to know of the unique queues which unique queue
// is being referred to. that code uses this map instead.
@@ -161,6 +160,7 @@ typedef struct {
VkFormat swap_chain_image_format;
VkFormat depth_stencil_format;
+
VulkanEntity *entity_freelist;
Arena *entity_arena;
i32 entity_lock;
@@ -451,17 +451,17 @@ vk_entity_release(VulkanEntity *entity)
}
function void *
-vk_entity_data(VulkanHandle h, VulkanEntityKind kind)
+vk_entity_data(u64 handle, VulkanEntityKind kind)
{
- VulkanEntity *e = (VulkanEntity *)h.value[0];
- assert(ValidVulkanHandle(h) && e->kind == kind);
+ VulkanEntity *e = (VulkanEntity *)handle;
+ assert(handle && e->kind == kind);
return &e->as;
}
function VkCommandBuffer
-vk_command_buffer(VulkanHandle h)
+vk_command_buffer(GPUCommandList h)
{
- VulkanCommandBuffer *vcb = vk_entity_data(h, VulkanEntityKind_CommandBuffer);
+ VulkanCommandBuffer *vcb = vk_entity_data(h.value, VulkanEntityKind_CommandBuffer);
VulkanCommandPool *vcp = vulkan_context->command_pools[vcb->timeline];
VkCommandBuffer result = vcp->buffers[vcb->buffer_index];
return result;
@@ -963,7 +963,7 @@ typedef struct {
u64 size;
VulkanUsageFlags flags;
u32 queue_family_count;
- u32 queue_family_indices[VulkanTimeline_Count];
+ u32 queue_family_indices[GPUTimeline_Count];
VkIndexType index_type;
OSHandle *export;
str8 label;
@@ -1950,7 +1950,7 @@ vk_load(OSLibrary vulkan_library_handle, Stream *err)
}
DEBUG_IMPORT GPUInfo *
-vk_gpu_info(void)
+gpu_info(void)
{
return &vulkan_context->gpu_info;
}
@@ -1975,7 +1975,7 @@ DEBUG_IMPORT void
vk_buffer_release(GPUBuffer *b)
{
if ValidVulkanHandle(b->handle)
- vk_vulkan_buffer_release(vk_entity_data(b->handle, VulkanEntityKind_Buffer));
+ vk_vulkan_buffer_release(vk_entity_data(b->handle.value[0], VulkanEntityKind_Buffer));
zero_struct(b);
}
@@ -2021,7 +2021,7 @@ vk_buffer_needs_sync(GPUBuffer *b)
{
b32 result = 0;
if ValidVulkanHandle(b->handle) {
- VulkanBuffer *vb = vk_entity_data(b->handle, VulkanEntityKind_Buffer);
+ VulkanBuffer *vb = vk_entity_data(b->handle.value[0], VulkanEntityKind_Buffer);
// TODO(rnp): not correct check. need to check if we used transfer queue
result = vb->memory_kind != VulkanMemoryKind_BAR;
@@ -2114,7 +2114,7 @@ vk_buffer_buffer_copy(VulkanBuffer *destination, VulkanBuffer *source, u64 desti
DEBUG_IMPORT void
vk_buffer_range_upload(GPUBuffer *b, void *data, u64 offset, u64 size, b32 non_temporal)
{
- VulkanBuffer *db = vk_entity_data(b->handle, VulkanEntityKind_Buffer);
+ VulkanBuffer *db = vk_entity_data(b->handle.value[0], VulkanEntityKind_Buffer);
VulkanBuffer sb = {
.host_pointer = data,
.memory_kind = VulkanMemoryKind_Host,
@@ -2125,7 +2125,7 @@ vk_buffer_range_upload(GPUBuffer *b, void *data, u64 offset, u64 size, b32 non_t
DEBUG_IMPORT void
vk_buffer_range_download(void *destination, GPUBuffer *source, u64 offset, u64 size, b32 non_temporal)
{
- VulkanBuffer *sb = vk_entity_data(source->handle, VulkanEntityKind_Buffer);
+ VulkanBuffer *sb = vk_entity_data(source->handle.value[0], VulkanEntityKind_Buffer);
VulkanBuffer db = {
.host_pointer = destination,
.memory_kind = VulkanMemoryKind_Host,
@@ -2137,7 +2137,7 @@ DEBUG_IMPORT void
vk_render_model_release(GPUBuffer *model)
{
if ValidVulkanHandle(model->handle)
- vk_vulkan_buffer_release(vk_entity_data(model->handle, VulkanEntityKind_RenderModel));
+ vk_vulkan_buffer_release(vk_entity_data(model->handle.value[0], VulkanEntityKind_RenderModel));
zero_struct(model);
}
@@ -2186,7 +2186,7 @@ vk_render_model_allocate(GPUBuffer *model, void *indices, u64 index_count, u64 m
DEBUG_IMPORT void
vk_render_model_range_upload(GPUBuffer *model, void *data, u64 offset, u64 size, b32 non_temporal)
{
- VulkanBuffer *db = vk_entity_data(model->handle, VulkanEntityKind_RenderModel);
+ VulkanBuffer *db = vk_entity_data(model->handle.value[0], VulkanEntityKind_RenderModel);
VulkanBuffer sb = {
.host_pointer = data,
.memory_kind = VulkanMemoryKind_Host,
@@ -2202,7 +2202,7 @@ vk_image_release(GPUImage *image)
{
if ValidVulkanHandle(image->image) {
VulkanContext *vk = vulkan_context;
- VulkanImage *vi = vk_entity_data(image->image, VulkanEntityKind_Image);
+ VulkanImage *vi = vk_entity_data(image->image.value[0], VulkanEntityKind_Image);
vkDestroyImageView(vk->device, vi->view, 0);
vkDestroyImage(vk->device, vi->image, 0);
@@ -2336,10 +2336,10 @@ vk_create_semaphore(OSHandle *export)
}
DEBUG_IMPORT b32
-vk_host_wait_timeline(VulkanTimeline timeline, u64 value, u64 timeout_ns)
+gpu_host_wait_timeline(GPUTimeline timeline, u64 value, u64 timeout_ns)
{
b32 result = 0;
- if Between(timeline, 0, VulkanTimeline_Count - 1) {
+ if Between(timeline, 0, GPUTimeline_Count - 1) {
VulkanContext *vk = vulkan_context;
VulkanQueue *vq = vk->queues[timeline];
VkSemaphoreWaitInfo semaphore_wait_info = {
@@ -2354,10 +2354,10 @@ vk_host_wait_timeline(VulkanTimeline timeline, u64 value, u64 timeout_ns)
}
DEBUG_IMPORT u64
-vk_host_signal_timeline(VulkanTimeline timeline)
+gpu_host_signal_timeline(GPUTimeline timeline)
{
u64 result = -1;
- if Between(timeline, 0, VulkanTimeline_Count - 1) {
+ if Between(timeline, 0, GPUTimeline_Count - 1) {
VulkanContext *vk = vulkan_context;
VulkanQueue *vq = vk->queues[timeline];
VulkanSemaphore *vs = &vq->timeline_semaphore;
@@ -2397,7 +2397,7 @@ vk_pipeline_valid(VulkanHandle h)
{
b32 result = 0;
if ValidVulkanHandle(h) {
- VulkanPipeline *vp = vk_entity_data(h, VulkanEntityKind_Pipeline);
+ VulkanPipeline *vp = vk_entity_data(h.value[0], VulkanEntityKind_Pipeline);
if (vp->stage_flags == VK_SHADER_STAGE_COMPUTE_BIT)
result = vp->pipeline != vulkan_context->default_compute_pipeline.pipeline;
else
@@ -2411,15 +2411,17 @@ vk_pipeline_release(VulkanHandle h)
{
if (vk_pipeline_valid(h)) {
VulkanEntity *e = (VulkanEntity *)h.value[0];
- VulkanTimeline timeline;
- if (e->as.pipeline.stage_flags == VK_SHADER_STAGE_COMPUTE_BIT) timeline = VulkanTimeline_Compute;
- else timeline = VulkanTimeline_Graphics;
+ GPUTimeline timeline;
+ // TODO(rnp): this is not correct, compute shaders can also appear on graphics timeline
+ if (e->as.pipeline.stage_flags == VK_SHADER_STAGE_COMPUTE_BIT) timeline = GPUTimeline_Compute;
+ else timeline = GPUTimeline_Graphics;
// NOTE(rnp): block more command buffers from being recorded
VulkanCommandPool *vcp = vulkan_context->command_pools[timeline];
- DeferLoop(take_lock(&vcp->lock, -1), release_lock(&vcp->lock)) {
- u32 index = (vcp->next_index - 1) % countof(vcp->buffers);
- vk_host_wait_timeline(timeline, vcp->submission_values[index], -1ULL);
+ DeferLoop(take_lock(&vcp->lock, -1), release_lock(&vcp->lock))
+ {
+ u32 index = (vcp->next_command_buffer_index - 1) % MaxCommandBuffersInFlight;
+ gpu_host_wait_timeline(timeline, vcp->last_submission_values[index], -1ULL);
vkDestroyPipeline(vulkan_context->device, e->as.pipeline.pipeline, 0);
vkDestroyPipelineLayout(vulkan_context->device, e->as.pipeline.layout, 0);
@@ -2440,7 +2442,7 @@ vk_bind_shader_resources(BeamformerShaderResourceInfo *infos, u64 info_count)
for EachIndex(info_count, it) {
switch (infos[it].kind) {
case BeamformerShaderResourceKind_Buffer:{
- VulkanBuffer *vb = vk_entity_data(infos[it].handle, VulkanEntityKind_Buffer);
+ VulkanBuffer *vb = vk_entity_data(infos[it].handle.value[0], VulkanEntityKind_Buffer);
vk->descriptor_buffer_infos[infos[it].slot].buffer = vb->buffer;
vk->descriptor_buffer_infos[infos[it].slot].offset = 0;
vk->descriptor_buffer_infos[infos[it].slot].range = vb->memory_size;
@@ -2460,27 +2462,28 @@ vk_bind_shader_resources(BeamformerShaderResourceInfo *infos, u64 info_count)
vkUpdateDescriptorSets(vk->device, countof(write_sets), write_sets, 0, 0);
}
-DEBUG_IMPORT VulkanHandle
-vk_command_begin(VulkanTimeline timeline)
+DEBUG_IMPORT GPUCommandList
+gpu_command_list_begin(GPUTimeline timeline)
{
- VulkanHandle result = {0};
- if Between(timeline, 0, VulkanTimeline_Count - 1) {
+ GPUCommandList result = {0};
+ if Between(timeline, 0, GPUTimeline_Count - 1) {
VulkanContext *vk = vulkan_context;
VulkanCommandPool *vcp = vk->command_pools[timeline];
take_lock(&vcp->lock, -1);
+ VulkanEntity *e = vk_entity_allocate(VulkanEntityKind_CommandBuffer);
+ result.value = (u64)e;
- VulkanEntity *e = vk_entity_allocate(VulkanEntityKind_CommandBuffer);
VulkanCommandBuffer *vcb = &e->as.command_buffer;
vcb->timeline = timeline;
- vcb->buffer_index = vcp->next_index++ % countof(vcp->buffers);
+ vcb->buffer_index = (vcp->next_command_buffer_index++) % MaxCommandBuffersInFlight;
u32 index = vcb->buffer_index;
// TODO(rnp): probably not the best to have this here but it will likely not be hit
- b32 wait_result = vk_host_wait_timeline(timeline, vcp->submission_values[index], -1ULL);
+ b32 wait_result = gpu_host_wait_timeline(timeline, vcp->last_submission_values[index], -1ULL);
assert(wait_result);
- vcp->queries_occupied[index] = 0;
+ vcp->timestamp_counts[index] = 0;
VkCommandBufferBeginInfo buffer_begin_info = {
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
@@ -2490,159 +2493,163 @@ vk_command_begin(VulkanTimeline timeline)
vkBeginCommandBuffer(vcp->buffers[index], &buffer_begin_info);
vkCmdResetQueryPool(vcp->buffers[index], vcp->query_pool, index * MaxCommandBufferTimestamps,
MaxCommandBufferTimestamps);
-
- result = (VulkanHandle){(u64)e};
}
return result;
}
DEBUG_IMPORT void
-vk_command_bind_pipeline(VulkanHandle command, VulkanHandle pipeline)
+gpu_command_bind_pipeline(GPUCommandList command, VulkanHandle pipeline)
{
- if ValidVulkanHandle(command) {
+ if (command.value) {
VulkanContext *vk = vulkan_context;
- VulkanCommandBuffer *vcb = vk_entity_data(command, VulkanEntityKind_CommandBuffer);
+ VulkanCommandBuffer *vcb = vk_entity_data(command.value, VulkanEntityKind_CommandBuffer);
VulkanCommandPool *vcp = vk->command_pools[vcb->timeline];
VulkanPipeline *vp = 0;
if ValidVulkanHandle(pipeline) {
- vp = vk_entity_data(pipeline, VulkanEntityKind_Pipeline);
- } else if (vcb->timeline == VulkanTimeline_Compute) {
+ vp = vk_entity_data(pipeline.value[0], VulkanEntityKind_Pipeline);
+ } else if (vcb->timeline == GPUTimeline_Compute) {
vp = &vk->default_compute_pipeline;
- } else if (vcb->timeline == VulkanTimeline_Graphics) {
+ } else if (vcb->timeline == GPUTimeline_Graphics) {
vp = &vk->default_graphics_pipeline;
} else {
InvalidCodePath;
}
- read_only local_persist VkPipelineBindPoint bind_point_lut[VulkanTimeline_Count] = {
- [VulkanTimeline_Graphics] = VK_PIPELINE_BIND_POINT_GRAPHICS,
- [VulkanTimeline_Compute] = VK_PIPELINE_BIND_POINT_COMPUTE,
- [VulkanTimeline_Transfer] = -1,
+ read_only local_persist VkPipelineBindPoint bind_point_lut[GPUTimeline_Count] = {
+ [GPUTimeline_Graphics] = VK_PIPELINE_BIND_POINT_GRAPHICS,
+ [GPUTimeline_Compute] = VK_PIPELINE_BIND_POINT_COMPUTE,
+ [GPUTimeline_Transfer] = -1,
};
VkPipelineBindPoint bind_point = bind_point_lut[vcb->timeline];
assert(bind_point != (VkPipelineBindPoint)-1);
- vkCmdBindPipeline(vcp->buffers[vcb->buffer_index], bind_point, vp->pipeline);
- vkCmdBindDescriptorSets(vcp->buffers[vcb->buffer_index], bind_point, vp->layout,
- 0, countof(vk->descriptor_sets), vk->descriptor_sets, 0, 0);
+ VkCommandBuffer cmd = vk_command_buffer(command);
+ vkCmdBindPipeline(cmd, bind_point, vp->pipeline);
+ vkCmdBindDescriptorSets(cmd, bind_point, vp->layout, 0, countof(vk->descriptor_sets),
+ vk->descriptor_sets, 0, 0);
vcp->bound_pipeline = vp;
}
}
+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
-vk_command_buffer_memory_barriers(VulkanHandle command, GPUMemoryBarrierInfo *barriers, u64 count)
+gpu_command_buffer_memory_barriers(GPUCommandList command, GPUMemoryBarrierInfo *barriers, u64 count)
{
- if ValidVulkanHandle(command) {
+ if (command.value) {
VulkanContext *vk = vulkan_context;
- VulkanCommandBuffer *vcb = vk_entity_data(command, VulkanEntityKind_CommandBuffer);
- VulkanCommandPool *vcp = vk->command_pools[vcb->timeline];
+ 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))
{
- u32 valid_count = 0;
- VkBufferMemoryBarrier2 *memory_barriers = push_array(vk->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, 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 dependancy_info = {
- .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
- .bufferMemoryBarrierCount = valid_count,
- .pBufferMemoryBarriers = memory_barriers,
- };
-
- vkCmdPipelineBarrier2(vcp->buffers[vcb->buffer_index], &dependancy_info);
+ VkDependencyInfo dependancy_info = vk_dependency_info_from_memory_barrier_info(scratch.arena, vq, barriers, count);
+ vkCmdPipelineBarrier2(vk_command_buffer(command), &dependancy_info);
}
}
}
DEBUG_IMPORT void
-vk_command_clear_buffer(VulkanHandle command, GPUBuffer *buffer, u64 offset, u64 size, u32 clear_word)
+gpu_command_clear_buffer(GPUCommandList 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);
+ if (command.value) {
+ VulkanBuffer *vb = vk_entity_data(buffer->handle.value[0], 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)
+gpu_command_dispatch_compute(GPUCommandList command, uv3 dispatch)
{
assert(dispatch.x <= U16_MAX);
assert(dispatch.y <= U16_MAX);
assert(dispatch.z <= U16_MAX);
- if ValidVulkanHandle(command) {
+ if (command.value) {
VkCommandBuffer cmd = vk_command_buffer(command);
vkCmdDispatch(cmd, dispatch.x, dispatch.y, dispatch.z);
}
}
DEBUG_IMPORT void
-vk_command_push_constants(VulkanHandle command, u32 offset, u32 size, void *values)
+gpu_command_push_constants(GPUCommandList command, u32 offset, u32 size, void *values)
{
- if ValidVulkanHandle(command) {
- VulkanCommandBuffer *vcb = vk_entity_data(command, VulkanEntityKind_CommandBuffer);
+ if (command.value) {
+ VulkanCommandBuffer *vcb = vk_entity_data(command.value, VulkanEntityKind_CommandBuffer);
VulkanCommandPool *vcp = vulkan_context->command_pools[vcb->timeline];
VulkanPipeline *vp = vcp->bound_pipeline;
assert(vp);
- vkCmdPushConstants(vcp->buffers[vcb->buffer_index], vp->layout, vp->stage_flags, offset, size, values);
+ vkCmdPushConstants(vk_command_buffer(command), vp->layout, vp->stage_flags, offset, size, values);
}
}
DEBUG_IMPORT void
-vk_command_timestamp(VulkanHandle command)
+gpu_command_timestamp(GPUCommandList command)
{
- if ValidVulkanHandle(command) {
+ if (command.value) {
VulkanContext *vk = vulkan_context;
- VulkanCommandBuffer *vcb = vk_entity_data(command, VulkanEntityKind_CommandBuffer);
+ VulkanCommandBuffer *vcb = vk_entity_data(command.value, VulkanEntityKind_CommandBuffer);
VulkanCommandPool *vcp = vk->command_pools[vcb->timeline];
- read_only local_persist VkPipelineStageFlags2 stage_lut[VulkanTimeline_Count] = {
- [VulkanTimeline_Graphics] = VK_PIPELINE_STAGE_2_ALL_GRAPHICS_BIT,
- [VulkanTimeline_Compute] = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
- [VulkanTimeline_Transfer] = -1,
+ read_only local_persist VkPipelineStageFlags2 stage_lut[GPUTimeline_Count] = {
+ [GPUTimeline_Graphics] = VK_PIPELINE_STAGE_2_ALL_GRAPHICS_BIT,
+ [GPUTimeline_Compute] = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
+ [GPUTimeline_Transfer] = -1,
};
VkPipelineStageFlags2 stage = stage_lut[vcb->timeline];
assert(stage != (VkPipelineStageFlags2)-1);
- if (vcp->queries_occupied[vcb->buffer_index] < MaxCommandBufferTimestamps) {
- u32 query_index = vcp->queries_occupied[vcb->buffer_index]++;
- vkCmdWriteTimestamp2(vcp->buffers[vcb->buffer_index], stage, vcp->query_pool,
+ if (vcp->timestamp_counts[vcb->buffer_index] < MaxCommandBufferTimestamps) {
+ u64 query_index = vcp->timestamp_counts[vcb->buffer_index]++;
+ vkCmdWriteTimestamp2(vk_command_buffer(command), stage, vcp->query_pool,
vcb->buffer_index * MaxCommandBufferTimestamps + query_index);
}
}
}
DEBUG_IMPORT void
-vk_command_wait_timeline(VulkanHandle command, VulkanTimeline timeline, u64 value)
+gpu_command_wait_timeline(GPUCommandList command, GPUTimeline timeline, u64 value)
{
- if (ValidVulkanHandle(command) && Between(timeline, 0, VulkanTimeline_Count - 1)) {
+ if (command.value && Between(timeline, 0, GPUTimeline_Count - 1)) {
VulkanContext *vk = vulkan_context;
- VulkanCommandBuffer *vcb = vk_entity_data(command, VulkanEntityKind_CommandBuffer);
+ VulkanCommandBuffer *vcb = vk_entity_data(command.value, VulkanEntityKind_CommandBuffer);
u32 wait_index = vk->queue_indices[timeline];
vcb->in_flight_wait_values[wait_index] = Max(value, vcb->in_flight_wait_values[wait_index]);
@@ -2650,12 +2657,12 @@ vk_command_wait_timeline(VulkanHandle command, VulkanTimeline timeline, u64 valu
}
DEBUG_IMPORT u64
-vk_command_end(VulkanHandle command, VulkanHandle wait_semaphore, VulkanHandle finished_semaphore)
+gpu_command_list_end(GPUCommandList command, VulkanHandle wait_semaphore, VulkanHandle finished_semaphore)
{
u64 result = -1;
- if ValidVulkanHandle(command) {
+ if (command.value) {
VulkanContext *vk = vulkan_context;
- VulkanCommandBuffer *vcb = vk_entity_data(command, VulkanEntityKind_CommandBuffer);
+ VulkanCommandBuffer *vcb = vk_entity_data(command.value, VulkanEntityKind_CommandBuffer);
VulkanCommandPool *vcp = vk->command_pools[vcb->timeline];
VulkanQueue *vq = vk->queues[vcb->timeline];
VulkanSemaphore *vs = &vq->timeline_semaphore;
@@ -2679,7 +2686,7 @@ vk_command_end(VulkanHandle command, VulkanHandle wait_semaphore, VulkanHandle f
}};
if ValidVulkanHandle(finished_semaphore) {
- VulkanSemaphore *fs = vk_entity_data(finished_semaphore, VulkanEntityKind_Semaphore);
+ VulkanSemaphore *fs = vk_entity_data(finished_semaphore.value[0], VulkanEntityKind_Semaphore);
signal_submit_infos[signal_submit_info_count++] = (VkSemaphoreSubmitInfo){
.sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO,
.semaphore = fs->semaphore,
@@ -2704,7 +2711,7 @@ vk_command_end(VulkanHandle command, VulkanHandle wait_semaphore, VulkanHandle f
}
if ValidVulkanHandle(wait_semaphore) {
- VulkanSemaphore *ws = vk_entity_data(wait_semaphore, VulkanEntityKind_Semaphore);
+ VulkanSemaphore *ws = vk_entity_data(wait_semaphore.value[0], VulkanEntityKind_Semaphore);
wait_submit_infos[wait_submit_info_count++] = (VkSemaphoreSubmitInfo){
.sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO,
.semaphore = ws->semaphore,
@@ -2725,29 +2732,28 @@ vk_command_end(VulkanHandle command, VulkanHandle wait_semaphore, VulkanHandle f
vkQueueSubmit2(vq->queue, 1, &submit_info, 0);
vcp->bound_pipeline = 0;
-
- atomic_store_u64(vcp->submission_values + vcb->buffer_index, result);
+ atomic_store_u64(vcp->last_submission_values + vcb->buffer_index, result);
}
release_lock(&vcp->lock);
- vk_entity_release((VulkanEntity *)command.value[0]);
+ vk_entity_release((VulkanEntity *)command.value);
}
return result;
}
DEBUG_IMPORT void
-vk_command_begin_rendering(VulkanHandle command, GPUImage *colour, GPUImage *depth, GPUImage *resolve)
+gpu_command_begin_rendering(GPUCommandList command, GPUImage *colour, GPUImage *depth, GPUImage *resolve)
{
- if ValidVulkanHandle(command) {
+ if (command.value) {
VkCommandBuffer cmd = vk_command_buffer(command);
assert((colour->width == depth->width) && (colour->height == depth->height));
- VulkanImage *ci = vk_entity_data(colour->image, VulkanEntityKind_Image);
- VulkanImage *di = vk_entity_data(depth->image, VulkanEntityKind_Image);
+ VulkanImage *ci = vk_entity_data(colour->image.value[0], VulkanEntityKind_Image);
+ VulkanImage *di = vk_entity_data(depth->image.value[0], VulkanEntityKind_Image);
VulkanImage *ri = 0;
- if (resolve) ri = vk_entity_data(resolve->image, VulkanEntityKind_Image);
+ if (resolve) ri = vk_entity_data(resolve->image.value[0], VulkanEntityKind_Image);
// NOTE: Layout Transitions
{
@@ -2852,20 +2858,20 @@ vk_command_begin_rendering(VulkanHandle command, GPUImage *colour, GPUImage *dep
}
DEBUG_IMPORT void
-vk_command_draw(VulkanHandle command, GPUBuffer *model)
+gpu_command_draw(GPUCommandList command, GPUBuffer *model)
{
- if (ValidVulkanHandle(command) && ValidVulkanHandle(model->handle)) {
+ if (command.value && ValidVulkanHandle(model->handle)) {
VkCommandBuffer cmd = vk_command_buffer(command);
- VulkanBuffer *vb = vk_entity_data(model->handle, VulkanEntityKind_RenderModel);
+ VulkanBuffer *vb = vk_entity_data(model->handle.value[0], VulkanEntityKind_RenderModel);
vkCmdBindIndexBuffer2(cmd, vb->buffer, 0, vk_index_size(vb->index_type) * model->index_count, vb->index_type);
vkCmdDrawIndexed(cmd, model->index_count, 1, 0, 0, 0);
}
}
DEBUG_IMPORT void
-vk_command_scissor(VulkanHandle command, u32 width, u32 height, u32 x_offset, u32 y_offset)
+gpu_command_scissor(GPUCommandList command, u32 width, u32 height, u32 x_offset, u32 y_offset)
{
- if ValidVulkanHandle(command) {
+ if (command.value) {
VkCommandBuffer cmd = vk_command_buffer(command);
VkRect2D scissor = {.offset = {x_offset, y_offset}, .extent = {width, height}};
vkCmdSetScissor(cmd, 0, 1, &scissor);
@@ -2873,9 +2879,9 @@ vk_command_scissor(VulkanHandle command, u32 width, u32 height, u32 x_offset, u3
}
DEBUG_IMPORT void
-vk_command_viewport(VulkanHandle command, f32 width, f32 height, f32 x_offset, f32 y_offset, f32 min_depth, f32 max_depth)
+gpu_command_viewport(GPUCommandList command, f32 width, f32 height, f32 x_offset, f32 y_offset, f32 min_depth, f32 max_depth)
{
- if ValidVulkanHandle(command) {
+ if (command.value) {
VkCommandBuffer cmd = vk_command_buffer(command);
VkViewport viewport = {x_offset, y_offset, width, height, min_depth, max_depth};
vkCmdSetViewport(cmd, 0, 1, &viewport);
@@ -2883,19 +2889,19 @@ vk_command_viewport(VulkanHandle command, f32 width, f32 height, f32 x_offset, f
}
DEBUG_IMPORT void
-vk_command_end_rendering(VulkanHandle command)
+gpu_command_end_rendering(GPUCommandList command)
{
- if ValidVulkanHandle(command) vkCmdEndRendering(vk_command_buffer(command));
+ if (command.value) vkCmdEndRendering(vk_command_buffer(command));
}
DEBUG_IMPORT void
-vk_command_copy_buffer(VulkanHandle command, GPUBuffer *restrict destination,
- GPUBuffer *restrict source, u64 source_offset, i64 size)
+gpu_command_copy_buffer(GPUCommandList command, GPUBuffer *restrict destination,
+ GPUBuffer *restrict source, u64 source_offset, i64 size)
{
- if (ValidVulkanHandle(command) && ValidVulkanHandle(destination->handle) && ValidVulkanHandle(source->handle)) {
+ if (command.value && ValidVulkanHandle(destination->handle) && ValidVulkanHandle(source->handle)) {
VkCommandBuffer cmd = vk_command_buffer(command);
- VulkanBuffer *db = vk_entity_data(destination->handle, VulkanEntityKind_Buffer);
- VulkanBuffer *sb = vk_entity_data(source->handle, VulkanEntityKind_Buffer);
+ VulkanBuffer *db = vk_entity_data(destination->handle.value[0], VulkanEntityKind_Buffer);
+ VulkanBuffer *sb = vk_entity_data(source->handle.value[0], VulkanEntityKind_Buffer);
VkBufferCopy2 buffer_copy = {
.sType = VK_STRUCTURE_TYPE_BUFFER_COPY_2,
@@ -2917,27 +2923,24 @@ vk_command_copy_buffer(VulkanHandle command, GPUBuffer *restrict destination,
}
DEBUG_IMPORT u64 *
-vk_command_read_timestamps(VulkanTimeline timeline, Arena *arena)
+gpu_read_timestamps(GPUTimeline timeline, u64 *count, Arena *arena)
{
u64 *result = 0;
- if Between(timeline, 0, VulkanTimeline_Count - 1) {
+ if Between(timeline, 0, GPUTimeline_Count - 1) {
VulkanContext *vk = vulkan_context;
VulkanCommandPool *vcp = vk->command_pools[timeline];
- DeferLoop(take_lock(&vcp->lock, -1), release_lock(&vcp->lock)) {
- u32 index = (vcp->next_index - 1) % countof(vcp->buffers);
- u32 count = vcp->queries_occupied[index];
- if (count > 0) {
- result = push_array(arena, u64, count + 1);
- result[0] = count;
-
- vk_host_wait_timeline(timeline, vcp->submission_values[index], -1ULL);
-
- vkGetQueryPoolResults(vk->device, vcp->query_pool, index * MaxCommandBufferTimestamps, count,
- count * sizeof(u64), result + 1, 8, VK_QUERY_RESULT_WAIT_BIT);
+ DeferLoop(take_lock(&vcp->lock, -1), release_lock(&vcp->lock))
+ {
+ u32 index = (vcp->next_command_buffer_index - 1) % MaxCommandBuffersInFlight;
+ *count = vcp->timestamp_counts[index];
+ if (*count > 0) {
+ result = push_array(arena, u64, *count);
+ gpu_host_wait_timeline(timeline, vcp->last_submission_values[index], -1ULL);
+
+ vkGetQueryPoolResults(vk->device, vcp->query_pool, index * MaxCommandBufferTimestamps, *count,
+ *count * sizeof(u64), result, 8, VK_QUERY_RESULT_WAIT_BIT);
}
}
- } else {
- result = push_array(arena, u64, 1);
}
return result;
}
diff --git a/vulkan.h b/vulkan.h
@@ -137,6 +137,7 @@ typedef enum {
VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO = 1000244001,
VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT = 1000247000,
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_FEATURES_KHR = 1000286000,
+ VK_STRUCTURE_TYPE_MEMORY_BARRIER_2 = 1000314000,
VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2 = 1000314001,
VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2 = 1000314002,
VK_STRUCTURE_TYPE_DEPENDENCY_INFO = 1000314003,
@@ -1637,6 +1638,7 @@ typedef enum {
VK_DEPENDENCY_VIEW_LOCAL_BIT = 0x00000002,
VK_DEPENDENCY_FEEDBACK_LOOP_BIT_EXT = 0x00000008,
VK_DEPENDENCY_QUEUE_FAMILY_OWNERSHIP_TRANSFER_USE_ALL_STAGES_BIT_KHR = 0x00000020,
+ VK_DEPENDENCY_ASYMMETRIC_EVENT_BIT_KHR = 0x00000040,
VK_DEPENDENCY_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
} VkDependencyFlagBits;
typedef VkFlags VkDependencyFlags;