@@ -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