Skip to content

Commit 5e21a9f

Browse files
simplify the base class
1 parent 6df6f1c commit 5e21a9f

File tree

1 file changed

+35
-64
lines changed

1 file changed

+35
-64
lines changed

include/nbl/video/utilities/ISimpleManagedSurface.h

Lines changed: 35 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -50,15 +50,16 @@ class NBL_API2 ISimpleManagedSurface : public core::IReferenceCounted
5050
// A small utility for the boilerplate
5151
inline uint8_t pickQueueFamily(ILogicalDevice* device) const
5252
{
53+
auto physDev = device->getPhysicalDevice();
5354
uint8_t qFam = 0u;
5455
for (; qFam<ILogicalDevice::MaxQueueFamilies; qFam++)
55-
if (device->getQueueCount(qFam) && m_surface->isSupportedForPhysicalDevice(device->getPhysicalDevice(),qFam))
56+
if (device->getQueueCount(qFam) && m_surface->isSupportedForPhysicalDevice(physDev,qFam) && queueFamilyOk(physDev->getQueueFamilyProperties()[qFam]))
5657
break;
5758
return qFam;
5859
}
5960

6061
// Just pick the first queue within the first compatible family
61-
inline CThreadSafeQueueAdapter* pickQueue(ILogicalDevice* device) const
62+
virtual inline CThreadSafeQueueAdapter* pickQueue(ILogicalDevice* device) const
6263
{
6364
return device->getThreadSafeQueue(pickQueueFamily(device),0);
6465
}
@@ -70,18 +71,7 @@ class NBL_API2 ISimpleManagedSurface : public core::IReferenceCounted
7071
friend class ISimpleManagedSurface;
7172

7273
public:
73-
// If window gets minimized on some platforms or more rarely if it gets resized weirdly, the render area becomes 0 so its impossible to recreate a swapchain.
74-
// So we need to defer the swapchain re-creation until we can resize to a valid extent.
75-
enum class STATUS : int8_t
76-
{
77-
IRRECOVERABLE = -1,
78-
USABLE,
79-
NOT_READY = 1
80-
};
81-
// If `getStatus()==STATUS::IRRECOVERABLE` the Managed Surface Object is useless and can't be recovered into a functioning state.
82-
inline STATUS getStatus() const {return status;}
83-
84-
// If status is `NOT_READY` this might either return nullptr or the old stale swapchain that should be retired
74+
// If `init` not called yet this might return nullptr, or the old stale swapchain that should be retired
8575
inline ISwapchain* getSwapchain() const {return swapchain.get();}
8676

8777
//
@@ -95,25 +85,13 @@ class NBL_API2 ISimpleManagedSurface : public core::IReferenceCounted
9585
protected:
9686
virtual ~ISwapchainResources()
9787
{
98-
// just to avoid deadlocks due to circular refcounting
88+
// just to get rid of circular refs
9989
becomeIrrecoverable();
10090
}
10191

102-
// just drop the per-swapchain resources, e.g. Framebuffers with each of the swapchain images, or even pre-recorded commandbuffers
103-
inline void invalidate()
104-
{
105-
if (status==STATUS::NOT_READY)
106-
return;
107-
invalidate_impl();
108-
std::fill(images.begin(),images.end(),nullptr);
109-
status = STATUS::NOT_READY;
110-
}
111-
// mark the surface & swapchain as hopeless and ready for deletion due to errors
92+
//
11293
inline void becomeIrrecoverable()
11394
{
114-
if (status==STATUS::IRRECOVERABLE)
115-
return;
116-
11795
// Want to nullify things in an order that leads to fastest drops (if possible) and shallowest callstacks when refcounting
11896
invalidate();
11997

@@ -124,8 +102,15 @@ class NBL_API2 ISimpleManagedSurface : public core::IReferenceCounted
124102
if (swapchain)
125103
while (swapchain->acquiredImagesAwaitingPresent()) {}
126104
swapchain = nullptr;
105+
}
127106

128-
status = STATUS::IRRECOVERABLE;
107+
// just drop the per-swapchain resources, e.g. Framebuffers with each of the swapchain images, or even pre-recorded commandbuffers
108+
inline void invalidate()
109+
{
110+
if (!images.front())
111+
return;
112+
invalidate_impl();
113+
std::fill(images.begin(),images.end(),nullptr);
129114
}
130115

