@@ -17,6 +17,63 @@ namespace nbl::video
1717// ! The "current recording commandBuffer" is returned by `getCurrentRecordingCommandBufferInfo` or updated via the pointer ref in beginNextCommandBuffer or overflowSubmit)
1818struct SIntendedSubmitInfo final : core::Uncopyable
1919{
20+ // All commandbuffers must be compatible with the queue we're about to submit to
21+ bool cmdbufNotSubmittableToQueue (const IGPUCommandBuffer* cmdbuf) const
22+ {
23+ return !cmdbuf || cmdbuf->getPool ()->getQueueFamilyIndex ()!=queue->getFamilyIndex ();
24+ }
25+
26+ // Returns the scratch to use if valid, nullptr otherwise
27+ template <bool AllChecks>
28+ inline const IQueue::SSubmitInfo::SCommandBufferInfo* valid_impl () const
29+ {
30+ if (!queue || scratchCommandBuffers.empty () || !scratchSemaphore.semaphore )
31+ return nullptr ;
32+ // the found scratch
33+ const IQueue::SSubmitInfo::SCommandBufferInfo* scratch = nullptr ;
34+ // skip expensive stuff
35+ std::conditional_t <AllChecks,core::unordered_set<const IGPUCommandBuffer*>,const void *> uniqueCmdBufs;
36+ if constexpr (AllChecks)
37+ {
38+ // All commandbuffers before the scratch must be executable (ready to be submitted)
39+ for (const auto & info : prevCommandBuffers)
40+ if (cmdbufNotSubmittableToQueue (info.cmdbuf ) || info.cmdbuf ->getState ()!=IGPUCommandBuffer::STATE::EXECUTABLE)
41+ return nullptr ;
42+ //
43+ uniqueCmdBufs.reserve (scratchCommandBuffers.size ());
44+ }
45+ for (auto & info : scratchCommandBuffers)
46+ {
47+ if constexpr (AllChecks)
48+ {
49+ // Must be resettable so we can end, submit, wait, reset and continue recording commands into it as-if nothing happened
50+ if (cmdbufNotSubmittableToQueue (info.cmdbuf ) || !info.cmdbuf ->isResettable ())
51+ return nullptr ;
52+ uniqueCmdBufs.insert (info.cmdbuf );
53+ }
54+ // not our scratch
55+ if (info.cmdbuf ->getState ()!=IGPUCommandBuffer::STATE::RECORDING)
56+ continue ;
57+ // there can only be one scratch!
58+ if (scratch)
59+ return nullptr ;
60+ scratch = &info;
61+ }
62+ // a commandbuffer repeats itself
63+ if constexpr (AllChecks)
64+ if (uniqueCmdBufs.size ()!=scratchCommandBuffers.size ())
65+ return nullptr ;
66+ // there is no scratch cmdbuf at all!
67+ if (!scratch)
68+ return nullptr ;
69+ // It makes no sense to reuse the same commands for a second submission.
70+ // Moreover its dangerous because the utilities record their own internal commands which might use subresources for which
71+ // frees have already been latched on the scratch semaphore you must signal anyway.
72+ if (!scratch->cmdbuf ->getRecordingFlags ().hasFlags (IGPUCommandBuffer::USAGE::ONE_TIME_SUBMIT_BIT))
73+ return nullptr ;
74+ return scratch;
75+ }
76+
2077 public:
2178 // This parameter is required but may be unused if there is no need (no overflow) to do submit
2279 IQueue* queue = nullptr ;
@@ -49,69 +106,11 @@ struct SIntendedSubmitInfo final : core::Uncopyable
49106 //
50107 inline ISemaphore::SWaitInfo getFutureScratchSemaphore () const {return {scratchSemaphore.semaphore ,scratchSemaphore.value +1 };}
51108
52- // Returns the command buffer to use for recording if valid, nullptr otherwise
53- inline const IQueue::SSubmitInfo::SCommandBufferInfo* getCurrentRecordingCommandBufferInfo () const
54- {
55- if (scratchCommandBuffers.empty ())
56- return nullptr ;
57-
58- // All commandbuffers must be compatible with the queue we're about to submit to
59- auto cmdbufNotSubmittableToQueue = [this ](const IGPUCommandBuffer* cmdbuf)->bool
60- {
61- return !cmdbuf || cmdbuf->getPool ()->getQueueFamilyIndex ()!=queue->getFamilyIndex ();
62- };
63-
64- // finding command buffer toRecord
65- const IQueue::SSubmitInfo::SCommandBufferInfo* toRecord = nullptr ;
66- core::unordered_set<const IGPUCommandBuffer*> uniqueCmdBufs;
67- uniqueCmdBufs.reserve (scratchCommandBuffers.size ());
68- for (auto & info : scratchCommandBuffers)
69- {
70- // Must be resettable so we can end, submit, wait, reset and continue recording commands into it as-if nothing happened
71- if (cmdbufNotSubmittableToQueue (info.cmdbuf ) || !info.cmdbuf ->isResettable ())
72- return nullptr ;
73- uniqueCmdBufs.insert (info.cmdbuf );
74- // not our toRecord
75- if (info.cmdbuf ->getState ()!=IGPUCommandBuffer::STATE::RECORDING)
76- continue ;
77- // there can only be one toRecord!
78- if (toRecord)
79- return nullptr ;
80- toRecord = &info;
81- }
82- // a commandbuffer repeats itself
83- if (uniqueCmdBufs.size ()!=scratchCommandBuffers.size ())
84- return nullptr ;
85- // there is no toRecord cmdbuf at all!
86- if (!toRecord)
87- return nullptr ;
88- // It makes no sense to reuse the same commands for a second submission.
89- // Moreover its dangerous because the utilities record their own internal commands which might use subresources for which
90- // frees have already been latched on the scratch semaphore you must signal anyway.
91- if (!toRecord->cmdbuf ->getRecordingFlags ().hasFlags (IGPUCommandBuffer::USAGE::ONE_TIME_SUBMIT_BIT))
92- return nullptr ;
93- return toRecord;
94- }
95-
96- // Returns the command buffer to use for recording if valid, nullptr otherwise
97- inline const IQueue::SSubmitInfo::SCommandBufferInfo* valid () const
98- {
99- if (!queue || !scratchSemaphore.semaphore )
100- return nullptr ;
101-
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-
108- // All prevCommandBuffers must be executable (ready to be submitted)
109- for (const auto & info : prevCommandBuffers)
110- if (cmdbufNotSubmittableToQueue (info.cmdbuf ) || info.cmdbuf ->getState ()!=IGPUCommandBuffer::STATE::EXECUTABLE)
111- return nullptr ;
109+ //
110+ inline const auto * getCommandBufferForRecording () const {return valid_impl<false >();}
112111
113- return getCurrentRecordingCommandBufferInfo ();
114- }
112+ //
113+ inline const auto * valid () const { return valid_impl< true >(); }
115114
116115 // ! xxxx
117116 class CSubmitStorage final : core::Uncopyable
@@ -164,7 +163,7 @@ struct SIntendedSubmitInfo final : core::Uncopyable
164163 // - clear the `waitSemaphores` which we'll use in the future because they will already be awaited on this `queue`
165164 inline CSubmitStorage popSubmit (IGPUCommandBuffer* recordingCmdBuf, const std::span<const IQueue::SSubmitInfo::SSemaphoreInfo> signalSemaphores)
166165 {
167- assert (scratch );
166+ assert (recordingCmdBuf );
168167 CSubmitStorage retval (*this ,recordingCmdBuf,signalSemaphores);
169168
170169 // If you want to wait for the result of this popped submit, you need to wait for this new value
0 commit comments