@@ -10,6 +10,12 @@ import org.lwjgl.vulkan.{VK13, VkCommandBuffer, VkCommandBufferSubmitInfo, VkSem
1010
1111import scala .collection .mutable
1212
13+ /** A command buffer that is pending execution, along with its dependencies and cleanup actions.
14+ *
15+ * You can call `close()` only when `isFinished || isPending` is true
16+ *
17+ * You can call `destroy()` only when all dependants are `isClosed`
18+ */
1319class PendingExecution (protected val handle : VkCommandBuffer , val dependencies : Seq [PendingExecution ], cleanup : () => Unit )(using Device ):
1420 private val semaphore : Semaphore = Semaphore ()
1521 private var fence : Option [Fence ] = None
@@ -23,6 +29,7 @@ class PendingExecution(protected val handle: VkCommandBuffer, val dependencies:
2329 private var closed = false
2430 def isClosed : Boolean = closed
2531 private def close (): Unit =
32+ assert(isFinished || isPending, " Cannot close a PendingExecution that is not finished or pending" )
2633 if closed then return
2734 cleanup()
2835 closed = true
@@ -35,24 +42,29 @@ class PendingExecution(protected val handle: VkCommandBuffer, val dependencies:
3542 fence.foreach(x => if x.isAlive then x.destroy())
3643 destroyed = true
3744
38- private def setFence (f : Fence ): Unit = {
39- if ! isPending then return
40- fence = Some (f)
41- dependencies.foreach(_.setFence(f))
42- }
43-
44- private def gatherForSubmission : Seq [((VkCommandBuffer , Semaphore ), Set [Semaphore ])] =
45+ /** Gathers all command buffers and their semaphores for submission to the queue, in the correct order.
46+ *
47+ * When you call this method, you are expected to submit the command buffers to the queue, and signal the provided fence when done.
48+ * @param f
49+ * The fence to signal when the command buffers are done executing.
50+ * @return
51+ * A sequence of tuples, each containing a command buffer, semaphore to signal, and a set of semaphores to wait on.
52+ */
53+ private def gatherForSubmission (f : Fence ): Seq [((VkCommandBuffer , Semaphore ), Set [Semaphore ])] =
4554 if ! isPending then return Seq .empty
4655 val mySubmission = ((handle, semaphore), dependencies.map(_.semaphore).toSet)
47- dependencies.flatMap(_.gatherForSubmission).appended(mySubmission)
56+ fence = Some (f)
57+ dependencies.flatMap(_.gatherForSubmission(f)).appended(mySubmission)
4858
4959object PendingExecution :
5060 def executeAll (executions : Seq [PendingExecution ], queue : Queue )(using Device ): Fence = pushStack : stack =>
5161 assert(executions.forall(_.isPending), " All executions must be pending" )
5262 assert(executions.nonEmpty, " At least one execution must be provided" )
5363
64+ val fence = Fence ()
65+
5466 val exec : Seq [(Set [Semaphore ], Set [(VkCommandBuffer , Semaphore )])] =
55- val gathered = executions.flatMap(_.gatherForSubmission)
67+ val gathered = executions.flatMap(_.gatherForSubmission(fence) )
5668 val ordering = gathered.zipWithIndex.map(x => (x._1._1._1, x._2)).toMap
5769 gathered.toSet.groupMap(_._2)(_._1).toSeq.sortBy(x => x._2.map(_._1).map(ordering).min)
5870
@@ -95,9 +107,7 @@ object PendingExecution:
95107
96108 submitInfos.flip()
97109
98- val fence = Fence ()
99110 check(vkQueueSubmit2(queue.get, submitInfos, fence.get), " Failed to submit command buffer to queue" )
100- executions.foreach(_.setFence(fence))
101111 fence
102112
103113 def cleanupAll (executions : Seq [PendingExecution ]): Unit =
0 commit comments