Skip to content

Commit e432997

Browse files
Roll out the big gun, the MultiTimelineEventHandler
I forgot that the acquire returns on CPU before the presentation is finished, so technically I can't get rid of resources needed for the previous acquire-release cycle on the same image index when a new acquire returns on the CPU also there's nothing in the spec saying that I can't acquire/return multiple times immediately on the CPU, getting the same image index every time and just spam my submission queue with acquire-present pairs
1 parent 80dfd1c commit e432997

File tree

2 files changed

+68
-18
lines changed

2 files changed

+68
-18
lines changed

include/nbl/video/ISwapchain.h

Lines changed: 61 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -361,11 +361,10 @@ class ISwapchain : public IBackendObject
361361
case ACQUIRE_IMAGE_RESULT::SUCCESS: [[fallthrough]];
362362
case ACQUIRE_IMAGE_RESULT::SUBOPTIMAL:
363363
m_acquireCounter++;
364+
// Now hold onto the signal-on-acquire semaphores for this image index till the acquire actually takes place
364365
{
365-
auto semaphoreArray = core::make_refctd_dynamic_array<core::smart_refctd_dynamic_array<void_refctd_ptr>>(info.signalSemaphores.size());
366-
for (auto i=0ull; i<info.signalSemaphores.size(); i++)
367-
semaphoreArray->operator[](i) = void_refctd_ptr(info.signalSemaphores[i].semaphore);
368-
m_frameResources[*out_imgIx] = std::move(semaphoreArray);
366+
const auto& lastSignal = info.signalSemaphores.back();
367+
m_frameResources[*out_imgIx]->latch({.semaphore=lastSignal.semaphore,.value=lastSignal.value},DeferredFrameResourceDrop(info.signalSemaphores));
369368
}
370369
if (m_oldSwapchain && m_acquireCounter>core::max(m_oldSwapchain->getImageCount(),m_imageCount) && !m_oldSwapchain->acquiredImagesAwaitingPresent())
371370
m_oldSwapchain = nullptr;
@@ -408,19 +407,15 @@ class ISwapchain : public IBackendObject
408407
threadsafeQ->m.unlock();
409408

410409
// If not FATAL_ERROR then semaphore wait will actually occur in the future and resources should be released, either:
411-
// - on the next acquire of the same index
410+
// - on the next SIGNALLED acquire of the same index
412411
// - when dropping the swapchain entirely, but need to wait on all previous presents to finish (some manageable UB)
413412
if (retval!=PRESENT_RESULT::FATAL_ERROR)
414413
{
415-
auto frameResources = core::make_refctd_dynamic_array<core::smart_refctd_dynamic_array<void_refctd_ptr>>(info.waitSemaphores.size()+2);
416-
frameResources->operator[](0) = std::move(m_frameResources[info.imgIndex]);
417-
frameResources->operator[](1) = std::move(_frameResources);
418-
for (auto i=0ull; i<info.waitSemaphores.size(); i++)
419-
frameResources->operator[](i+2) = void_refctd_ptr(info.waitSemaphores[i].semaphore);
420-
m_frameResources[info.imgIndex] = std::move(frameResources);
414+
auto& lastWait = info.waitSemaphores.back();
415+
m_frameResources[info.imgIndex]->latch({.semaphore=lastWait.semaphore,.value=lastWait.value},DeferredFrameResourceDrop(info.waitSemaphores,std::move(_frameResources)));
421416
}
422-
else
423-
m_frameResources[info.imgIndex] = nullptr;
417+
// kill a few frame resources
418+
m_frameResources[info.imgIndex]->poll();
424419
return retval;
425420
}
426421

@@ -433,7 +428,7 @@ class ISwapchain : public IBackendObject
433428
for (uint8_t i=0; i<m_imageCount; i++)
434429
{
435430
if (unacquired(i))
436-
m_frameResources[i] = nullptr;
431+
m_frameResources[i]->abortAll();
437432
else
438433
return true;
439434
}
@@ -470,7 +465,56 @@ class ISwapchain : public IBackendObject
470465

