@@ -14,6 +14,63 @@ namespace nbl::video
1414// ! MAKE SURE to do a submit to `queue` by yourself with the result of `popSubmit(...)` implicitly converted to `std::span<const IQueue::SSubmitInfo>` !
1515struct SIntendedSubmitInfo final : core::Uncopyable
1616{
17+ // All commandbuffers must be compatible with the queue we're about to submit to
18+ bool cmdbufNotSubmittableToQueue (const IGPUCommandBuffer* cmdbuf) const
19+ {
20+ return !cmdbuf || cmdbuf->getPool ()->getQueueFamilyIndex ()!=queue->getFamilyIndex ();
21+ }
22+
23+ // Returns the scratch to use if valid, nullptr otherwise
24+ template <bool AllChecks>
25+ inline const IQueue::SSubmitInfo::SCommandBufferInfo* valid_impl () const
26+ {
27+ if (!queue || scratchCommandBuffers.empty () || !scratchSemaphore.semaphore )
28+ return nullptr ;
29+ // the found scratch
30+ const IQueue::SSubmitInfo::SCommandBufferInfo* scratch = nullptr ;
31+ // skip expensive stuff
32+ std::conditional_t <AllChecks,core::unordered_set<const IGPUCommandBuffer*>,const void *> uniqueCmdBufs;
33+ if constexpr (AllChecks)
34+ {
35+ // All commandbuffers before the scratch must be executable (ready to be submitted)
36+ for (const auto & info : prevCommandBuffers)
37+ if (cmdbufNotSubmittableToQueue (info.cmdbuf ) || info.cmdbuf ->getState ()!=IGPUCommandBuffer::STATE::EXECUTABLE)
38+ return nullptr ;
39+ //
40+ uniqueCmdBufs.reserve (scratchCommandBuffers.size ());
41+ }
42+ for (auto & info : scratchCommandBuffers)
43+ {
44+ if constexpr (AllChecks)
45+ {
46+ // Must be resettable so we can end, submit, wait, reset and continue recording commands into it as-if nothing happened
47+ if (cmdbufNotSubmittableToQueue (info.cmdbuf ) || !info.cmdbuf ->isResettable ())
48+ return nullptr ;
49+ uniqueCmdBufs.insert (info.cmdbuf );
50+ }
51+ // not our scratch
52+ if (info.cmdbuf ->getState ()!=IGPUCommandBuffer::STATE::RECORDING)
53+ continue ;
54+ // there can only be one scratch!
55+ if (scratch)
56+ return nullptr ;
57+ scratch = &info;
58+ }
59+ // a commandbuffer repeats itself
60+ if constexpr (AllChecks)
61+ if (uniqueCmdBufs.size ()!=scratchCommandBuffers.size ())
62+ return nullptr ;
63+ // there is no scratch cmdbuf at all!
64+ if (!scratch)
65+ return nullptr ;
66+ // It makes no sense to reuse the same commands for a second submission.
67+ // Moreover its dangerous because the utilities record their own internal commands which might use subresources for which
68+ // frees have already been latched on the scratch semaphore you must signal anyway.
69+ if (!scratch->cmdbuf ->getRecordingFlags ().hasFlags (IGPUCommandBuffer::USAGE::ONE_TIME_SUBMIT_BIT))
70+ return nullptr ;
71+ return scratch;
72+ }
73+
1774 public:
1875 // This parameter is required but may be unused if there is no need (no overflow) to do submit
1976 IQueue* queue = nullptr ;
@@ -48,68 +105,11 @@ struct SIntendedSubmitInfo final : core::Uncopyable
48105 //
49106 inline ISemaphore::SWaitInfo getFutureScratchSemaphore () const {return {scratchSemaphore.semaphore ,scratchSemaphore.value +1 };}
50107
51- // Returns the scratch to use if valid, nullptr otherwise
52- inline const IQueue::SSubmitInfo::SCommandBufferInfo* getCommandBufferForRecording () const
53- {
54- if (!queue || scratchCommandBuffers.empty () || !scratchSemaphore.semaphore )
55- return nullptr ;
56- // All commandbuffers must be compatible with the queue we're about to submit to
57- auto cmdbufNotSubmittableToQueue = [this ](const IGPUCommandBuffer* cmdbuf)->bool
58- {
59- return !cmdbuf || cmdbuf->getPool ()->getQueueFamilyIndex ()!=queue->getFamilyIndex ();
60- };
61- // All commandbuffers before the scratch must be executable (ready to be submitted)
62- for (const auto & info : prevCommandBuffers)
63- if (cmdbufNotSubmittableToQueue (info.cmdbuf ) || info.cmdbuf ->getState ()!=IGPUCommandBuffer::STATE::EXECUTABLE)
64- return nullptr ;
65- // the found scratch
66- const IQueue::SSubmitInfo::SCommandBufferInfo* scratch = nullptr ;
67- core::unordered_set<const IGPUCommandBuffer*> uniqueCmdBufs;
68- uniqueCmdBufs.reserve (scratchCommandBuffers.size ());
69- for (auto & info : scratchCommandBuffers)
70- {
71- // Must be resettable so we can end, submit, wait, reset and continue recording commands into it as-if nothing happened
72- if (cmdbufNotSubmittableToQueue (info.cmdbuf ) || !info.cmdbuf ->isResettable ())
73- return nullptr ;
74- uniqueCmdBufs.insert (info.cmdbuf );
75- // not our scratch
76- if (info.cmdbuf ->getState ()!=IGPUCommandBuffer::STATE::RECORDING)
77- continue ;
78- // there can only be one scratch!
79- if (scratch)
80- return nullptr ;
81- scratch = &info;
82- }
83- // a commandbuffer repeats itself
84- if (uniqueCmdBufs.size ()!=scratchCommandBuffers.size ())
85- return nullptr ;
86- // there is no scratch cmdbuf at all!
87- if (!scratch)
88- return nullptr ;
89- // It makes no sense to reuse the same commands for a second submission.
90- // Moreover its dangerous because the utilities record their own internal commands which might use subresources for which
91- // frees have already been latched on the scratch semaphore you must signal anyway.
92- if (!scratch->cmdbuf ->getRecordingFlags ().hasFlags (IGPUCommandBuffer::USAGE::ONE_TIME_SUBMIT_BIT))
93- return nullptr ;
94- return scratch;
95- }
108+ //
109+ inline const auto * getCommandBufferForRecording () const {return valid_impl<false >();}
96110
97- // Returns the scratch to use if valid, nullptr otherwise
98- inline const IQueue::SSubmitInfo::SCommandBufferInfo* valid () const
99- {
100- if (!queue || scratchCommandBuffers.empty () || !scratchSemaphore.semaphore )
101- return nullptr ;
102- // All commandbuffers must be compatible with the queue we're about to submit to
103- auto cmdbufNotSubmittableToQueue = [this ](const IGPUCommandBuffer* cmdbuf)->bool
104- {
105- return !cmdbuf || cmdbuf->getPool ()->getQueueFamilyIndex ()!=queue->getFamilyIndex ();
106- };
107- // All commandbuffers before the scratch must be executable (ready to be submitted)
108- for (const auto & info : prevCommandBuffers)
109- if (cmdbufNotSubmittableToQueue (info.cmdbuf ) || info.cmdbuf ->getState ()!=IGPUCommandBuffer::STATE::EXECUTABLE)
110- return nullptr ;
111- return getCommandBufferForRecording ();
112- }
111+ //
112+ inline const auto * valid () const {return valid_impl<true >();}
113113
114114 // ! xxxx
115115 class CSubmitStorage final : core::Uncopyable
@@ -162,7 +162,7 @@ struct SIntendedSubmitInfo final : core::Uncopyable
162162 // - clear the `waitSemaphores` which we'll use in the future because they will already be awaited on this `queue`
163163 inline CSubmitStorage popSubmit (IGPUCommandBuffer* recordingCmdBuf, const std::span<const IQueue::SSubmitInfo::SSemaphoreInfo> signalSemaphores)
164164 {
165- assert (scratch );
165+ assert (recordingCmdBuf );
166166 CSubmitStorage retval (*this ,recordingCmdBuf,signalSemaphores);
167167
168168 // If you want to wait for the result of this popped submit, you need to wait for this new value
0 commit comments