@@ -48,6 +48,8 @@ TEST(GPUUploadManagerTest, Creation)
4848 IRenderDevice* pDevice = pEnv->GetDevice ();
4949 IDeviceContext* pContext = pEnv->GetDeviceContext ();
5050
51+ GPUTestingEnvironment::ScopedReset AutoReset;
52+
5153 RefCntAutoPtr<IGPUUploadManager> pUploadManager;
5254 GPUUploadManagerCreateInfo CreateInfo{pDevice, pContext};
5355 CreateGPUUploadManager (CreateInfo, &pUploadManager);
@@ -60,6 +62,8 @@ void VerifyBufferContents(IBuffer* pBuffer, const std::vector<Uint8>& ExpectedDa
6062 IRenderDevice* pDevice = pEnv->GetDevice ();
6163 IDeviceContext* pContext = pEnv->GetDeviceContext ();
6264
65+ GPUTestingEnvironment::ScopedReset AutoReset;
66+
6367 BufferDesc Desc = pBuffer->GetDesc ();
6468 Desc.Name = " GPUUploadManagerTest readback buffer" ;
6569 Desc.Usage = USAGE_STAGING;
@@ -77,6 +81,7 @@ void VerifyBufferContents(IBuffer* pBuffer, const std::vector<Uint8>& ExpectedDa
7781 void * pBufferData = nullptr ;
7882 pContext->MapBuffer (pReadbackBuffer, MAP_READ, MAP_FLAG_DO_NOT_WAIT, pBufferData);
7983 ASSERT_NE (pBufferData, nullptr );
84+ pContext->UnmapBuffer (pReadbackBuffer, MAP_READ);
8085
8186 EXPECT_TRUE (std::memcmp (pBufferData, ExpectedData.data (), ExpectedData.size ()) == 0 ) << " Buffer contents do not match expected data" ;
8287}
@@ -87,6 +92,8 @@ TEST(GPUUploadManagerTest, ScheduleUpdates)
8792 IRenderDevice* pDevice = pEnv->GetDevice ();
8893 IDeviceContext* pContext = pEnv->GetDeviceContext ();
8994
95+ GPUTestingEnvironment::ScopedReset AutoReset;
96+
9097 RefCntAutoPtr<IGPUUploadManager> pUploadManager;
9198 GPUUploadManagerCreateInfo CreateInfo{pDevice, pContext, 1024 };
9299 CreateGPUUploadManager (CreateInfo, &pUploadManager);
@@ -118,4 +125,96 @@ TEST(GPUUploadManagerTest, ScheduleUpdates)
118125 VerifyBufferContents (pBuffer, BufferData);
119126}
120127
128+ TEST (GPUUploadManagerTest, ParallelUpdates)
129+ {
130+ GPUTestingEnvironment* pEnv = GPUTestingEnvironment::GetInstance ();
131+ IRenderDevice* pDevice = pEnv->GetDevice ();
132+ IDeviceContext* pContext = pEnv->GetDeviceContext ();
133+
134+ RefCntAutoPtr<IGPUUploadManager> pUploadManager;
135+ GPUUploadManagerCreateInfo CreateInfo{pDevice, pContext, 16384 };
136+ CreateGPUUploadManager (CreateInfo, &pUploadManager);
137+ ASSERT_TRUE (pUploadManager != nullptr );
138+
139+ std::vector<Uint8> BufferData (4 << 20 );
140+ for (size_t i = 0 ; i < BufferData.size (); ++i)
141+ {
142+ BufferData[i] = static_cast <Uint8>(i % 256 );
143+ }
144+
145+ BufferDesc Desc;
146+ Desc.Name = " GPUUploadManagerTest buffer" ;
147+ Desc.Size = BufferData.size ();
148+ Desc.Usage = USAGE_DEFAULT;
149+ Desc.BindFlags = BIND_VERTEX_BUFFER;
150+
151+ RefCntAutoPtr<IBuffer> pBuffer;
152+ pDevice->CreateBuffer (Desc, nullptr , &pBuffer);
153+ ASSERT_TRUE (pBuffer);
154+
155+ const size_t kNumThreads = std::max (2u , std::thread::hardware_concurrency () - 1 );
156+ LOG_INFO_MESSAGE (" Number of threads: " , kNumThreads );
157+
158+ std::atomic<Uint32> CurrOffset{0 };
159+ std::atomic<Uint32> NumUpdatesScheduled{0 };
160+ std::atomic<Uint32> NumThreadsCompleted{0 };
161+
162+ std::vector<std::thread> Threads;
163+ for (size_t t = 0 ; t < kNumThreads ; ++t)
164+ {
165+ Threads.emplace_back (
166+ [&]() {
167+ while (true )
168+ {
169+ const Uint32 UpdateSize = 64 ;
170+
171+ Uint32 Offset = CurrOffset.fetch_add (UpdateSize);
172+ if (Offset >= BufferData.size ())
173+ break ;
174+ pUploadManager->ScheduleBufferUpdate (nullptr , pBuffer, Offset, UpdateSize, &BufferData[Offset]);
175+ NumUpdatesScheduled.fetch_add (1 );
176+ }
177+ NumThreadsCompleted.fetch_add (1 );
178+ });
179+ }
180+
181+ const Uint32 NumUpdatesToRenderThreadUpdate = 256 ;
182+
183+ Uint32 LastNumUpdatesScheduled = 0 ;
184+ Uint32 NumIterationsWithoutUpdate = 0 ;
185+ Uint32 NumRenderThreadUpdates = 0 ;
186+ while (NumThreadsCompleted.load () < kNumThreads )
187+ {
188+ if (LastNumUpdatesScheduled == NumUpdatesScheduled.load ())
189+ {
190+ ++NumIterationsWithoutUpdate;
191+ }
192+ else
193+ {
194+ LastNumUpdatesScheduled = NumUpdatesScheduled.load ();
195+ NumIterationsWithoutUpdate = 0 ;
196+ }
197+
198+ if (NumUpdatesScheduled.load () >= NumUpdatesToRenderThreadUpdate || NumIterationsWithoutUpdate >= 100 )
199+ {
200+ pUploadManager->RenderThreadUpdate (pContext);
201+ NumUpdatesScheduled.fetch_sub (NumUpdatesToRenderThreadUpdate);
202+ pContext->Flush ();
203+ pContext->FinishFrame ();
204+ ++NumRenderThreadUpdates;
205+ }
206+ }
207+
208+ LOG_INFO_MESSAGE (" Total render thread updates: " , NumRenderThreadUpdates);
209+
210+ pUploadManager->RenderThreadUpdate (pContext);
211+
212+ for (std::thread& thread : Threads)
213+ {
214+ thread.join ();
215+ }
216+
217+ VerifyBufferContents (pBuffer, BufferData);
218+ }
219+
121220} // namespace
0 commit comments