@@ -237,7 +237,7 @@ class ASyncThreadRunner {
237
237
vulkan::CreateFence (&app_->device ()),
238
238
app_->CreateAndBindDeviceBuffer (&create_info),
239
239
app_->GetCommandBuffer (app_->async_compute_queue ()->index ()),
240
- app_->GetCommandBuffer (),
240
+ app_->GetCommandBuffer (), app_-> GetCommandBuffer (),
241
241
containers::make_unique<vulkan::DescriptorSet>(
242
242
allocator_, app_->AllocateDescriptorSet (
243
243
{compute_descriptor_set_layouts_[0 ],
@@ -349,29 +349,75 @@ class ASyncThreadRunner {
349
349
command_buffer->vkEndCommandBuffer (command_buffer);
350
350
ready_buffers_.push_back (static_cast <uint32_t >(i));
351
351
352
- // Wake command buffer
353
- auto & wake_command_buffer = dat.wake_command_buffer_ ;
354
- wake_command_buffer->vkBeginCommandBuffer (
355
- wake_command_buffer, &sample_application::kBeginCommandBuffer );
356
- VkBufferMemoryBarrier wake_barrier = {
357
- VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, // sType
358
- nullptr , // pNext
359
- VK_ACCESS_SHADER_READ_BIT, // srcAccessMask
360
- 0 , // dstAccessMask
361
- app_->render_queue ().index (), // srcQueueFamilyIndex
362
- app_->async_compute_queue ()->index (), // dstQueueFamilyIndex
363
- *dat.render_ssbo_ , // buffer
364
- 0 , // offset
365
- dat.render_ssbo_ ->size (), // size
366
- };
367
- wake_command_buffer->vkCmdPipelineBarrier (
368
- wake_command_buffer, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT,
369
- VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0 , 0 , nullptr , 1 , &wake_barrier,
370
- 0 , nullptr );
352
+ {
353
+ // Acquire command buffer
354
+ auto & acquire_command_buffer = dat.acquire_command_buffer_ ;
355
+ acquire_command_buffer->vkBeginCommandBuffer (
356
+ acquire_command_buffer, &sample_application::kBeginCommandBuffer );
357
+
358
+ VkBufferMemoryBarrier barrier = {
359
+ VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, // sType
360
+ nullptr , // pNext
361
+ 0 , // srcAccessMask
362
+ VK_ACCESS_SHADER_READ_BIT, // dstAccessMask
363
+ app_->async_compute_queue ()->index (), // srcQueueFamilyIndex
364
+ app_->render_queue ().index (), // dstQueueFamilyIndex
365
+ *dat.render_ssbo_ , // bufferdraw_data
366
+ 0 , // offset
367
+ dat.render_ssbo_ ->size (), // size
368
+ };
369
+ acquire_command_buffer->vkCmdPipelineBarrier (
370
+ acquire_command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
371
+ VK_PIPELINE_STAGE_VERTEX_SHADER_BIT, 0 , 0 , nullptr , 1 , &barrier, 0 ,
372
+ nullptr );
373
+ acquire_command_buffer->vkEndCommandBuffer (acquire_command_buffer);
374
+ }
371
375
372
- wake_command_buffer->vkEndCommandBuffer (wake_command_buffer);
376
+ {
377
+ // Wake command buffer
378
+ auto & wake_command_buffer = dat.wake_command_buffer_ ;
379
+ wake_command_buffer->vkBeginCommandBuffer (
380
+ wake_command_buffer, &sample_application::kBeginCommandBuffer );
381
+ VkBufferMemoryBarrier wake_barrier = {
382
+ VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, // sType
383
+ nullptr , // pNext
384
+ VK_ACCESS_SHADER_READ_BIT, // srcAccessMask
385
+ 0 , // dstAccessMask
386
+ app_->render_queue ().index (), // srcQueueFamilyIndex
387
+ app_->async_compute_queue ()->index (), // dstQueueFamilyIndex
388
+ *dat.render_ssbo_ , // buffer
389
+ 0 , // offset
390
+ dat.render_ssbo_ ->size (), // size
391
+ };
392
+ wake_command_buffer->vkCmdPipelineBarrier (
393
+ wake_command_buffer, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT,
394
+ VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0 , 0 , nullptr , 1 ,
395
+ &wake_barrier, 0 , nullptr );
396
+
397
+ wake_command_buffer->vkEndCommandBuffer (wake_command_buffer);
398
+ }
373
399
}
374
400
401
+ std::vector<VkCommandBuffer> all_wake_command_buffers;
402
+ for (const auto & dat : data_) {
403
+ all_wake_command_buffers.push_back (dat.wake_command_buffer_ );
404
+ }
405
+
406
+ VkSubmitInfo wake_all_submit_info{
407
+ VK_STRUCTURE_TYPE_SUBMIT_INFO, // sType
408
+ nullptr , // pNext
409
+ 0 , // waitSemaphoreCount
410
+ nullptr , // pWaitSemaphores
411
+ nullptr , // pWaitDstStageMask,
412
+ static_cast <uint32_t >(all_wake_command_buffers.size ()),
413
+ all_wake_command_buffers.data (),
414
+ 0 , // signalSemaphoreCount
415
+ nullptr // pSignalSemaphores
416
+ };
417
+ app_->render_queue ()->vkQueueSubmit (app_->render_queue (), 1 ,
418
+ &wake_all_submit_info,
419
+ ::VkFence (VK_NULL_HANDLE));
420
+
375
421
(*initial_data_buffer)->vkEndCommandBuffer (*initial_data_buffer);
376
422
VkSubmitInfo setup_submit_info{
377
423
VK_STRUCTURE_TYPE_SUBMIT_INFO, // sType
@@ -426,28 +472,23 @@ class ASyncThreadRunner {
426
472
427
473
int32_t mb = mailbox_buffer_;
428
474
mailbox_buffer_ = -1 ;
429
- if (index != -1 ) {
430
- // Enqueues a command-buffer that transitions the buffer back to
431
- // the compute queue. It also sets the fence that we can wait on
432
- // in the future.
433
- auto & data = data_[index ];
434
- VkSubmitInfo wake_submit_info{
435
- VK_STRUCTURE_TYPE_SUBMIT_INFO, // sType
436
- nullptr , // pNext
437
- 0 , // waitSemaphoreCount
438
- nullptr , // pWaitSemaphores
439
- nullptr , // pWaitDstStageMask,
440
- 1 , // commandBufferCount
441
- &(data.wake_command_buffer_ .get_command_buffer ()),
442
- 0 , // signalSemaphoreCount
443
- nullptr // pSignalSemaphores
444
- };
445
475
446
- app_->render_queue ()->vkQueueSubmit (
447
- app_->render_queue (), 1 , &wake_submit_info, data.return_fence_ );
448
- returned_buffers_.push_back (index );
476
+ // Acquire the mailbox buffer to the gfx queue for rendering
477
+ TransferBuffer (mb, true , false );
478
+
479
+ if (index != -1 ) {
480
+ // Release the previously rendered buffer back to async compute
481
+ TransferBuffer (index , false , true );
449
482
}
450
483
484
+ for (int32_t released : released_buffers_) {
485
+ if (released != mb) {
486
+ // Acquire and immediately release any other buffers that have been
487
+ // released by async compute.
488
+ TransferBuffer (released, true , true );
489
+ }
490
+ }
491
+ released_buffers_.clear ();
451
492
return mb;
452
493
}
453
494
@@ -597,12 +638,38 @@ class ASyncThreadRunner {
597
638
// already in the mailbox, moves it to the ready_buffers_.
598
639
void PutBufferInMailbox (int32_t buffer) {
599
640
std::lock_guard<std::mutex> lock (data_mutex_);
600
- if (mailbox_buffer_ != -1 ) {
601
- ready_buffers_.push_back (mailbox_buffer_);
602
- }
603
641
mailbox_buffer_ = buffer;
642
+ released_buffers_.push_back (buffer);
604
643
}
605
644
645
+ // Acquires and/or releases a buffer *on the graphics queue*
646
+ void TransferBuffer (int32_t index, bool acquire_to_gfx,
647
+ bool release_from_gfx) {
648
+ std::vector<VkCommandBuffer> command_buffers;
649
+ auto & data = data_[index ];
650
+ VkFence fence = VK_NULL_HANDLE;
651
+ if (acquire_to_gfx) {
652
+ command_buffers.push_back (data.acquire_command_buffer_ );
653
+ }
654
+ if (release_from_gfx) {
655
+ command_buffers.push_back (data.wake_command_buffer_ );
656
+ fence = data.return_fence_ ;
657
+ returned_buffers_.push_back (index );
658
+ }
659
+ VkSubmitInfo submit_info{
660
+ VK_STRUCTURE_TYPE_SUBMIT_INFO, // sType
661
+ nullptr , // pNext
662
+ 0 , // waitSemaphoreCount
663
+ nullptr , // pWaitSemaphores
664
+ nullptr , // pWaitDstStageMask,
665
+ static_cast <uint32_t >(command_buffers.size ()), // commandBufferCount
666
+ command_buffers.data (),
667
+ 0 , // signalSemaphoreCount
668
+ nullptr // pSignalSemaphores
669
+ };
670
+ app_->render_queue ()->vkQueueSubmit (app_->render_queue (), 1 , &submit_info,
671
+ fence);
672
+ }
606
673
struct PrivateAsyncData {
607
674
// Fence that is signalled once a buffer is returned.
608
675
vulkan::VkFence return_fence_;
@@ -612,6 +679,8 @@ class ASyncThreadRunner {
612
679
vulkan::VkCommandBuffer command_buffer_;
613
680
// The command buffer for transferring this back to the simulation thread.
614
681
vulkan::VkCommandBuffer wake_command_buffer_;
682
+ // The command buffer for acquiring this from the simulation thread.
683
+ vulkan::VkCommandBuffer acquire_command_buffer_;
615
684
// The descriptor set needed for simulating.
616
685
containers::unique_ptr<vulkan::DescriptorSet> compute_descriptor_set_;
617
686
};
@@ -651,6 +720,8 @@ class ASyncThreadRunner {
651
720
652
721
// The current buffer sitting in the output mailbox.
653
722
int32_t mailbox_buffer_;
723
+ // Buffers that have been released by async and need to be acquired by gfx
724
+ std::vector<int32_t > released_buffers_;
654
725
bool first = true ;
655
726
int current_frame = 0 ;
656
727
@@ -878,7 +949,6 @@ class AsyncSample : public sample_application::Sample<AsyncFrameData> {
878
949
current_computation_result_buffer_ =
879
950
thread_runner_.TryToReturnAndGetNextBuffer (
880
951
current_computation_result_buffer_);
881
- bool swapped_buffer = old_buffer != current_computation_result_buffer_;
882
952
auto * buffer =
883
953
thread_runner_.GetBufferForIndex (current_computation_result_buffer_);
884
954
aspect_buffer_->UpdateBuffer (&app ()->render_queue (), frame_index);
@@ -971,26 +1041,6 @@ class AsyncSample : public sample_application::Sample<AsyncFrameData> {
971
1041
vulkan::MemoryClear (&clear);
972
1042
clear.color .float32 [3 ] = 1 .0f ;
973
1043
974
- if (swapped_buffer) {
975
- // If we have not transitioned this buffer yet, then move it from
976
- // the compute queue over to this queue.
977
- VkBufferMemoryBarrier barrier = {
978
- VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, // sType
979
- nullptr , // pNext
980
- 0 , // srcAccessMask
981
- VK_ACCESS_SHADER_READ_BIT, // dstAccessMask
982
- app ()->async_compute_queue ()->index (), // srcQueueFamilyIndex
983
- app ()->render_queue ().index (), // dstQueueFamilyIndex
984
- *buffer, // bufferdraw_data
985
- 0 , // offset
986
- buffer->size (), // size
987
- };
988
- cmdBuffer->vkCmdPipelineBarrier (cmdBuffer,
989
- VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
990
- VK_PIPELINE_STAGE_VERTEX_SHADER_BIT, 0 , 0 ,
991
- nullptr , 1 , &barrier, 0 , nullptr );
992
- }
993
-
994
1044
// The rest of the normal drawing.
995
1045
VkRenderPassBeginInfo pass_begin = {
996
1046
VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, // sType
0 commit comments