Skip to content

Commit e0cf1f7

Browse files
GPUUploadManager: add tests for Page::Writer::ScheduleBufferUpdates in parallel
1 parent 41fb614 commit e0cf1f7

File tree

2 files changed

+95
-8
lines changed

2 files changed

+95
-8
lines changed

Tests/DiligentCoreAPITest/src/GPUUploadManagerTest.cpp

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,92 @@ TEST(GPUUploadManagerTest, Writer_ScheduleBufferUpdatesWithWriteAndCopyCallbacks
256256
TestWriterScheduleBufferUpdates(/*UseWriteCallback = */ true, /*UseCopyCallback = */ true);
257257
}
258258

259+
TEST(GPUUploadManagerTest, Writer_ScheduleBufferUpdateParallel)
260+
{
261+
GPUTestingEnvironment* pEnv = GPUTestingEnvironment::GetInstance();
262+
IRenderDevice* pDevice = pEnv->GetDevice();
263+
IDeviceContext* pContext = pEnv->GetDeviceContext();
264+
265+
GPUTestingEnvironment::ScopedReset AutoReset;
266+
267+
constexpr Uint32 kPageSize = 65536;
268+
constexpr Uint32 kUpdateSize = 32;
269+
constexpr Uint32 kNumUpdates = kPageSize / kUpdateSize;
270+
271+
std::vector<Uint8> BufferData(kPageSize);
272+
for (size_t i = 0; i < BufferData.size(); ++i)
273+
{
274+
BufferData[i] = static_cast<Uint8>(i % 256);
275+
}
276+
277+
BufferDesc Desc;
278+
Desc.Name = "GPUUploadManagerTest buffer";
279+
Desc.Size = BufferData.size();
280+
Desc.Usage = USAGE_DEFAULT;
281+
Desc.BindFlags = BIND_VERTEX_BUFFER;
282+
RefCntAutoPtr<IBuffer> pBuffer;
283+
pDevice->CreateBuffer(Desc, nullptr, &pBuffer);
284+
ASSERT_TRUE(pBuffer);
285+
286+
GPUUploadManagerImpl::Page Page{nullptr, pDevice, kPageSize};
287+
Page.Reset(pContext);
288+
Page.Unseal();
289+
290+
Threading::Signal StartSignal;
291+
292+
std::vector<std::thread> threads;
293+
294+
const size_t kNumThreads = std::max(4u, std::thread::hardware_concurrency());
295+
const size_t kNumIterations = (kNumUpdates + kNumThreads - 1) / kNumThreads;
296+
297+
std::atomic<size_t> UpdatesScheduled{0};
298+
std::atomic<Uint32> DstOffset{0};
299+
for (size_t t = 0; t < kNumThreads; ++t)
300+
{
301+
threads.emplace_back(
302+
[&](size_t ThreadId) {
303+
StartSignal.Wait(true, static_cast<int>(kNumThreads));
304+
305+
for (size_t i = 0; i < kNumIterations; ++i)
306+
{
307+
GPUUploadManagerImpl::Page::Writer Writer = Page.TryBeginWriting();
308+
EXPECT_TRUE(Writer) << "Writer should be valid because the page should not be sealed yet";
309+
if (!Writer)
310+
break;
311+
312+
Uint32 Offset = DstOffset.fetch_add(kUpdateSize);
313+
if (Offset < kPageSize)
314+
{
315+
ScheduleBufferUpdateInfo UpdateInfo;
316+
UpdateInfo.pDstBuffer = pBuffer;
317+
UpdateInfo.pSrcData = &BufferData[Offset];
318+
UpdateInfo.DstOffset = Offset;
319+
UpdateInfo.NumBytes = kUpdateSize;
320+
if (Writer.ScheduleBufferUpdate(UpdateInfo))
321+
{
322+
UpdatesScheduled.fetch_add(1);
323+
}
324+
}
325+
Writer.EndWriting();
326+
}
327+
},
328+
t);
329+
}
330+
331+
StartSignal.Trigger(true);
332+
333+
for (auto& thread : threads)
334+
thread.join();
335+
336+
EXPECT_EQ(Page.GetNumPendingOps(), kNumUpdates);
337+
EXPECT_EQ(UpdatesScheduled.load(), kNumUpdates) << "Should be able to schedule updates until the page size is reached";
338+
EXPECT_EQ(Page.TrySeal(), GPUUploadManagerImpl::Page::SealStatus::Ready) << "Page should be ready for sealing after all updates are scheduled";
339+
Page.ExecutePendingOps(pContext, 1);
340+
Page.ReleaseStagingBuffer(pContext);
341+
342+
VerifyBufferContents(pBuffer, BufferData);
343+
}
344+
259345
TEST(GPUUploadManagerTest, ScheduleBufferUpdates)
260346
{
261347
GPUTestingEnvironment* pEnv = GPUTestingEnvironment::GetInstance();

Tests/DiligentCoreTest/src/GraphicsTools/GPUUploadManagerPageTest.cpp

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -256,15 +256,16 @@ TEST(GPUUploadManagerPageTest, ScheduleBufferUpdateParallel)
256256
[&](size_t ThreadId) {
257257
StartSignal.Wait(true, static_cast<int>(kNumThreads));
258258

259-
GPUUploadManagerImpl::Page::Writer Writer = Page.TryBeginWriting();
260-
if (Writer)
259+
for (size_t i = 0; i < kNumIterations; ++i)
261260
{
262-
for (size_t i = 0; i < kNumIterations; ++i)
261+
GPUUploadManagerImpl::Page::Writer Writer = Page.TryBeginWriting();
262+
EXPECT_TRUE(Writer) << "Writer should be valid because the page should not be sealed yet";
263+
if (!Writer)
264+
break;
265+
266+
if (Writer.ScheduleBufferUpdate({nullptr, nullptr, 0, kUpdateSize, nullptr, Callback, Callback}))
263267
{
264-
if (Writer.ScheduleBufferUpdate({nullptr, nullptr, 0, kUpdateSize, nullptr, Callback, Callback}))
265-
{
266-
UpdatesScheduled.fetch_add(1);
267-
}
268+
UpdatesScheduled.fetch_add(1);
268269
}
269270
Writer.EndWriting();
270271
}
@@ -279,7 +280,7 @@ TEST(GPUUploadManagerPageTest, ScheduleBufferUpdateParallel)
279280

280281
EXPECT_EQ(Page.GetNumPendingOps(), kNumUpdates);
281282
EXPECT_EQ(UpdatesScheduled.load(), kNumUpdates) << "Should be able to schedule updates until the page size is reached";
282-
EXPECT_EQ(Page.TrySeal() == GPUUploadManagerImpl::Page::SealStatus::Ready, true) << "Page should be ready for sealing after all updates are scheduled";
283+
EXPECT_EQ(Page.TrySeal(), GPUUploadManagerImpl::Page::SealStatus::Ready) << "Page should be ready for sealing after all updates are scheduled";
283284
Page.ExecutePendingOps(nullptr, 0);
284285
EXPECT_EQ(NumUpdatesScheduled, kNumUpdates) << "All scheduled updates should have been executed";
285286
}

0 commit comments

Comments
 (0)