@@ -4,29 +4,43 @@ using namespace nbl;
44using namespace video ;
55
66
7- bool ISimpleManagedSurface::immediateBlit (const image_barrier_t & contents, IQueue* blitQueue )
7+ bool ISimpleManagedSurface::immediateBlit (const image_barrier_t & contents, const IQueue::SSubmitInfo::SSemaphoreInfo& waitBeforeBlit, CThreadSafeQueueAdapter* blitAndPresentQueue )
88{
9- if (!contents.image || !m_queue)
9+ auto & swapchainResources = getSwapchainResources ();
10+ if (!contents.image || swapchainResources.getStatus ()!=ISwapchainResources::STATUS::USABLE)
1011 return false ;
1112
12- auto device = const_cast <ILogicalDevice*>(m_queue->getOriginDevice ());
13- const auto qFamProps = device->getPhysicalDevice ()->getQueueFamilyProperties ();
14- if (!blitQueue)
13+ auto * swapchain = swapchainResources.getSwapchain ();
14+ assert (swapchain); // because status is usable
15+ auto device = const_cast <ILogicalDevice*>(swapchain->getOriginDevice ());
16+
17+ // check queue provided
1518 {
16- // default to using the presentation queue if it can blit
17- if (qFamProps[m_queue->getFamilyIndex ()].queueFlags .hasFlags (IQueue::FAMILY_FLAGS::GRAPHICS_BIT))
18- blitQueue = m_queue;
19- else // just pick first compatible
20- for (uint8_t qFam=0 ; qFam<ILogicalDevice::MaxQueueFamilies; qFam++)
21- if (device->getQueueCount (qFam) && qFamProps[qFam].queueFlags .hasFlags (IQueue::FAMILY_FLAGS::GRAPHICS_BIT))
19+ const auto qFamProps = device->getPhysicalDevice ()->getQueueFamilyProperties ();
20+ auto compatibleQueue = [&](const uint8_t qFam)->bool
2221 {
23- blitQueue = device->getThreadSafeQueue (qFam,0 );
24- break ;
22+ return qFamProps[qFam].queueFlags .hasFlags (IQueue::FAMILY_FLAGS::GRAPHICS_BIT) && m_surface->isSupportedForPhysicalDevice (device->getPhysicalDevice (),qFam);
23+ };
24+ // pick if default wanted
25+ if (!blitAndPresentQueue)
26+ {
27+ for (uint8_t qFam=0 ; qFam<ILogicalDevice::MaxQueueFamilies; qFam++)
28+ {
29+ const auto qCount = device->getQueueCount (qFam);
30+ if (qCount && qFamProps[qFam].queueFlags .hasFlags (IQueue::FAMILY_FLAGS::GRAPHICS_BIT))
31+ {
32+ // pick a different queue than we'd pick for a regular present
33+ blitAndPresentQueue = device->getThreadSafeQueue (qFam,0 );
34+ if (blitAndPresentQueue==m_queue)
35+ blitAndPresentQueue = device->getThreadSafeQueue (qFam,qCount-1 );
36+ break ;
37+ }
38+ }
2539 }
26- }
2740
28- if (!blitQueue || qFamProps[blitQueue->getFamilyIndex ()].queueFlags .hasFlags (IQueue::FAMILY_FLAGS::GRAPHICS_BIT))
29- return false ;
41+ if (!blitAndPresentQueue || compatibleQueue (blitAndPresentQueue->getFamilyIndex ()))
42+ return false ;
43+ }
3044
3145 // create a different semaphore so we don't increase the acquire counter in `this`
3246 auto semaphore = device->createSemaphore (0 );
@@ -36,26 +50,42 @@ bool ISimpleManagedSurface::immediateBlit(const image_barrier_t& contents, IQueu
3650 // transient commandbuffer and pool to perform the blit
3751 core::smart_refctd_ptr<IGPUCommandBuffer> cmdbuf;
3852 {
39- auto pool = device->createCommandPool (blitQueue ->getFamilyIndex (),IGPUCommandPool::CREATE_FLAGS::TRANSIENT_BIT);
53+ auto pool = device->createCommandPool (blitAndPresentQueue ->getFamilyIndex (),IGPUCommandPool::CREATE_FLAGS::TRANSIENT_BIT);
4054 if (!pool || !pool->createCommandBuffers (IGPUCommandPool::BUFFER_LEVEL::PRIMARY,{&cmdbuf,1 }) || !cmdbuf)
4155 return false ;
56+
57+ if (!cmdbuf->begin (IGPUCommandBuffer::USAGE::ONE_TIME_SUBMIT_BIT))
58+ return false ;
4259 }
4360
44- const IQueue::SSubmitInfo::SSemaphoreInfo acquired[1 ] = {
45- {
46- .semaphore =semaphore.get (),
47- .value =1
48- }
61+ const IQueue::SSubmitInfo::SSemaphoreInfo acquired = {
62+ .semaphore =semaphore.get (),
63+ .value =1
4964 };
5065 // acquire
51- ;
52-
53- // now record the blit commands
54- auto acquiredImage = getSwapchainResources ().getImage (0xffu );
66+ uint32_t imageIndex;
67+ switch (swapchain->acquireNextImage ({.queue =blitAndPresentQueue,.signalSemaphores ={&acquired,1 }},&imageIndex))
5568 {
56- if (!cmdbuf->begin (IGPUCommandBuffer::USAGE::ONE_TIME_SUBMIT_BIT))
69+ case ISwapchain::ACQUIRE_IMAGE_RESULT::SUBOPTIMAL: [[fallthrough]];
70+ case ISwapchain::ACQUIRE_IMAGE_RESULT::SUCCESS:
71+ break ;
72+ case ISwapchain::ACQUIRE_IMAGE_RESULT::TIMEOUT: [[fallthrough]];
73+ case ISwapchain::ACQUIRE_IMAGE_RESULT::NOT_READY: // don't throw our swapchain away just because of a timeout XD
74+ assert (false ); // shouldn't happen though cause we use uint64_t::max() as the timeout
75+ return false ;
76+ case ISwapchain::ACQUIRE_IMAGE_RESULT::OUT_OF_DATE:
77+ swapchainResources.invalidate ();
78+ return false ;
79+ default :
80+ swapchainResources.becomeIrrecoverable ();
5781 return false ;
82+ }
83+ // once image is acquired, WE HAVE TO present it
84+ bool retval = true ;
5885
86+ // now record the blit commands
87+ auto acquiredImage = swapchainResources.getImage (imageIndex);
88+ {
5989 const auto blitSrcLayout = IGPUImage::LAYOUT::TRANSFER_SRC_OPTIMAL;
6090 const auto blitDstLayout = IGPUImage::LAYOUT::TRANSFER_DST_OPTIMAL;
6191 IGPUCommandBuffer::SPipelineBarrierDependencyInfo depInfo = {};
@@ -100,8 +130,7 @@ bool ISimpleManagedSurface::immediateBlit(const image_barrier_t& contents, IQueu
100130 }
101131 };
102132 depInfo.imgBarriers = preBarriers;
103- if (!cmdbuf->pipelineBarrier (asset::EDF_NONE,depInfo))
104- return false ;
133+ retval &= cmdbuf->pipelineBarrier (asset::EDF_NONE,depInfo);
105134
106135 // TODO: Implement scaling modes other than plain STRETCH, and allow for using subrectangles of the initial contents
107136 {
@@ -117,8 +146,7 @@ bool ISimpleManagedSurface::immediateBlit(const image_barrier_t& contents, IQueu
117146 .dstBaseLayer = 0 ,
118147 .srcMipLevel = 0 // TODO
119148 }};
120- if (!cmdbuf->blitImage (contents.image ,blitSrcLayout,acquiredImage,blitDstLayout,regions,IGPUSampler::ETF_LINEAR))
121- return false ;
149+ retval &= cmdbuf->blitImage (contents.image ,blitSrcLayout,acquiredImage,blitDstLayout,regions,IGPUSampler::ETF_LINEAR);
122150 }
123151
124152 // barrier after
@@ -148,14 +176,54 @@ bool ISimpleManagedSurface::immediateBlit(const image_barrier_t& contents, IQueu
148176 }
149177 };
150178 depInfo.imgBarriers = postBarriers;
151- if (!cmdbuf->pipelineBarrier (asset::EDF_NONE,depInfo))
152- return false ;
179+ retval &= cmdbuf->pipelineBarrier (asset::EDF_NONE,depInfo);
180+
181+ retval &= cmdbuf->end ();
153182 }
154183
184+ const IQueue::SSubmitInfo::SSemaphoreInfo blitted[1 ] = {
185+ {
186+ .semaphore = semaphore.get (),
187+ .value = 2 ,
188+ .stageMask = asset::PIPELINE_STAGE_FLAGS::BLIT_BIT
189+ }
190+ };
155191 // submit
192+ {
193+ const IQueue::SSubmitInfo::SSemaphoreInfo wait[2 ] = {acquired,waitBeforeBlit};
194+ const IQueue::SSubmitInfo::SCommandBufferInfo cmdbufs[1 ] = {{.cmdbuf =cmdbuf.get ()}};
195+ IQueue::SSubmitInfo infos[1 ] = {
196+ {
197+ .waitSemaphores = wait,
198+ .commandBuffers = cmdbufs,
199+ .signalSemaphores = blitted
200+ }
201+ };
202+ retval &= blitAndPresentQueue->submit (infos)==IQueue::RESULT::SUCCESS;
203+ }
156204
157- // present
158- ;
159-
160- return true ;
205+ // present
206+ switch (swapchainResources.swapchain ->present ({.queue =blitAndPresentQueue,.imgIndex =imageIndex,.waitSemaphores =blitted},std::move (cmdbuf)))
207+ {
208+ case ISwapchain::PRESENT_RESULT::SUBOPTIMAL: [[fallthrough]];
209+ case ISwapchain::PRESENT_RESULT::SUCCESS:
210+ // all resources can be dropped, the swapchain will hold onto them
211+ return retval;
212+ case ISwapchain::PRESENT_RESULT::OUT_OF_DATE:
213+ swapchainResources.invalidate ();
214+ break ;
215+ default :
216+ swapchainResources.becomeIrrecoverable ();
217+ break ;
218+ }
219+ // swapchain won't hold onto anything, so just block till resources not used anymore
220+ if (retval) // only if queue has submitted you have anything to wait on
221+ {
222+ ISemaphore::SWaitInfo infos[1 ] = {{
223+ .semaphore = blitted[0 ].semaphore ,
224+ .value = blitted[0 ].value
225+ }};
226+ device->blockForSemaphores (infos);
227+ }
228+ return false ;
161229}
0 commit comments