471466
// Vulkan: const VkSwapchainKHR*
472467
virtual const void* getNativeHandle() const = 0;
473-
468+
469+
// only public because MultiTimelineEventHandlerST needs to know about it
470+
class DeferredFrameResourceDrop final
471+
{
472+
core::smart_refctd_dynamic_array<void_refctd_ptr> m_frameResources;
473+
474+
public:
475+
inline DeferredFrameResourceDrop(const std::span<const IQueue::SSubmitInfo::SSemaphoreInfo> _semaphores, void_refctd_ptr&& _frameResources=nullptr)
476+
{
477+
m_frameResources = core::make_refctd_dynamic_array<decltype(m_frameResources)>(_semaphores.size()+(_frameResources ? 1:0));
478+
for (auto i=0ull; i< _semaphores.size(); i++)
479+
m_frameResources->operator[](i) = void_refctd_ptr(_semaphores[i].semaphore);
480+
if (_frameResources)
481+
m_frameResources->back() = std::move(_frameResources);
482+
}
483+
DeferredFrameResourceDrop(const DeferredFrameResourceDrop& other) = delete;
484+
inline DeferredFrameResourceDrop(DeferredFrameResourceDrop&& other) : m_frameResources(nullptr)
485+
{
486+
this->operator=(std::move(other));
487+
}
488+
489+
DeferredFrameResourceDrop& operator=(const DeferredFrameResourceDrop& other) = delete;
490+
inline DeferredFrameResourceDrop& operator=(DeferredFrameResourceDrop&& other)
491+
{
492+
m_frameResources = std::move(other.m_frameResources);
493+
m_frameResources = nullptr;
494+
return *this;
495+
}
496+
497+
struct single_poll_t {};
498+
static inline single_poll_t single_poll;
499+
inline bool operator()(single_poll_t _single_poll)
500+
{
501+
operator()();
502+
return true;
503+
}
504+
505+
struct exhaustive_poll_t {};
506+
static inline exhaustive_poll_t exhaustive_poll;
507+
inline bool operator()(exhaustive_poll_t _exhaustive_poll)
508+
{
509+
operator()();
510+
return false;
511+
}
512+
513+
inline void operator()()
514+
{
515+
m_frameResources = nullptr;
516+
}
517+
};
474518
protected:
475519
ISwapchain(core::smart_refctd_ptr<const ILogicalDevice>&& dev, SCreationParams&& params, const uint8_t imageCount, core::smart_refctd_ptr<ISwapchain>&& oldSwapchain);
476520
virtual inline ~ISwapchain()
@@ -513,8 +557,8 @@ class ISwapchain : public IBackendObject
513557
std::array<uint8_t,ILogicalDevice::MaxQueueFamilies> m_queueFamilies;
514558
const uint8_t m_imageCount;
515559
uint64_t m_acquireCounter = 0;
516-
// resource to hold onto until a frame is done rendering (between; just before presenting, and next acquire of the same image index)
517-
std::array<void_refctd_ptr,ILogicalDevice::MaxQueueFamilies> m_frameResources = {};
560+
// Resources to hold onto until a frame is done rendering (between; just before presenting, and next acquire of the same image index)
561+
std::array<std::unique_ptr<MultiTimelineEventHandlerST<DeferredFrameResourceDrop>>,ILogicalDevice::MaxQueueFamilies> m_frameResources;
518562
};
519563

520564
}

src/nbl/video/ISwapchain.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,12 @@ ISwapchain::ISwapchain(core::smart_refctd_ptr<const ILogicalDevice>&& dev, SCrea
2626

2727
std::copy(m_params.queueFamilyIndices.begin(),m_params.queueFamilyIndices.end(),m_queueFamilies.data());
2828
m_params.queueFamilyIndices = {m_queueFamilies.data(),m_params.queueFamilyIndices.size()};
29-
}
29+
30+
for (auto i=0; i<m_imageCount; i++)
31+
{
32+
auto device = core::smart_refctd_ptr<ILogicalDevice>(const_cast<ILogicalDevice*>(getOriginDevice()));
33+
m_frameResources[i] = std::make_unique<MultiTimelineEventHandlerST<DeferredFrameResourceDrop>>(std::move(device));
34+
}
35+
}
3036

3137
}

0 commit comments

Comments
 (0)