@@ -420,42 +420,56 @@ TEST(GPUUploadManagerTest, DestroyWhileBufferUpdatesAreRunning)
420420
421421 GPUTestingEnvironment::ScopedReset AutoReset;
422422
423- RefCntAutoPtr<IGPUUploadManager> pUploadManager;
424- GPUUploadManagerCreateInfo CreateInfo{pDevice, pContext, 1024 , 2048 };
425- CreateGPUUploadManager (CreateInfo, &pUploadManager);
426- ASSERT_TRUE (pUploadManager != nullptr );
427-
428- const size_t kNumThreads = 4 ;
429- std::vector<std::thread> Threads;
430- std::atomic<Uint32> NumUpdatesRunning{0 };
431- Threading::Signal AllThreadsRunningSignal;
432- for (size_t t = 0 ; t < kNumThreads ; ++t)
423+ constexpr size_t kNumIterations = 10 ;
424+ for (size_t i = 0 ; i < kNumIterations ; ++i)
433425 {
434- Threads.emplace_back (
435- [&]() {
436- if (NumUpdatesRunning.fetch_add (1 ) == kNumThreads - 1 )
437- {
438- AllThreadsRunningSignal.Trigger ();
439- }
440- pUploadManager->ScheduleBufferUpdate ({nullptr , 0 , 4096 , nullptr });
441- NumUpdatesRunning.fetch_sub (1 );
442- });
443- }
426+ RefCntAutoPtr<IGPUUploadManager> pUploadManager;
427+ // Use small page size to make the uploaded attempt to create a new page and block in ScheduleBufferUpdate
428+ GPUUploadManagerCreateInfo CreateInfo{pDevice, pContext, 1024 , 2048 };
429+ CreateGPUUploadManager (CreateInfo, &pUploadManager);
430+ ASSERT_TRUE (pUploadManager != nullptr );
431+
432+ const size_t kNumThreads = 4 ;
433+ std::vector<std::thread> Threads;
434+ std::atomic<Uint32> NumUpdatesRunning{0 };
435+ Threading::Signal AllThreadsRunningSignal;
436+ for (size_t t = 0 ; t < kNumThreads ; ++t)
437+ {
438+ Threads.emplace_back (
439+ [&]() {
440+ if (NumUpdatesRunning.fetch_add (1 ) == kNumThreads - 1 )
441+ {
442+ AllThreadsRunningSignal.Trigger ();
443+ }
444+ // Set update size to be larger than page size to make the manager create new large page and block in ScheduleBufferUpdate
445+ pUploadManager->ScheduleBufferUpdate ({nullptr , 0 , 4096 , nullptr });
446+ NumUpdatesRunning.fetch_sub (1 );
447+ });
448+ }
444449
445- AllThreadsRunningSignal.Wait ();
450+ AllThreadsRunningSignal.Wait ();
446451
447- std::this_thread::sleep_for (10ms);
448- EXPECT_EQ (NumUpdatesRunning.load (), kNumThreads ) << " All threads should be running updates because RenderThreadUpdate() was not called" ;
452+ // Wait for some time to ensure that ScheduleTextureUpdate starts.
453+ std::this_thread::sleep_for (10ms);
454+ EXPECT_EQ (NumUpdatesRunning.load (), kNumThreads ) << " All threads sh0ould be running updates because RenderThreadUpdate() was not called" ;
449455
450- LogUploadManagerStats (pUploadManager);
456+ if (i == kNumIterations - 1 )
457+ {
458+ LogUploadManagerStats (pUploadManager);
459+ }
451460
452- pUploadManager.Release ();
461+ pUploadManager.Release ();
453462
454- for (std::thread& thread : Threads)
455- {
456- thread.join ();
463+ for (std::thread& thread : Threads)
464+ {
465+ thread.join ();
466+ }
467+ EXPECT_EQ (NumUpdatesRunning.load (), 0u );
468+
469+ pContext->Flush ();
470+ pContext->FinishFrame ();
471+ pDevice->ReleaseStaleResources ();
457472 }
458- EXPECT_EQ (NumUpdatesRunning.load (), 0u );
459473}
460474
461475
@@ -1264,4 +1278,98 @@ TEST(GPUUploadManagerTest, ParallelBufferAndTextureUpdates)
12641278 VerifyTextureContents (pTexture, SubresData);
12651279}
12661280
1281+
1282+ TEST (GPUUploadManagerTest, DestroyWhileTextureUpdatesAreRunning)
1283+ {
1284+ GPUTestingEnvironment* pEnv = GPUTestingEnvironment::GetInstance ();
1285+ IRenderDevice* pDevice = pEnv->GetDevice ();
1286+ IDeviceContext* pContext = pEnv->GetDeviceContext ();
1287+
1288+ GPUTestingEnvironment::ScopedReset AutoReset;
1289+
1290+ TextureDesc TexDesc;
1291+ TexDesc.Type = RESOURCE_DIM_TEX_2D_ARRAY;
1292+ TexDesc.Usage = USAGE_DEFAULT;
1293+ TexDesc.Width = 512 ;
1294+ TexDesc.Height = 512 ;
1295+ TexDesc.ArraySize = 32 ;
1296+ TexDesc.MipLevels = 4 ;
1297+ TexDesc.BindFlags = BIND_SHADER_RESOURCE;
1298+
1299+ std::array<RefCntAutoPtr<ITexture>, 4 > pTextures;
1300+ std::array<TEXTURE_FORMAT, 4 > Formats = {TEX_FORMAT_RGBA8_UNORM, TEX_FORMAT_BC1_UNORM, TEX_FORMAT_RG16_FLOAT, TEX_FORMAT_BC3_UNORM};
1301+ for (size_t i = 0 ; i < pTextures.size (); ++i)
1302+ {
1303+ TextureDesc Desc = TexDesc;
1304+ Desc.Format = Formats[i];
1305+ std::string Name = " GPUUploadManagerTest texture " + std::to_string (i);
1306+ Desc.Name = Name.c_str ();
1307+ pDevice->CreateTexture (Desc, nullptr , &pTextures[i]);
1308+ ASSERT_NE (pTextures[i], nullptr );
1309+ }
1310+
1311+ constexpr size_t kNumIterations = 10 ;
1312+ for (size_t i = 0 ; i < kNumIterations ; ++i)
1313+ {
1314+ RefCntAutoPtr<IGPUUploadManager> pUploadManager;
1315+ // Use small page size to make the uploaded attempt to create a new page and block in ScheduleTextureUpdate
1316+ GPUUploadManagerCreateInfo CreateInfo{pDevice, pContext, 1024 , 2048 };
1317+ CreateGPUUploadManager (CreateInfo, &pUploadManager);
1318+ ASSERT_TRUE (pUploadManager != nullptr );
1319+
1320+ const size_t kNumThreads = pTextures.size ();
1321+ std::vector<std::thread> Threads;
1322+ std::atomic<Uint32> NumUpdatesRunning{0 };
1323+ Threading::Signal AllThreadsRunningSignal;
1324+ std::vector<Uint32> Data (256 * 256 * 4 );
1325+
1326+ for (size_t t = 0 ; t < kNumThreads ; ++t)
1327+ {
1328+ Threads.emplace_back (
1329+ [&](ITexture* pTexture) {
1330+ if (NumUpdatesRunning.fetch_add (1 ) == kNumThreads - 1 )
1331+ {
1332+ AllThreadsRunningSignal.Trigger ();
1333+ }
1334+
1335+ ScheduleTextureUpdateInfo UpdateInfo;
1336+ UpdateInfo.pSrcData = Data.data ();
1337+ UpdateInfo.Stride = 256 * 4 ;
1338+ UpdateInfo.pDstTexture = pTexture;
1339+ UpdateInfo.DstMipLevel = 0 ;
1340+ UpdateInfo.DstSlice = 0 ;
1341+ // Set a large box to make the manager request a new large page for update and block in ScheduleTextureUpdate.
1342+ UpdateInfo.DstBox = {0 , 256 , 0 , 256 };
1343+ pUploadManager->ScheduleTextureUpdate (UpdateInfo);
1344+
1345+ NumUpdatesRunning.fetch_sub (1 );
1346+ },
1347+ pTextures[t]);
1348+ }
1349+
1350+ AllThreadsRunningSignal.Wait ();
1351+
1352+ // Wait for some time to ensure that ScheduleTextureUpdate starts.
1353+ std::this_thread::sleep_for (10ms);
1354+ EXPECT_EQ (NumUpdatesRunning.load (), kNumThreads ) << " All threads should be running updates because RenderThreadUpdate() was not called" ;
1355+
1356+ if (i == kNumIterations - 1 )
1357+ {
1358+ LogUploadManagerStats (pUploadManager);
1359+ }
1360+
1361+ pUploadManager.Release ();
1362+
1363+ for (std::thread& thread : Threads)
1364+ {
1365+ thread.join ();
1366+ }
1367+ EXPECT_EQ (NumUpdatesRunning.load (), 0u );
1368+
1369+ pContext->Flush ();
1370+ pContext->FinishFrame ();
1371+ pDevice->ReleaseStaleResources ();
1372+ }
1373+ }
1374+
12671375} // namespace
0 commit comments