ogl_beamforming

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

Commit: 2865c89febccaa0e39ea5be76644bad86a291c95
Parent: 9176fb5c8ae3d5f82e11fe73e60b3201e745bd20
Author: Randy Palamar
Date:   Tue, 15 Sep 2026 22:12:39 -0700

vulkan: correctly handle queue index assignments

This will allow for proper transfer queue usage on nVidia cards
when staging buffers need to be used.

Diffstat:
Mbeamformer_core.c | 9++++++---
Mbeamformer_internal.h | 2+-
Mvulkan.c | 57+++++++++++++++++++++++++++++++++++----------------------
3 files changed, 42 insertions(+), 26 deletions(-)

diff --git a/beamformer_core.c b/beamformer_core.c @@ -272,6 +272,8 @@ gpu_resource_build_end(GPUResourceBuilder *rb, GPUBuffer *buffer) .size = size, .flags = GPUUsageFlag_HostWrite, .label = push_str8_f(rb->arena, "GPU Temp Arena [%p]", buffer), + .timelines_used = (GPUTimeline []){GPUTimeline_Compute}, + .timeline_count = 1, }); } @@ -1742,12 +1744,13 @@ DEBUG_EXPORT BEAMFORMER_RF_UPLOAD_FN(beamformer_rf_upload) rf->active_rf_size = gpu_round_up_to_sync_size(rf_block_rf_size & 0xFFFFFFFFULL, 64); if unlikely(rf->buffer.size < countof(rf->upload_complete_values) * rf->active_rf_size) { - GPUBufferAllocateInfo allocate_info = { + gpu_buffer_allocate(&rf->buffer, (GPUBufferAllocateInfo){ .size = countof(rf->upload_complete_values) * rf->active_rf_size, .flags = GPUUsageFlag_HostWrite, .label = str8("RawRFBuffer"), - }; - gpu_buffer_allocate(&rf->buffer, allocate_info); + .timelines_used = (GPUTimeline []){GPUTimeline_Compute}, + .timeline_count = 1, + }); } u64 slot = rf->insertion_index % countof(rf->upload_complete_values); diff --git a/beamformer_internal.h b/beamformer_internal.h @@ -118,7 +118,7 @@ typedef struct { GPUUsageFlags flags; i64 size; - // NOTE(rnp): only required if buffer will be used on multiple timelines + // NOTE(rnp): these are required if buffer will have any CPU<->GPU transfers u32 timeline_count; GPUTimeline *timelines_used; diff --git a/vulkan.c b/vulkan.c @@ -1078,12 +1078,14 @@ vk_buffer_allocate_common(VulkanBuffer *vb, VulkanBufferAllocateInfo *ai) */ u32 host_rw_flags = (ai->flags & GPUUsageFlag_HostReadWrite); + assert(!host_rw_flags || (host_rw_flags && ai->queue_family_count > 0)); + b32 result = 0; if ((ForceStagingBuffers && !host_rw_flags) || !ForceStagingBuffers) result = vk_buffer_allocate_common_base(vb, ai, host_rw_flags ? VulkanMemoryKind_BAR : VulkanMemoryKind_Device); if (!result && host_rw_flags) { - u32 transfer_queue_family = vk->queues[vk->queue_indices[VulkanQueueKind_Transfer]]->queue_family; + u32 transfer_queue_family = vk->queues[VulkanQueueKind_Transfer]->queue_family; ai->flags &= ~GPUUsageFlag_HostReadWrite; ai->flags |= GPUUsageFlag_TransferDestination; @@ -1107,7 +1109,7 @@ vk_buffer_allocate_common(VulkanBuffer *vb, VulkanBufferAllocateInfo *ai) .index_type = VK_INDEX_TYPE_NONE_KHR, .flags = host_rw_flags|GPUUsageFlag_TransferSource, .queue_family_count = 1, - .queue_family_indices[0] = vk->queues[vk->queue_indices[VulkanQueueKind_Transfer]]->queue_family, + .queue_family_indices[0] = vk->queues[VulkanQueueKind_Transfer]->queue_family, }; Temp scratch; DeferLoop(take_lock(&vk->arena_lock, -1), release_lock(&vk->arena_lock)) @@ -1675,20 +1677,32 @@ vk_load_queues(Arena *arena, Stream *err) ///////////////////////////////////////////// // NOTE(rnp): fill in info and create device - for EachElement(vk->queues, it) { - u32 index = queue_subindices[it]; - for (i32 i = 0; i < queue_indices[it]; i++) - index += assigned_subindices[i]; - vk->queue_indices[it] = index; - } - - for EachElement(vk->queues, it) { - if (vk->queues[vk->queue_indices[it]] == 0) { - vk->queues[vk->queue_indices[it]] = push_struct(vk->arena, VulkanQueue); - vk->queues[vk->queue_indices[it]]->queue_family = queue_indices[it]; - vk->queues[vk->queue_indices[it]]->queue_index = queue_subindices[it]; + + u32 unique_queue_count = 0; + for EachElement(vk->queues, i) { + VulkanQueue *qp = 0; + + u32 unique_queue_index = unique_queue_count; + for EachElement(vk->queues, j) { + if (vk->queues[j] && + vk->queues[j]->queue_family == queue_indices[i] && + vk->queues[j]->queue_index == queue_subindices[i]) + { + qp = vk->queues[j]; + unique_queue_index = j; + break; + } } - vk->queues[it] = vk->queues[vk->queue_indices[it]]; + + if (!qp) { + qp = push_struct(vk->arena, VulkanQueue); + qp->queue_family = queue_indices[i]; + qp->queue_index = queue_subindices[i]; + unique_queue_count++; + } + + vk->queues[i] = qp; + vk->queue_indices[i] = unique_queue_index; } for EachElement(vk->command_pools, it) @@ -1700,16 +1714,16 @@ vk_load_queues(Arena *arena, Stream *err) for (u32 i = 0; i < VulkanQueueKind_Count; i++) for (u32 j = 0; j < VulkanQueueKind_Count; j++) queue_priorities[i][j] = 1.0f; - queue_priorities[queue_indices[VulkanQueueKind_Compute]][queue_subindices[VulkanQueueKind_Compute]] = 0.5f; + queue_priorities[vk->queue_indices[VulkanQueueKind_Compute]][queue_subindices[VulkanQueueKind_Compute]] = 0.5f; u32 queue_create_index = 0; b32 queue_info_filled[VulkanQueueKind_Count] = {0}; - for (u32 q = 0; q < vk->unique_queues; q++) { - u32 base_q = queue_indices[q]; - if (!queue_info_filled[base_q]) { + for EachElement(vk->queue_indices, q) { + u32 base_q = vk->queue_indices[q]; + if (!queue_info_filled[base_q] && assigned_subindices[q] > 0) { queue_create_infos[queue_create_index++] = (VkDeviceQueueCreateInfo){ .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, - .queueFamilyIndex = base_q, + .queueFamilyIndex = vk->queues[base_q]->queue_family, .queueCount = assigned_subindices[q], .pQueuePriorities = queue_priorities[q], }; @@ -1803,9 +1817,8 @@ vk_load_queues(Arena *arena, Stream *err) #undef X for (u32 q = 0; q < vk->unique_queues; q++) { - VulkanQueue *qp = vk->queues[q]; + VulkanQueue *qp = vk->queues[vk->queue_indices[q]]; vkGetDeviceQueue(vk->device, qp->queue_family, qp->queue_index, &qp->queue); - qp->timeline_semaphore = vk_make_semaphore(0); }