131116
// here you drop your own resources of the base class
@@ -152,19 +137,15 @@ class NBL_API2 ISimpleManagedSurface : public core::IReferenceCounted
152137
// extra things you might need
153138
virtual bool onCreateSwapchain_impl() = 0;
154139

155-
// As per the above, the swapchain might not be possible to create or recreate right away, so this might be
156-
// either nullptr before the first successful acquire or the old to-be-retired swapchain.
140+
// We start with a `nullptr` swapchain because some implementations might defer its creation
157141
core::smart_refctd_ptr<ISwapchain> swapchain = {};
158142
// Useful for everyone
159143
std::array<core::smart_refctd_ptr<IGPUImage>,ISwapchain::MaxImages> images = {};
160-
// We start in not-ready, instead of irrecoverable, because we haven't tried to create a swapchain yet
161-
STATUS status = STATUS::NOT_READY;
162144
};
163145

164146
// We need to defer the swapchain creation till the Physical Device is chosen and Queues are created together with the Logical Device
165147
inline bool init(CThreadSafeQueueAdapter* queue, const ISwapchain::SSharedCreationParams& sharedParams={})
166148
{
167-
getSwapchainResources().becomeIrrecoverable();
168149
if (!queue)
169150
return false;
170151

@@ -194,30 +175,23 @@ class NBL_API2 ISimpleManagedSurface : public core::IReferenceCounted
194175
protected: // some of the methods need to stay protected in this base class because they need to be performed under a Mutex for smooth resize variants
195176
inline ISimpleManagedSurface(core::smart_refctd_ptr<ISurface>&& _surface, ICallback* _cb) : m_surface(std::move(_surface)), m_cb(_cb) {}
196177
virtual inline ~ISimpleManagedSurface() = default;
178+
179+
virtual inline bool checkQueueFamilyProps(const IPhysicalDevice::SQueueFamilyProperties& props) const {return true;}
197180

198181
// RETURNS: `ISwapchain::MaxImages` on failure, otherwise its the acquired image's index.
199182
inline uint8_t acquireNextImage()
200183
{
184+
auto swapchainResources = getSwapchainResources();
185+
if (!swapchainResources)
186+
return ISwapchain::MaxImages;
187+
201188
// Only check upon an acquire, previously acquired images MUST be presented
202189
// Window/Surface got closed, but won't actually disappear UNTIL the swapchain gets dropped,
203190
// which is outside of our control here as there is a nice chain of lifetimes of:
204191
// `ExternalCmdBuf -via usage of-> Swapchain Image -memory provider-> Swapchain -created from-> Window/Surface`
205192
// Only when the last user of the swapchain image drops it, will the window die.
206-
if (m_cb->isWindowOpen())
193+
if (m_cb->isWindowOpen() && swapchainResources->swapchain)
207194
{
208-
using status_t = ISwapchainResources::STATUS;
209-
switch (getSwapchainResources().getStatus())
210-
{
211-
case status_t::NOT_READY:
212-
if (handleNotReady())
213-
break;
214-
[[fallthrough]];
215-
case status_t::IRRECOVERABLE:
216-
return ISwapchain::MaxImages;
217-
default:
218-
break;
219-
}
220-
221195
const IQueue::SSubmitInfo::SSemaphoreInfo signalInfos[1] = {
222196
{
223197
.semaphore=m_acquireSemaphore.get(),
@@ -227,7 +201,7 @@ class NBL_API2 ISimpleManagedSurface : public core::IReferenceCounted
227201

228202
uint32_t imageIndex;
229203
// We don't support resizing (swapchain recreation) in this example, so a failure to acquire is a failure to keep running
230-
switch (getSwapchainResources().swapchain->acquireNextImage({.queue=m_queue,.signalSemaphores=signalInfos},&imageIndex))
204+
switch (swapchainResources->swapchain->acquireNextImage({.queue=m_queue,.signalSemaphores=signalInfos},&imageIndex))
231205
{
232206
case ISwapchain::ACQUIRE_IMAGE_RESULT::SUBOPTIMAL: [[fallthrough]];
233207
case ISwapchain::ACQUIRE_IMAGE_RESULT::SUCCESS:
@@ -239,7 +213,7 @@ class NBL_API2 ISimpleManagedSurface : public core::IReferenceCounted
239213
assert(false); // shouldn't happen though cause we use uint64_t::max() as the timeout
240214
break;
241215
case ISwapchain::ACQUIRE_IMAGE_RESULT::OUT_OF_DATE:
242-
getSwapchainResources().invalidate();
216+
swapchainResources->invalidate();
243217
// try again, will re-create swapchain
244218
{
245219
const auto retval = handleOutOfDate();
@@ -250,28 +224,32 @@ class NBL_API2 ISimpleManagedSurface : public core::IReferenceCounted
250224
break;
251225
}
252226
}
253-
getSwapchainResources().becomeIrrecoverable();
227+
swapchainResources->becomeIrrecoverable();
254228
return ISwapchain::MaxImages;
255229
}
230+
231+
// nice little callback
232+
virtual uint8_t handleOutOfDate() = 0;
256233

257234
// Frame Resources are not optional, shouldn't be null!
258235
inline bool present(const uint8_t imageIndex, const std::span<const IQueue::SSubmitInfo::SSemaphoreInfo> waitSemaphores, core::IReferenceCounted* frameResources)
259236
{
260-
if (getSwapchainResources().getStatus()!=ISwapchainResources::STATUS::USABLE || !frameResources)
237+
auto swapchainResources = getSwapchainResources();
238+
if (!swapchainResources || !swapchainResources->swapchain || !frameResources)
261239
return false;
262240

263241
const ISwapchain::SPresentInfo info = {
264242
.queue = m_queue,
265243
.imgIndex = imageIndex,
266244
.waitSemaphores = waitSemaphores
267245
};
268-
switch (getSwapchainResources().getSwapchain()->present(info,core::smart_refctd_ptr<core::IReferenceCounted>(frameResources)))
246+
switch (swapchainResources->swapchain->present(info,core::smart_refctd_ptr<core::IReferenceCounted>(frameResources)))
269247
{
270248
case ISwapchain::PRESENT_RESULT::SUBOPTIMAL: [[fallthrough]];
271249
case ISwapchain::PRESENT_RESULT::SUCCESS:
272250
return true;
273251
case ISwapchain::PRESENT_RESULT::OUT_OF_DATE:
274-
getSwapchainResources().invalidate();
252+
swapchainResources->invalidate();
275253
break;
276254
default:
277255
// because we won't hold onto the `frameResources` we need to block for `waitSemaphores`
@@ -282,25 +260,18 @@ class NBL_API2 ISimpleManagedSurface : public core::IReferenceCounted
282260
*(outWait++) = {.semaphore=wait.semaphore,.value=wait.value};
283261
const_cast<ILogicalDevice*>(m_queue->getOriginDevice())->blockForSemaphores(waitInfos);
284262
}
285-
getSwapchainResources().becomeIrrecoverable();
263+
swapchainResources->becomeIrrecoverable();
286264
break;
287265
}
288266
return false;
289267
}
290268

291-
using image_barrier_t = IGPUCommandBuffer::SImageMemoryBarrier<IGPUCommandBuffer::SOwnershipTransferBarrier>;
292-
// Utility function for more complex Managed Surfaces, it does not increase the `m_acquireCount` but does acquire and present immediately
293-
bool immediateBlit(const image_barrier_t& contents, const IQueue::SSubmitInfo::SSemaphoreInfo& waitBeforeBlit, CThreadSafeQueueAdapter* blitAndPresentQueue);
294-
295-
virtual ISwapchainResources& getSwapchainResources() = 0;
269+
//
270+
virtual ISwapchainResources* getSwapchainResources() = 0;
296271

297272
// Generally used to check that per-swapchain resources can be created (including the swapchain itself)
298273
virtual bool init_impl(CThreadSafeQueueAdapter* queue, const ISwapchain::SSharedCreationParams& sharedParams) = 0;
299274

300-
// Handlers for acquisition exceptions, by default we can't do anything about them
301-
virtual bool handleNotReady() {return false;}
302-
virtual uint8_t handleOutOfDate() {return ISwapchain::MaxImages;}
303-
304275
//
305276
ICallback* const m_cb = nullptr;
306277

0 commit comments

Comments
 (0)