ogl_beamforming

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

Commit: 920a6bc097353f8f2c05edc2fe12b3d2406d26b7
Parent: 36abc76bf3aaa47ba2d99de2f8c6afcf8348a97e
Author: Randy Palamar
Date:   Tue, 10 Feb 2026 15:59:48 -0700

vulkan: per timeline command pool instead of per queue

On devices with only a single queue we still want to be able to
record commands on multiple threads. We need a command pool per
timeline rather than per unique queue.

Diffstat:
Mvulkan.c | 292++++++++++++++++++++++++++++++++++++++++++-------------------------------------
1 file changed, 155 insertions(+), 137 deletions(-)

diff --git a/vulkan.c b/vulkan.c @@ -2,11 +2,14 @@ // TODO(rnp) // [ ]: what is needed for HDR? I think it makes sense to just default to it nowadays // [ ]: once opengl is removed switch images to SRGB and/or 16 bit Float +// [ ]: synchronization is busted when there is only one unique queue #include "beamformer_internal.h" #include "vulkan.h" #include "external/glslang/glslang/Include/glslang_c_interface.h" +#define ForceSingleQueue (0) + #define glslang_info(s) s8("[glslang] " s) #define vulkan_info(s) s8("[vulkan] " s) @@ -59,8 +62,8 @@ typedef struct { } VulkanSemaphore; typedef struct { - VulkanQueueKind kind; - u32 command_buffer_index; + VulkanTimeline 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. @@ -96,22 +99,26 @@ typedef alignas(64) struct { u16 queue_index; VkQueue queue; - VkQueryPool query_pool; - u32 query_pool_occupied[VulkanQueueKind_Count]; - - u32 next_command_buffer_index; - VkCommandPool command_pool; - VkCommandBuffer command_buffers[MaxCommandBuffersInFlight]; - u64 command_buffer_submission_values[MaxCommandBuffersInFlight]; - VulkanSemaphore timeline_semaphore; VkPipelineStageFlags2 pipeline_stage_flags; - - VulkanPipeline *bound_pipeline; } VulkanQueue; static_assert(alignof(VulkanQueue) == 64, "VulkanQueue must be placed on its own cacheline"); +typedef alignas(64) struct { + i32 lock; + i32 next_index; + + VulkanPipeline *bound_pipeline; + + VkCommandPool handle; + VkQueryPool query_pool; + VkCommandBuffer buffers[MaxCommandBuffersInFlight]; + + u64 submission_values[MaxCommandBuffersInFlight]; + u32 queries_occupied[MaxCommandBuffersInFlight]; +} VulkanCommandPool; + typedef struct { Arena arena; i32 arena_lock; @@ -136,7 +143,8 @@ typedef struct { static_assert(VK_MAX_MEMORY_TYPES < U8_MAX, ""); } memory_info; - VulkanQueue * queues[VulkanQueueKind_Count]; + VulkanCommandPool * command_pools[VulkanTimeline_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. @@ -355,9 +363,8 @@ function VkCommandBuffer vk_command_buffer(VulkanHandle h) { VulkanCommandBuffer *vcb = vk_entity_data(h, VulkanEntityKind_CommandBuffer); - VulkanQueue *vq = vulkan_context->queues[vcb->kind]; - - VkCommandBuffer result = vq->command_buffers[vcb->command_buffer_index]; + VulkanCommandPool *vcp = vulkan_context->command_pools[vcb->timeline]; + VkCommandBuffer result = vcp->buffers[vcb->buffer_index]; return result; } @@ -1208,6 +1215,7 @@ vk_load_queues(Arena *memory, Stream *err) // NOTE(rnp): start by assigning queue families for each queue /* NOTE(rnp): try for exclusive transfer queue */ + #if !ForceSingleQueue { u32 mask = VK_QUEUE_GRAPHICS_BIT|VK_QUEUE_COMPUTE_BIT|VK_QUEUE_TRANSFER_BIT; u32 max_timestamp_bits = 0; @@ -1230,6 +1238,7 @@ vk_load_queues(Arena *memory, Stream *err) break; } } + #endif /* !ForceSingleQueue */ /* NOTE(rnp): find graphics family and verify it is exclusive */ b32 multi_graphics = 0; @@ -1318,6 +1327,9 @@ vk_load_queues(Arena *memory, Stream *err) vk->queues[it] = vk->queues[vk->queue_indices[it]]; } + for EachElement(vk->command_pools, it) + vk->command_pools[it] = push_struct(memory, VulkanCommandPool); + VkDeviceQueueCreateInfo queue_create_infos[VulkanQueueKind_Count]; f32 queue_priorities[VulkanQueueKind_Count][VulkanQueueKind_Count]; @@ -1409,33 +1421,38 @@ vk_load_queues(Arena *memory, Stream *err) VulkanQueue *qp = vk->queues[q]; vkGetDeviceQueue(vk->device, qp->queue_family, qp->queue_index, &qp->queue); + qp->timeline_semaphore = vk_make_semaphore(0); + } + + vk->queues[VulkanQueueKind_Graphics]->pipeline_stage_flags |= VK_PIPELINE_STAGE_2_ALL_GRAPHICS_BIT; + vk->queues[VulkanQueueKind_Compute]->pipeline_stage_flags |= VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT; + + for EachElement(vk->command_pools, it) { + VulkanCommandPool *vcp = vk->command_pools[it]; + VkCommandPoolCreateInfo command_pool_create_info = { .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, .flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, - .queueFamilyIndex = qp->queue_family, + .queueFamilyIndex = vk->queues[it]->queue_family, }; - vkCreateCommandPool(vk->device, &command_pool_create_info, 0, &qp->command_pool); + + vkCreateCommandPool(vk->device, &command_pool_create_info, 0, &vcp->handle); VkCommandBufferAllocateInfo command_buffer_allocate_info = { .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, - .commandPool = qp->command_pool, + .commandPool = vcp->handle, .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY, - .commandBufferCount = countof(qp->command_buffers), + .commandBufferCount = countof(vcp->buffers), }; - vkAllocateCommandBuffers(vk->device, &command_buffer_allocate_info, qp->command_buffers); - - qp->timeline_semaphore = vk_make_semaphore(0); + vkAllocateCommandBuffers(vk->device, &command_buffer_allocate_info, vcp->buffers); VkQueryPoolCreateInfo query_pool_create_info = { .sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO, .queryType = VK_QUERY_TYPE_TIMESTAMP, - .queryCount = countof(qp->command_buffers) * MaxCommandBufferTimestamps, + .queryCount = MaxCommandBuffersInFlight * MaxCommandBufferTimestamps, }; - vkCreateQueryPool(vk->device, &query_pool_create_info, 0, &qp->query_pool); + vkCreateQueryPool(vk->device, &query_pool_create_info, 0, &vcp->query_pool); } - - vk->queues[VulkanQueueKind_Graphics]->pipeline_stage_flags |= VK_PIPELINE_STAGE_2_ALL_GRAPHICS_BIT; - vk->queues[VulkanQueueKind_Compute]->pipeline_stage_flags |= VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT; } function void @@ -1998,17 +2015,16 @@ vk_pipeline_release(VulkanHandle h) if (e->as.pipeline.stage_flags == VK_SHADER_STAGE_COMPUTE_BIT) timeline = VulkanTimeline_Compute; else timeline = VulkanTimeline_Graphics; - VulkanQueue *vq = vulkan_context->queues[timeline]; - DeferLoop(take_lock(&vq->lock, -1), release_lock(&vq->lock)) - { - u32 index = (vq->next_command_buffer_index - 1) % countof(vq->command_buffers); - vk_host_wait_timeline(timeline, vq->command_buffer_submission_values[index], -1ULL); - - if (&e->as.pipeline == vq->bound_pipeline) - vq->bound_pipeline = 0; - + // 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); vkDestroyPipeline(vulkan_context->device, e->as.pipeline.pipeline, 0); vkDestroyPipelineLayout(vulkan_context->device, e->as.pipeline.layout, 0); + + if (&e->as.pipeline == vcp->bound_pipeline) + vcp->bound_pipeline = 0; } vk_entity_release(e); } @@ -2019,31 +2035,31 @@ vk_command_begin(VulkanTimeline timeline) { VulkanHandle result = {0}; if Between(timeline, 0, VulkanTimeline_Count - 1) { - VulkanContext *vk = vulkan_context; - VulkanQueue *vq = vk->queues[timeline]; + VulkanContext *vk = vulkan_context; + VulkanCommandPool *vcp = vk->command_pools[timeline]; - take_lock(&vq->lock, -1); + take_lock(&vcp->lock, -1); VulkanEntity *e = vk_entity_allocate(VulkanEntityKind_CommandBuffer); VulkanCommandBuffer *vcb = &e->as.command_buffer; - u32 index = vq->next_command_buffer_index++ % countof(vq->command_buffers); - vcb->kind = (VulkanQueueKind)timeline; - vcb->command_buffer_index = index; + vcb->timeline = timeline; + vcb->buffer_index = vcp->next_index++ % countof(vcp->buffers); + 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, vq->command_buffer_submission_values[index], -1ULL); + b32 wait_result = vk_host_wait_timeline(timeline, vcp->submission_values[index], -1ULL); assert(wait_result); + vcp->queries_occupied[index] = 0; + VkCommandBufferBeginInfo buffer_begin_info = { .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, }; - vq->query_pool_occupied[index] = 0; - - vkBeginCommandBuffer(vq->command_buffers[index], &buffer_begin_info); - vkCmdResetQueryPool(vq->command_buffers[index], vq->query_pool, - index * MaxCommandBufferTimestamps, MaxCommandBufferTimestamps); + vkBeginCommandBuffer(vcp->buffers[index], &buffer_begin_info); + vkCmdResetQueryPool(vcp->buffers[index], vcp->query_pool, index * MaxCommandBufferTimestamps, + MaxCommandBufferTimestamps); result = (VulkanHandle){(u64)e}; } @@ -2056,30 +2072,30 @@ vk_command_bind_pipeline(VulkanHandle command, VulkanHandle pipeline) if ValidVulkanHandle(command) { VulkanContext *vk = vulkan_context; VulkanCommandBuffer *vcb = vk_entity_data(command, VulkanEntityKind_CommandBuffer); - VulkanQueue *vq = vk->queues[vcb->kind]; + VulkanCommandPool *vcp = vk->command_pools[vcb->timeline]; VulkanPipeline *vp = 0; if ValidVulkanHandle(pipeline) { vp = vk_entity_data(pipeline, VulkanEntityKind_Pipeline); - } else if (vcb->kind == VulkanQueueKind_Compute) { + } else if (vcb->timeline == VulkanTimeline_Compute) { vp = &vk->default_compute_pipeline; - } else if (vcb->kind == VulkanQueueKind_Graphics) { + } else if (vcb->timeline == VulkanTimeline_Graphics) { vp = &vk->default_graphics_pipeline; } else { InvalidCodePath; } - read_only local_persist VkPipelineBindPoint bind_point_lut[VulkanQueueKind_Count] = { - [VulkanQueueKind_Graphics] = VK_PIPELINE_BIND_POINT_GRAPHICS, - [VulkanQueueKind_Compute] = VK_PIPELINE_BIND_POINT_COMPUTE, - [VulkanQueueKind_Transfer] = -1, + 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, }; - VkPipelineBindPoint bind_point = bind_point_lut[vcb->kind]; + VkPipelineBindPoint bind_point = bind_point_lut[vcb->timeline]; assert(bind_point != (VkPipelineBindPoint)-1); - vkCmdBindPipeline(vq->command_buffers[vcb->command_buffer_index], bind_point, vp->pipeline); - vq->bound_pipeline = vp; + vkCmdBindPipeline(vcp->buffers[vcb->buffer_index], bind_point, vp->pipeline); + vcp->bound_pipeline = vp; } } @@ -2089,7 +2105,8 @@ vk_command_buffer_memory_barriers(VulkanHandle command, GPUMemoryBarrierInfo *ba if ValidVulkanHandle(command) { VulkanContext *vk = vulkan_context; VulkanCommandBuffer *vcb = vk_entity_data(command, VulkanEntityKind_CommandBuffer); - VulkanQueue *vq = vk->queues[vcb->kind]; + VulkanCommandPool *vcp = vk->command_pools[vcb->timeline]; + VulkanQueue *vq = vk->queues[vcb->timeline]; DeferLoop(take_lock(&vk->arena_lock, -1), release_lock(&vk->arena_lock)) { @@ -2119,7 +2136,7 @@ vk_command_buffer_memory_barriers(VulkanHandle command, GPUMemoryBarrierInfo *ba .pBufferMemoryBarriers = memory_barriers, }; - vkCmdPipelineBarrier2(vq->command_buffers[vcb->command_buffer_index], &dependancy_info); + vkCmdPipelineBarrier2(vcp->buffers[vcb->buffer_index], &dependancy_info); } } } @@ -2141,13 +2158,12 @@ vk_command_push_constants(VulkanHandle command, u32 offset, u32 size, void *valu { if ValidVulkanHandle(command) { VulkanCommandBuffer *vcb = vk_entity_data(command, VulkanEntityKind_CommandBuffer); - VulkanQueue *vq = vulkan_context->queues[vcb->kind]; - VulkanPipeline *vp = vq->bound_pipeline; + VulkanCommandPool *vcp = vulkan_context->command_pools[vcb->timeline]; + VulkanPipeline *vp = vcp->bound_pipeline; assert(vp); - vkCmdPushConstants(vq->command_buffers[vcb->command_buffer_index], vp->layout, vp->stage_flags, - offset, size, values); + vkCmdPushConstants(vcp->buffers[vcb->buffer_index], vp->layout, vp->stage_flags, offset, size, values); } } @@ -2157,22 +2173,21 @@ vk_command_timestamp(VulkanHandle command) if ValidVulkanHandle(command) { VulkanContext *vk = vulkan_context; VulkanCommandBuffer *vcb = vk_entity_data(command, VulkanEntityKind_CommandBuffer); - VulkanQueue *vq = vk->queues[vcb->kind]; + VulkanCommandPool *vcp = vk->command_pools[vcb->timeline]; - read_only local_persist VkPipelineStageFlags2 stage_lut[VulkanQueueKind_Count] = { - [VulkanQueueKind_Graphics] = VK_PIPELINE_STAGE_2_ALL_GRAPHICS_BIT, - [VulkanQueueKind_Compute] = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, - [VulkanQueueKind_Transfer] = -1, + 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, }; - VkPipelineStageFlags2 stage = stage_lut[vcb->kind]; + VkPipelineStageFlags2 stage = stage_lut[vcb->timeline]; assert(stage != (VkPipelineStageFlags2)-1); - if (vq->query_pool_occupied[vcb->command_buffer_index] < MaxCommandBufferTimestamps) { - u32 query_index = vq->query_pool_occupied[vcb->command_buffer_index]++; - vkCmdWriteTimestamp2(vq->command_buffers[vcb->command_buffer_index], stage, - vq->query_pool, - vcb->command_buffer_index * MaxCommandBufferTimestamps + query_index); + 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, + vcb->buffer_index * MaxCommandBufferTimestamps + query_index); } } } @@ -2196,77 +2211,80 @@ vk_command_end(VulkanHandle command, VulkanHandle wait_semaphore, VulkanHandle f if ValidVulkanHandle(command) { VulkanContext *vk = vulkan_context; VulkanCommandBuffer *vcb = vk_entity_data(command, VulkanEntityKind_CommandBuffer); - VulkanQueue *vq = vk->queues[vcb->kind]; + VulkanCommandPool *vcp = vk->command_pools[vcb->timeline]; + VulkanQueue *vq = vk->queues[vcb->timeline]; VulkanSemaphore *vs = &vq->timeline_semaphore; - vkEndCommandBuffer(vq->command_buffers[vcb->command_buffer_index]); + vkEndCommandBuffer(vcp->buffers[vcb->buffer_index]); - VkCommandBufferSubmitInfo command_buffer_submit_info = { - .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO, - .commandBuffer = vq->command_buffers[vcb->command_buffer_index], - }; - - result = ++vs->value; + DeferLoop(take_lock(&vq->lock, -1), release_lock(&vq->lock)) { + VkCommandBufferSubmitInfo command_buffer_submit_info = { + .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO, + .commandBuffer = vcp->buffers[vcb->buffer_index], + }; - u32 signal_submit_info_count = 1; - VkSemaphoreSubmitInfo signal_submit_infos[2] = {{ - .sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO, - .semaphore = vs->semaphore, - .value = result, - .stageMask = vq->pipeline_stage_flags, - }}; + result = ++vs->value; - if ValidVulkanHandle(finished_semaphore) { - VulkanSemaphore *fs = vk_entity_data(finished_semaphore, VulkanEntityKind_Semaphore); - signal_submit_infos[signal_submit_info_count++] = (VkSemaphoreSubmitInfo){ + u32 signal_submit_info_count = 1; + VkSemaphoreSubmitInfo signal_submit_infos[2] = {{ .sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO, - .semaphore = fs->semaphore, + .semaphore = vs->semaphore, + .value = result, .stageMask = vq->pipeline_stage_flags, - }; - } + }}; - u32 wait_submit_info_count = 0; - VkSemaphoreSubmitInfo wait_submit_infos[VulkanQueueKind_Count + 1]; - for (u32 i = 0; i < vk->unique_queues; i++) { - u32 queue_index = vk->queue_indices[i]; - if (vcb->in_flight_wait_values[queue_index] > 0) { - VulkanQueue *q = vk->queues[queue_index]; - VkSemaphoreSubmitInfo wait_ssi = { + if ValidVulkanHandle(finished_semaphore) { + VulkanSemaphore *fs = vk_entity_data(finished_semaphore, VulkanEntityKind_Semaphore); + signal_submit_infos[signal_submit_info_count++] = (VkSemaphoreSubmitInfo){ .sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO, - .semaphore = q->timeline_semaphore.semaphore, - .value = vcb->in_flight_wait_values[queue_index], - .stageMask = q->pipeline_stage_flags, + .semaphore = fs->semaphore, + .stageMask = vq->pipeline_stage_flags, }; - wait_submit_infos[wait_submit_info_count++] = wait_ssi; } - } - if ValidVulkanHandle(wait_semaphore) { - VulkanSemaphore *ws = vk_entity_data(wait_semaphore, VulkanEntityKind_Semaphore); - wait_submit_infos[wait_submit_info_count++] = (VkSemaphoreSubmitInfo){ - .sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO, - .semaphore = ws->semaphore, - .stageMask = vq->pipeline_stage_flags, - }; - } + u32 wait_submit_info_count = 0; + VkSemaphoreSubmitInfo wait_submit_infos[VulkanQueueKind_Count + 1]; + for (u32 i = 0; i < vk->unique_queues; i++) { + u32 queue_index = vk->queue_indices[i]; + if (vcb->in_flight_wait_values[queue_index] > 0) { + VulkanQueue *q = vk->queues[queue_index]; + VkSemaphoreSubmitInfo wait_ssi = { + .sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO, + .semaphore = q->timeline_semaphore.semaphore, + .value = vcb->in_flight_wait_values[queue_index], + .stageMask = q->pipeline_stage_flags, + }; + wait_submit_infos[wait_submit_info_count++] = wait_ssi; + } + } - VkSubmitInfo2 submit_info = { - .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO_2, - .commandBufferInfoCount = 1, - .pCommandBufferInfos = &command_buffer_submit_info, - .waitSemaphoreInfoCount = wait_submit_info_count, - .pWaitSemaphoreInfos = wait_submit_infos, - .signalSemaphoreInfoCount = signal_submit_info_count, - .pSignalSemaphoreInfos = signal_submit_infos, - }; + if ValidVulkanHandle(wait_semaphore) { + VulkanSemaphore *ws = vk_entity_data(wait_semaphore, VulkanEntityKind_Semaphore); + wait_submit_infos[wait_submit_info_count++] = (VkSemaphoreSubmitInfo){ + .sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO, + .semaphore = ws->semaphore, + .stageMask = vq->pipeline_stage_flags, + }; + } + + VkSubmitInfo2 submit_info = { + .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO_2, + .commandBufferInfoCount = 1, + .pCommandBufferInfos = &command_buffer_submit_info, + .waitSemaphoreInfoCount = wait_submit_info_count, + .pWaitSemaphoreInfos = wait_submit_infos, + .signalSemaphoreInfoCount = signal_submit_info_count, + .pSignalSemaphoreInfos = signal_submit_infos, + }; - vkQueueSubmit2(vq->queue, 1, &submit_info, 0); + vkQueueSubmit2(vq->queue, 1, &submit_info, 0); - vq->bound_pipeline = 0; + vcp->bound_pipeline = 0; - atomic_store_u64(vq->command_buffer_submission_values + vcb->command_buffer_index, result); + atomic_store_u64(vcp->submission_values + vcb->buffer_index, result); + } - release_lock(&vq->lock); + release_lock(&vcp->lock); vk_entity_release((VulkanEntity *)command.value[0]); } @@ -2458,18 +2476,18 @@ vk_command_read_timestamps(VulkanTimeline timeline, Arena *arena) { u64 *result = 0; if Between(timeline, 0, VulkanTimeline_Count - 1) { - VulkanContext *vk = vulkan_context; - VulkanQueue *vq = vk->queues[timeline]; - DeferLoop(take_lock(&vq->lock, -1), release_lock(&vq->lock)) { - u32 index = (vq->next_command_buffer_index - 1) % countof(vq->command_buffers); - u32 count = vq->query_pool_occupied[index]; + 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, vq->command_buffer_submission_values[index], -1ULL); + vk_host_wait_timeline(timeline, vcp->submission_values[index], -1ULL); - vkGetQueryPoolResults(vk->device, vq->query_pool, index * MaxCommandBufferTimestamps, count, + vkGetQueryPoolResults(vk->device, vcp->query_pool, index * MaxCommandBufferTimestamps, count, count * sizeof(u64), result + 1, 8, VK_QUERY_RESULT_WAIT_BIT); } }