Skip to content

Commit 9d0dbab

Browse files
GPUUploadManager: add tests for Page::Writer::ScheduleTextureUpdates in parallel
1 parent e0cf1f7 commit 9d0dbab

File tree

1 file changed

+119
-15
lines changed

1 file changed

+119
-15
lines changed

Tests/DiligentCoreAPITest/src/GPUUploadManagerTest.cpp

Lines changed: 119 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -291,8 +291,7 @@ TEST(GPUUploadManagerTest, Writer_ScheduleBufferUpdateParallel)
291291

292292
std::vector<std::thread> threads;
293293

294-
const size_t kNumThreads = std::max(4u, std::thread::hardware_concurrency());
295-
const size_t kNumIterations = (kNumUpdates + kNumThreads - 1) / kNumThreads;
294+
const size_t kNumThreads = std::max(4u, std::thread::hardware_concurrency());
296295

297296
std::atomic<size_t> UpdatesScheduled{0};
298297
std::atomic<Uint32> DstOffset{0};
@@ -302,26 +301,27 @@ TEST(GPUUploadManagerTest, Writer_ScheduleBufferUpdateParallel)
302301
[&](size_t ThreadId) {
303302
StartSignal.Wait(true, static_cast<int>(kNumThreads));
304303

305-
for (size_t i = 0; i < kNumIterations; ++i)
304+
while (true)
306305
{
306+
Uint32 Offset = DstOffset.fetch_add(kUpdateSize);
307+
if (Offset >= kPageSize)
308+
break;
309+
307310
GPUUploadManagerImpl::Page::Writer Writer = Page.TryBeginWriting();
308311
EXPECT_TRUE(Writer) << "Writer should be valid because the page should not be sealed yet";
309312
if (!Writer)
310313
break;
311314

312-
Uint32 Offset = DstOffset.fetch_add(kUpdateSize);
313-
if (Offset < kPageSize)
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))
314321
{
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-
}
322+
UpdatesScheduled.fetch_add(1);
324323
}
324+
325325
Writer.EndWriting();
326326
}
327327
},
@@ -1022,6 +1022,7 @@ void TestWriterScheduleTextureUpdates(Uint32 Flags = TEST_TEXTURE_UPDATES_FLAGS_
10221022
ASSERT_TRUE(pTexture != nullptr);
10231023

10241024
const std::vector<std::vector<Uint8>> SubresData = GenerateTextureSubresData(TexDesc);
1025+
const std::vector<Uint8>& Mip0Data = SubresData[0];
10251026

10261027
const Uint32 ElementSize = GetTextureFormatAttribs(TexDesc.Format).GetElementSize();
10271028

@@ -1035,7 +1036,6 @@ void TestWriterScheduleTextureUpdates(Uint32 Flags = TEST_TEXTURE_UPDATES_FLAGS_
10351036
Page = std::make_unique<GPUUploadManagerImpl::Page>(nullptr, pDevice, TexDesc.Width * TexDesc.Height * ElementSize);
10361037
}
10371038

1038-
const std::vector<Uint8>& Mip0Data = SubresData[0];
10391039
Page->Reset(pContext);
10401040
Page->Unseal();
10411041

@@ -1199,6 +1199,110 @@ TEST(GPUUploadManagerTest, Writer_ScheduleTextureUpdates_WithWriteAndCopyCallbac
11991199
TestWriterScheduleTextureUpdates(TEST_TEXTURE_UPDATES_FLAGS_USE_WRITE_DATA_CALLBACK | TEST_TEXTURE_UPDATES_FLAGS_USE_COPY_CALLBACK);
12001200
}
12011201

1202+
TEST(GPUUploadManagerTest, Writer_ScheduleTextureUpdateParallel)
1203+
{
1204+
GPUTestingEnvironment* pEnv = GPUTestingEnvironment::GetInstance();
1205+
IRenderDevice* pDevice = pEnv->GetDevice();
1206+
IDeviceContext* pContext = pEnv->GetDeviceContext();
1207+
1208+
GPUTestingEnvironment::ScopedReset AutoReset;
1209+
1210+
TextureDesc TexDesc;
1211+
TexDesc.Name = "GPUUploadManagerTest texture";
1212+
TexDesc.Type = RESOURCE_DIM_TEX_2D;
1213+
TexDesc.Format = TEX_FORMAT_RGBA8_UNORM;
1214+
TexDesc.Usage = USAGE_DEFAULT;
1215+
TexDesc.Width = 2048;
1216+
TexDesc.Height = 2048;
1217+
TexDesc.MipLevels = 1;
1218+
TexDesc.BindFlags = BIND_SHADER_RESOURCE;
1219+
1220+
RefCntAutoPtr<ITexture> pTexture;
1221+
pDevice->CreateTexture(TexDesc, nullptr, &pTexture);
1222+
ASSERT_TRUE(pTexture != nullptr);
1223+
1224+
const std::vector<std::vector<Uint8>> SubresData = GenerateTextureSubresData(TexDesc);
1225+
const std::vector<Uint8>& Mip0Data = SubresData[0];
1226+
1227+
const Uint32 ElementSize = GetTextureFormatAttribs(TexDesc.Format).GetElementSize();
1228+
1229+
std::unique_ptr<GPUUploadManagerImpl::Page> Page;
1230+
if (pDevice->GetDeviceInfo().Type == RENDER_DEVICE_TYPE_D3D11)
1231+
{
1232+
Page = std::make_unique<GPUUploadManagerImpl::Page>(nullptr, pDevice, TexDesc.Width, TexDesc.Format);
1233+
}
1234+
else
1235+
{
1236+
Page = std::make_unique<GPUUploadManagerImpl::Page>(nullptr, pDevice, TexDesc.Width * TexDesc.Height * ElementSize);
1237+
}
1238+
1239+
Page->Reset(pContext);
1240+
Page->Unseal();
1241+
Threading::Signal StartSignal;
1242+
1243+
std::vector<std::thread> threads;
1244+
1245+
const Uint32 kUpdateWidth = 512;
1246+
const Uint32 kUpdateHeight = 16;
1247+
const Uint32 NumUpdates = (TexDesc.Width / kUpdateWidth) * (TexDesc.Height / kUpdateHeight);
1248+
const Uint32 NumUpdatesPerRow = TexDesc.Width / kUpdateWidth;
1249+
1250+
const size_t kNumThreads = std::max(4u, std::thread::hardware_concurrency());
1251+
1252+
std::atomic<Uint32> UpdateIndex{0};
1253+
std::atomic<size_t> UpdatesScheduled{0};
1254+
std::atomic<Uint32> DstOffset{0};
1255+
for (size_t t = 0; t < kNumThreads; ++t)
1256+
{
1257+
threads.emplace_back(
1258+
[&](size_t ThreadId) {
1259+
StartSignal.Wait(true, static_cast<int>(kNumThreads));
1260+
1261+
while (true)
1262+
{
1263+
Uint32 UpdateId = UpdateIndex.fetch_add(1);
1264+
if (UpdateId >= NumUpdates)
1265+
break;
1266+
1267+
GPUUploadManagerImpl::Page::Writer Writer = Page->TryBeginWriting();
1268+
EXPECT_TRUE(Writer) << "Writer should be valid because the page should not be sealed yet";
1269+
if (!Writer)
1270+
break;
1271+
1272+
ScheduleTextureUpdateInfo UpdateInfo;
1273+
UpdateInfo.pDstTexture = pTexture;
1274+
UpdateInfo.Stride = TexDesc.Width * ElementSize;
1275+
UpdateInfo.DstBox.MinX = (UpdateId % NumUpdatesPerRow) * kUpdateWidth;
1276+
UpdateInfo.DstBox.MinY = (UpdateId / NumUpdatesPerRow) * kUpdateHeight;
1277+
UpdateInfo.DstBox.MaxX = UpdateInfo.DstBox.MinX + kUpdateWidth;
1278+
UpdateInfo.DstBox.MaxY = UpdateInfo.DstBox.MinY + kUpdateHeight;
1279+
UpdateInfo.pSrcData = &Mip0Data[(UpdateInfo.DstBox.MinX + UpdateInfo.DstBox.MinY * TexDesc.Width) * ElementSize];
1280+
1281+
BufferToTextureCopyInfo CopyInfo = GetBufferToTextureCopyInfo(TexDesc.Format, UpdateInfo.DstBox, 1024);
1282+
if (Writer.ScheduleTextureUpdate(UpdateInfo, CopyInfo, 1024))
1283+
{
1284+
UpdatesScheduled.fetch_add(1);
1285+
}
1286+
Writer.EndWriting();
1287+
}
1288+
},
1289+
t);
1290+
}
1291+
1292+
StartSignal.Trigger(true);
1293+
1294+
for (auto& thread : threads)
1295+
thread.join();
1296+
1297+
EXPECT_EQ(Page->GetNumPendingOps(), NumUpdates);
1298+
EXPECT_EQ(UpdatesScheduled.load(), NumUpdates) << "Should be able to schedule updates until the page size is reached";
1299+
EXPECT_EQ(Page->TrySeal(), GPUUploadManagerImpl::Page::SealStatus::Ready) << "Page should be ready for sealing after all updates are scheduled";
1300+
Page->ExecutePendingOps(pContext, 1);
1301+
Page->ReleaseStagingBuffer(pContext);
1302+
1303+
VerifyTextureContents(pTexture, SubresData);
1304+
}
1305+
12021306
void TestTextureUpdates(TEXTURE_FORMAT Format, RESOURCE_DIMENSION Type, Uint32 Flags = TEST_TEXTURE_UPDATES_FLAGS_NONE)
12031307
{
12041308
GPUTestingEnvironment* pEnv = GPUTestingEnvironment::GetInstance();

0 commit comments

Comments
 (0)