Skip to content

Commit 0607f76

Browse files
GPUUploadManager: prevent render-thread deadlock at max page count without allowing worker-thread over-allocation
1 parent 3ac2245 commit 0607f76

File tree

3 files changed

+21
-10
lines changed

3 files changed

+21
-10
lines changed

Graphics/GraphicsTools/include/GPUUploadManagerImpl.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -337,8 +337,8 @@ class GPUUploadManagerImpl final : public ObjectBase<IGPUUploadManager>
337337
Uint32 InitialPageCount,
338338
TEXTURE_FORMAT Format = TEX_FORMAT_UNKNOWN) noexcept;
339339

340-
Page* CreatePage(IDeviceContext* pContext, Uint32 RequiredSize = 0);
341-
Page* AcquireFreePage(IDeviceContext* pContext, Uint32 RequiredSize = 0);
340+
Page* CreatePage(IDeviceContext* pContext, Uint32 RequiredSize = 0, bool AllowOverLimit = false);
341+
Page* AcquireFreePage(IDeviceContext* pContext, Uint32 RequiredSize = 0, bool AllowOverLimit = false);
342342
bool SealAndSwapCurrentPage(IDeviceContext* pContext);
343343
bool TryRotatePage(IDeviceContext* pContext, Page* ExpectedCurrent, Uint32 RequiredSize);
344344
bool TryEnqueuePage(Page* P);

Graphics/GraphicsTools/src/GPUUploadManagerImpl.cpp

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1145,11 +1145,9 @@ void GPUUploadManagerImpl::ScheduleTextureUpdate(const ScheduleTextureUpdateInfo
11451145
});
11461146
}
11471147

1148-
GPUUploadManagerImpl::Page* GPUUploadManagerImpl::UploadStream::CreatePage(IDeviceContext* pContext, Uint32 RequiredSize)
1148+
GPUUploadManagerImpl::Page* GPUUploadManagerImpl::UploadStream::CreatePage(IDeviceContext* pContext, Uint32 RequiredSize, bool AllowOverLimit)
11491149
{
1150-
// Always create a new page from the render thread (when pContext is not null) to avoid deadlock in
1151-
// UploadStream::ScheduleUpdate.
1152-
if (pContext == nullptr)
1150+
if (!AllowOverLimit)
11531151
{
11541152
const Uint32 MaxExistingPageSize = m_PageSizeToCount.empty() ? 0 : m_PageSizeToCount.rbegin()->first;
11551153
if (m_MaxPageCount != 0 && m_Pages.size() >= m_MaxPageCount && RequiredSize <= MaxExistingPageSize)
@@ -1201,8 +1199,11 @@ bool GPUUploadManagerImpl::UploadStream::SealAndSwapCurrentPage(IDeviceContext*
12011199

12021200
bool GPUUploadManagerImpl::UploadStream::TryRotatePage(IDeviceContext* pContext, Page* ExpectedCurrent, Uint32 RequiredSize)
12031201
{
1204-
// Grab a free page (workers can't create, so pContext=null)
1205-
Page* Fresh = AcquireFreePage(pContext, RequiredSize);
1202+
// Allow going over the max page count when rotating the page from the render thread to
1203+
// prevent deadlock in ScheduleUpdate.
1204+
bool AllowOverLimit = pContext != nullptr;
1205+
// Grab a free page.
1206+
Page* Fresh = AcquireFreePage(pContext, RequiredSize, AllowOverLimit);
12061207
if (!Fresh)
12071208
return false;
12081209

@@ -1375,15 +1376,17 @@ void GPUUploadManagerImpl::ProcessPendingPages(IDeviceContext* pContext)
13751376
}
13761377
}
13771378

1378-
GPUUploadManagerImpl::Page* GPUUploadManagerImpl::UploadStream::AcquireFreePage(IDeviceContext* pContext, Uint32 RequiredSize)
1379+
GPUUploadManagerImpl::Page* GPUUploadManagerImpl::UploadStream::AcquireFreePage(IDeviceContext* pContext,
1380+
Uint32 RequiredSize,
1381+
bool AllowOverLimit)
13791382
{
13801383
// For texture pages, all sizes are texture dimensions.
13811384
Uint32 MaxPendingUpdateSize = std::max(m_MaxPendingUpdateSize.load(std::memory_order_acquire), RequiredSize);
13821385

13831386
Page* P = m_FreePages.Pop(MaxPendingUpdateSize);
13841387
if (P == nullptr && pContext != nullptr)
13851388
{
1386-
P = CreatePage(pContext, MaxPendingUpdateSize);
1389+
P = CreatePage(pContext, MaxPendingUpdateSize, AllowOverLimit);
13871390
}
13881391

13891392
if (P != nullptr)

Tests/DiligentCoreAPITest/src/GPUUploadManagerTest.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1293,6 +1293,8 @@ TEST(GPUUploadManagerTest, ParallelBufferAndTextureUpdates)
12931293

12941294
LOG_INFO_MESSAGE("Total render thread updates: ", NumRenderThreadUpdates);
12951295

1296+
pUploadManager->RenderThreadUpdate(pContext);
1297+
pContext->WaitForIdle();
12961298
pUploadManager->RenderThreadUpdate(pContext);
12971299

12981300
for (std::thread& thread : Threads)
@@ -1306,6 +1308,12 @@ TEST(GPUUploadManagerTest, ParallelBufferAndTextureUpdates)
13061308
VerifyTextureContents(Data.pTexture, Data.SubresData);
13071309
}
13081310

1311+
GPUUploadManagerStats Stats;
1312+
pUploadManager->GetStats(Stats);
1313+
ASSERT_EQ(Stats.NumStreams, 2u);
1314+
EXPECT_EQ(Stats.pStreamStats[0].NumPages, CreateInfo.MaxPageCount) << "Normal page count should not exceed the specified maximum";
1315+
EXPECT_EQ(Stats.pStreamStats[1].NumPages, CreateInfo.MaxLargePageCount) << "Large page count should not exceed the specified maximum";
1316+
13091317
LogUploadManagerStats(pUploadManager);
13101318
}
13111319

0 commit comments

Comments
 (0)