@@ -14,6 +14,63 @@ namespace nbl::video
14
14
// ! MAKE SURE to do a submit to `queue` by yourself with the result of `popSubmit(...)` implicitly converted to `std::span<const IQueue::SSubmitInfo>` !
15
15
struct SIntendedSubmitInfo final : core::Uncopyable
16
16
{
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
+
17
74
public:
18
75
// This parameter is required but may be unused if there is no need (no overflow) to do submit
19
76
IQueue* queue = nullptr ;
@@ -48,68 +105,11 @@ struct SIntendedSubmitInfo final : core::Uncopyable
48
105
//
49
106
inline ISemaphore::SWaitInfo getFutureScratchSemaphore () const {return {scratchSemaphore.semaphore ,scratchSemaphore.value +1 };}
50
107
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 >();}
96
110
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 >();}
113
113
114
114
// ! xxxx
115
115
class CSubmitStorage final : core::Uncopyable
@@ -162,7 +162,7 @@ struct SIntendedSubmitInfo final : core::Uncopyable
162
162
// - clear the `waitSemaphores` which we'll use in the future because they will already be awaited on this `queue`
163
163
inline CSubmitStorage popSubmit (IGPUCommandBuffer* recordingCmdBuf, const std::span<const IQueue::SSubmitInfo::SSemaphoreInfo> signalSemaphores)
164
164
{
165
- assert (scratch );
165
+ assert (recordingCmdBuf );
166
166
CSubmitStorage retval (*this ,recordingCmdBuf,signalSemaphores);
167
167
168
168
// If you want to wait for the result of this popped submit, you need to wait for this new value
0 commit comments