Skip to content

Commit e64a4c2

Browse files
GPUUploadManagerImpl: implement ReclaimCompletedPages and AcquireFreePage
1 parent 90ac071 commit e64a4c2

2 files changed

Lines changed: 106 additions & 6 deletions

File tree

Graphics/GraphicsTools/include/GPUUploadManagerImpl.hpp

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,10 @@ class GPUUploadManagerImpl final : public ObjectBase<IGPUUploadManager>
200200
};
201201

202202
private:
203+
void ReclaimCompletedPages(IDeviceContext* pContext);
204+
bool SealAndSwapCurrentPage(IDeviceContext* pContext);
205+
bool TryEnqueuePage(Page* P);
206+
Page* AcquireFreePage(IDeviceContext* pContext);
203207
Page* CreatePage(IDeviceContext* pContext, Uint32 MinSize = 0);
204208

205209
private:
@@ -212,13 +216,13 @@ class GPUUploadManagerImpl final : public ObjectBase<IGPUUploadManager>
212216
MPSCQueue<Page*> m_PendingPages;
213217

214218
// Pages that are ready to be used for writing. They are already mapped.
215-
//std::mutex m_FreePagesMtx;
216-
//std::vector<Page*> m_FreePages;
217-
//std::vector<Page*> m_NewFreePages;
219+
std::mutex m_FreePagesMtx;
220+
std::vector<Page*> m_FreePages;
221+
std::vector<Page*> m_NewFreePages;
218222

219223
// Pages that have been submitted for execution and are being processed by the GPU.
220-
//std::vector<Page*> m_InFlightPages;
221-
//std::vector<Page*> m_TmpInFlightPages;
224+
std::vector<Page*> m_InFlightPages;
225+
std::vector<Page*> m_TmpInFlightPages;
222226

223227
RefCntAutoPtr<IFence> m_pFence;
224228
Uint64 m_NextFenceValue = 1;

Graphics/GraphicsTools/src/GPUUploadManagerImpl.cpp

Lines changed: 97 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -323,7 +323,12 @@ GPUUploadManagerImpl::~GPUUploadManagerImpl()
323323
void GPUUploadManagerImpl::RenderThreadUpdate(IDeviceContext* pContext)
324324
{
325325
DEV_CHECK_ERR(pContext == m_pContext, "The context passed to RenderThreadUpdate must be the same as the one used to create the GPUUploadManagerImpl");
326-
(void)m_NextFenceValue;
326+
327+
SealAndSwapCurrentPage(pContext);
328+
329+
ReclaimCompletedPages(pContext);
330+
331+
m_pFence->Signal(m_NextFenceValue++);
327332
}
328333

329334
void GPUUploadManagerImpl::ScheduleBufferUpdate(IBuffer* pDstBuffer,
@@ -349,6 +354,97 @@ GPUUploadManagerImpl::Page* GPUUploadManagerImpl::CreatePage(IDeviceContext* pCo
349354
return P;
350355
}
351356

357+
bool GPUUploadManagerImpl::SealAndSwapCurrentPage(IDeviceContext* pContext)
358+
{
359+
VERIFY_EXPR(pContext != nullptr);
360+
361+
// Get a fresh page (from free-list or allocate)
362+
Page* pFreshPage = AcquireFreePage(pContext);
363+
VERIFY_EXPR(pFreshPage != nullptr);
364+
365+
// Swap it in
366+
Page* pOld = m_pCurrentPage.exchange(pFreshPage, std::memory_order_acq_rel);
367+
368+
// Seal old page and enqueue if no writers; otherwise last writer will enqueue it
369+
if (pOld->TrySeal() == Page::SealStatus::Ready)
370+
{
371+
TryEnqueuePage(pOld);
372+
}
373+
374+
return true;
375+
}
376+
377+
bool GPUUploadManagerImpl::TryEnqueuePage(Page* P)
378+
{
379+
if (P->TryEnqueue())
380+
{
381+
m_PendingPages.Enqueue(P);
382+
return true;
383+
}
384+
return false;
385+
}
386+
387+
void GPUUploadManagerImpl::ReclaimCompletedPages(IDeviceContext* pContext)
388+
{
389+
VERIFY_EXPR(pContext != nullptr);
390+
391+
Uint64 CompletedFenceValue = m_pFence->GetCompletedValue();
392+
393+
m_TmpInFlightPages.clear();
394+
m_NewFreePages.clear();
395+
for (Page* P : m_InFlightPages)
396+
{
397+
if (P->GetFenceValue() <= CompletedFenceValue)
398+
{
399+
P->Reset(pContext);
400+
m_NewFreePages.push_back(P);
401+
}
402+
else
403+
{
404+
m_TmpInFlightPages.push_back(P);
405+
}
406+
}
407+
m_InFlightPages.swap(m_TmpInFlightPages);
408+
m_TmpInFlightPages.clear();
409+
410+
{
411+
std::lock_guard<std::mutex> Guard{m_FreePagesMtx};
412+
m_FreePages.insert(m_FreePages.end(), m_NewFreePages.begin(), m_NewFreePages.end());
413+
}
414+
m_NewFreePages.clear();
415+
}
416+
417+
GPUUploadManagerImpl::Page* GPUUploadManagerImpl::AcquireFreePage(IDeviceContext* pContext)
418+
{
419+
Uint32 MaxPendingUpdateSize = m_MaxPendingUpdateSize.load(std::memory_order_relaxed);
420+
421+
Page* P = nullptr;
422+
{
423+
std::lock_guard<std::mutex> Guard{m_FreePagesMtx};
424+
for (auto it = m_FreePages.begin(); it != m_FreePages.end(); ++it)
425+
{
426+
if ((*it)->GetSize() >= MaxPendingUpdateSize)
427+
{
428+
P = *it;
429+
m_FreePages.erase(it);
430+
break;
431+
}
432+
}
433+
}
434+
435+
if (P == nullptr && pContext != nullptr)
436+
{
437+
P = CreatePage(pContext, MaxPendingUpdateSize);
438+
}
439+
440+
if (P != nullptr)
441+
{
442+
// Clear only if no one increased it since we read it
443+
m_MaxPendingUpdateSize.compare_exchange_strong(MaxPendingUpdateSize, 0u, std::memory_order_relaxed);
444+
}
445+
446+
return P;
447+
}
352448

353449
void CreateGPUUploadManager(const GPUUploadManagerCreateInfo& CreateInfo,
354450
IGPUUploadManager** ppManager)

0 commit comments

Comments
 (0)