@@ -70,7 +70,12 @@ class VulkanExample : public VulkanExampleBase
7070 VkCommandPool commandPool; // Use a separate command pool (queue family may differ from the one used for graphics)
7171 std::array<VkCommandBuffer, maxConcurrentFrames> commandBuffers; // Command buffer storing the dispatch commands and barriers
7272 std::array<VkFence, maxConcurrentFrames> fences; // Synchronization fence to avoid rewriting compute CB if still in use
73- std::array<VkSemaphore, maxConcurrentFrames> semaphores; // Used as a wait semaphore for graphics submission
73+ struct ComputeSemaphores {
74+ VkSemaphore ready{ VK_NULL_HANDLE };
75+ VkSemaphore complete{ VK_NULL_HANDLE };
76+ };
77+ std::array<ComputeSemaphores, maxConcurrentFrames> semaphores{}; // Used as a wait semaphore for graphics submission
78+ // std::array<VkSemaphore, maxConcurrentFrames> semaphores; // Used as a wait semaphore for graphics submission
7479 VkDescriptorSetLayout descriptorSetLayout; // Compute shader binding layout
7580 std::array<VkDescriptorSet, maxConcurrentFrames> descriptorSets{}; // Compute shader bindings
7681 VkPipelineLayout pipelineLayout; // Layout of the compute pipeline
@@ -90,7 +95,6 @@ class VulkanExample : public VulkanExampleBase
9095 camera.setPerspective (60 .0f , (float )width / (float )height, 0 .1f , 512 .0f );
9196 camera.setTranslation (glm::vec3 (0 .5f , 0 .0f , 0 .0f ));
9297 camera.movementSpeed = 5 .0f ;
93- settings.overlay = false ;
9498 }
9599
96100 ~VulkanExample ()
@@ -118,7 +122,8 @@ class VulkanExample : public VulkanExampleBase
118122 vkDestroyFence (device, fence, nullptr );
119123 }
120124 for (auto & semaphore : compute.semaphores ) {
121- vkDestroySemaphore (device, semaphore, nullptr );
125+ vkDestroySemaphore (device, semaphore.complete , nullptr );
126+ vkDestroySemaphore (device, semaphore.ready , nullptr );
122127 }
123128
124129 }
@@ -406,37 +411,17 @@ class VulkanExample : public VulkanExampleBase
406411
407412 std::vector<VkDescriptorSetLayoutBinding> setLayoutBindings = {
408413 // Binding 0: Instance input data buffer
409- vks::initializers::descriptorSetLayoutBinding (
410- VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
411- VK_SHADER_STAGE_COMPUTE_BIT,
412- 0 ),
414+ vks::initializers::descriptorSetLayoutBinding (VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT, 0 ),
413415 // Binding 1: Indirect draw command output buffer (input)
414- vks::initializers::descriptorSetLayoutBinding (
415- VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
416- VK_SHADER_STAGE_COMPUTE_BIT,
417- 1 ),
416+ vks::initializers::descriptorSetLayoutBinding (VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT, 1 ),
418417 // Binding 2: Uniform buffer with global matrices (input)
419- vks::initializers::descriptorSetLayoutBinding (
420- VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
421- VK_SHADER_STAGE_COMPUTE_BIT,
422- 2 ),
418+ vks::initializers::descriptorSetLayoutBinding (VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT, 2 ),
423419 // Binding 3: Indirect draw stats (output)
424- vks::initializers::descriptorSetLayoutBinding (
425- VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
426- VK_SHADER_STAGE_COMPUTE_BIT,
427- 3 ),
420+ vks::initializers::descriptorSetLayoutBinding (VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT, 3 ),
428421 // Binding 4: LOD info (input)
429- vks::initializers::descriptorSetLayoutBinding (
430- VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
431- VK_SHADER_STAGE_COMPUTE_BIT,
432- 4 ),
422+ vks::initializers::descriptorSetLayoutBinding (VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT,4 ),
433423 };
434-
435- VkDescriptorSetLayoutCreateInfo descriptorLayout =
436- vks::initializers::descriptorSetLayoutCreateInfo (
437- setLayoutBindings.data (),
438- static_cast <uint32_t >(setLayoutBindings.size ()));
439-
424+ VkDescriptorSetLayoutCreateInfo descriptorLayout = vks::initializers::descriptorSetLayoutCreateInfo (setLayoutBindings);
440425 VK_CHECK_RESULT (vkCreateDescriptorSetLayout (device, &descriptorLayout, nullptr , &compute.descriptorSetLayout ));
441426
442427 VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = vks::initializers::pipelineLayoutCreateInfo (&compute.descriptorSetLayout , 1 );
@@ -445,8 +430,7 @@ class VulkanExample : public VulkanExampleBase
445430 for (auto i = 0 ; i < uniformBuffers.size (); i++) {
446431 VkDescriptorSetAllocateInfo allocInfo = vks::initializers::descriptorSetAllocateInfo (descriptorPool, &compute.descriptorSetLayout , 1 );
447432 VK_CHECK_RESULT (vkAllocateDescriptorSets (device, &allocInfo, &compute.descriptorSets [i]));
448- std::vector<VkWriteDescriptorSet> computeWriteDescriptorSets =
449- {
433+ std::vector<VkWriteDescriptorSet> computeWriteDescriptorSets = {
450434 // Binding 0: Instance input data buffer
451435 vks::initializers::writeDescriptorSet (compute.descriptorSets [i], VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 0 , &instanceBuffer.descriptor ),
452436 // Binding 1: Indirect draw command output buffer
@@ -504,8 +488,14 @@ class VulkanExample : public VulkanExampleBase
504488 // Semaphores to order compute and graphics submissions
505489 for (auto & semaphore : compute.semaphores ) {
506490 VkSemaphoreCreateInfo semaphoreInfo{ .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO };
507- vkCreateSemaphore (device, &semaphoreInfo, nullptr , &semaphore);
491+ VK_CHECK_RESULT (vkCreateSemaphore (device, &semaphoreInfo, nullptr , &semaphore.complete ));
492+ VK_CHECK_RESULT (vkCreateSemaphore (device, &semaphoreInfo, nullptr , &semaphore.ready ));
508493 }
494+ // Signal first used ready semaphore
495+ VkSubmitInfo computeSubmitInfo = vks::initializers::submitInfo ();
496+ computeSubmitInfo.signalSemaphoreCount = 1 ;
497+ computeSubmitInfo.pSignalSemaphores = &compute.semaphores [-1 % maxConcurrentFrames].ready ;
498+ VK_CHECK_RESULT (vkQueueSubmit (compute.queue , 1 , &computeSubmitInfo, VK_NULL_HANDLE));
509499 }
510500
511501 void updateUniformBuffer ()
@@ -731,8 +721,6 @@ class VulkanExample : public VulkanExampleBase
731721 0 , nullptr );
732722 }
733723
734- // todo: barrier for indirect stats buffer?
735-
736724 vkEndCommandBuffer (cmdBuffer);
737725 }
738726
@@ -741,55 +729,55 @@ class VulkanExample : public VulkanExampleBase
741729 if (!prepared)
742730 return ;
743731
744- VulkanExampleBase::prepareFrame (false );
745-
746732 // Submit compute commands
747-
748- VK_CHECK_RESULT (vkWaitForFences (device, 1 , &compute.fences [currentBuffer], VK_TRUE, UINT64_MAX));
749- VK_CHECK_RESULT (vkResetFences (device, 1 , &compute.fences [currentBuffer]));
750-
751- // Get draw count from compute
752- memcpy (&indirectStats, indirectDrawCountBuffers[currentBuffer].mapped , sizeof (indirectStats));
753-
754- // updateComputeUniformBuffers();
755- buildComputeCommandBuffer ();
756-
757- // Wait for rendering finished
758- VkPipelineStageFlags waitStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
759-
760- VkSubmitInfo computeSubmitInfo = vks::initializers::submitInfo ();
761- computeSubmitInfo.commandBufferCount = 1 ;
762- computeSubmitInfo.pCommandBuffers = &compute.commandBuffers [currentBuffer];
763- computeSubmitInfo.pWaitDstStageMask = &waitStageMask;
764- computeSubmitInfo.signalSemaphoreCount = 1 ;
765- computeSubmitInfo.pSignalSemaphores = &compute.semaphores [currentBuffer];
766- VK_CHECK_RESULT (vkQueueSubmit (compute.queue , 1 , &computeSubmitInfo, compute.fences [currentBuffer]));
767-
768- // Submit graphics commands
769-
770- VK_CHECK_RESULT (vkWaitForFences (device, 1 , &waitFences[currentBuffer], VK_TRUE, UINT64_MAX));
771- VK_CHECK_RESULT (vkResetFences (device, 1 , &waitFences[currentBuffer]));
772-
773- // @todo: need to split for new sycn
774- updateUniformBuffer ();
775- buildGraphicsCommandBuffer ();
776-
777- VkPipelineStageFlags graphicsWaitStageMasks[] = { VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT };
778- VkSemaphore graphicsWaitSemaphores[] = { compute.semaphores [currentBuffer], presentCompleteSemaphores[currentBuffer] };
733+ {
734+ VK_CHECK_RESULT (vkWaitForFences (device, 1 , &compute.fences [currentBuffer], VK_TRUE, UINT64_MAX));
735+ VK_CHECK_RESULT (vkResetFences (device, 1 , &compute.fences [currentBuffer]));
736+
737+ // Get draw count from compute
738+ memcpy (&indirectStats, indirectDrawCountBuffers[currentBuffer].mapped , sizeof (indirectStats));
739+ buildComputeCommandBuffer ();
740+
741+ // Wait for rendering finished
742+ VkPipelineStageFlags waitDstStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
743+ VkSubmitInfo submitInfo = vks::initializers::submitInfo ();
744+ submitInfo.waitSemaphoreCount = 1 ;
745+ submitInfo.pWaitSemaphores = &compute.semaphores [((int )currentBuffer - 1 ) % maxConcurrentFrames].ready ;
746+ submitInfo.pWaitDstStageMask = &waitDstStageMask;
747+ submitInfo.signalSemaphoreCount = 1 ;
748+ submitInfo.pSignalSemaphores = &compute.semaphores [currentBuffer].complete ;
749+ submitInfo.commandBufferCount = 1 ;
750+ submitInfo.pCommandBuffers = &compute.commandBuffers [currentBuffer];
751+ VK_CHECK_RESULT (vkQueueSubmit (compute.queue , 1 , &submitInfo, compute.fences [currentBuffer]));
752+ }
779753
780754 // Submit graphics commands
781- VkSubmitInfo graphicsSubmitInfo = vks::initializers::submitInfo ();
782- graphicsSubmitInfo.commandBufferCount = 1 ;
783- graphicsSubmitInfo.pCommandBuffers = &drawCmdBuffers[currentBuffer];
784- graphicsSubmitInfo.waitSemaphoreCount = 2 ;
785- graphicsSubmitInfo.pWaitSemaphores = graphicsWaitSemaphores;
786- graphicsSubmitInfo.pWaitDstStageMask = graphicsWaitStageMasks;
787- graphicsSubmitInfo.signalSemaphoreCount = 1 ;
788- graphicsSubmitInfo.pSignalSemaphores = &renderCompleteSemaphores[currentImageIndex];
789- VK_CHECK_RESULT (vkQueueSubmit (queue, 1 , &graphicsSubmitInfo, waitFences[currentBuffer]));
790-
791- VulkanExampleBase::submitFrame (VK_NULL_HANDLE, true );
792-
755+ {
756+ VK_CHECK_RESULT (vkWaitForFences (device, 1 , &waitFences[currentBuffer], VK_TRUE, UINT64_MAX));
757+ VK_CHECK_RESULT (vkResetFences (device, 1 , &waitFences[currentBuffer]));
758+
759+ VulkanExampleBase::prepareFrame (false );
760+
761+ updateUniformBuffer ();
762+ buildGraphicsCommandBuffer ();
763+
764+ VkPipelineStageFlags waitDstStageMask[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT };
765+ VkSemaphore waitSemaphores[2 ] = { presentCompleteSemaphores[currentBuffer], compute.semaphores [currentBuffer].complete };
766+ VkSemaphore signalSemaphores[2 ] = { renderCompleteSemaphores[currentImageIndex], compute.semaphores [currentBuffer].ready };
767+
768+ // Submit graphics commands
769+ VkSubmitInfo submitInfo = vks::initializers::submitInfo ();
770+ submitInfo.waitSemaphoreCount = 2 ;
771+ submitInfo.pWaitDstStageMask = waitDstStageMask;
772+ submitInfo.pWaitSemaphores = waitSemaphores;
773+ submitInfo.commandBufferCount = 1 ;
774+ submitInfo.pCommandBuffers = &drawCmdBuffers[currentBuffer];
775+ submitInfo.signalSemaphoreCount = 2 ;
776+ submitInfo.pSignalSemaphores = signalSemaphores;
777+ VK_CHECK_RESULT (vkQueueSubmit (queue, 1 , &submitInfo, waitFences[currentBuffer]));
778+
779+ VulkanExampleBase::submitFrame (VK_NULL_HANDLE, true );
780+ }
793781 }
794782
795783 virtual void OnUpdateUIOverlay (vks::UIOverlay *overlay)
0 commit comments