@@ -105,6 +105,157 @@ void VerifyBufferContents(IBuffer* pBuffer, const std::vector<Uint8>& ExpectedDa
105105 pContext->UnmapBuffer (pReadbackBuffer, MAP_READ);
106106}
107107
108+
109+ void TestWriterScheduleBufferUpdates (bool UseWriteCallback, bool UseCopyCallback)
110+ {
111+ GPUTestingEnvironment* pEnv = GPUTestingEnvironment::GetInstance ();
112+ IRenderDevice* pDevice = pEnv->GetDevice ();
113+ IDeviceContext* pContext = pEnv->GetDeviceContext ();
114+
115+ GPUTestingEnvironment::ScopedReset AutoReset;
116+
117+ std::vector<Uint8> BufferData (8192 );
118+ for (size_t i = 0 ; i < BufferData.size (); ++i)
119+ {
120+ BufferData[i] = static_cast <Uint8>(i % 256 );
121+ }
122+
123+ static constexpr Uint32 kNumUpdates = 10 ;
124+ constexpr std::array<Uint32, kNumUpdates > UpdateSizes = {256 , 512 , 256 , 1024 , 2048 , 1024 , 2048 , 512 , 256 , 256 };
125+
126+ BufferDesc Desc;
127+ Desc.Name = " GPUUploadManagerTest buffer" ;
128+ Desc.Size = BufferData.size ();
129+ Desc.Usage = USAGE_DEFAULT;
130+ Desc.BindFlags = BIND_VERTEX_BUFFER;
131+
132+ RefCntAutoPtr<IBuffer> pBuffer;
133+ pDevice->CreateBuffer (Desc, nullptr , &pBuffer);
134+ ASSERT_TRUE (pBuffer);
135+
136+ Uint32 CurrOffset = 0 ;
137+
138+ GPUUploadManagerImpl::Page Page{nullptr , pDevice, static_cast <Uint32>(BufferData.size ())};
139+ Page.Reset (pContext);
140+ Page.Unseal ();
141+
142+ GPUUploadManagerImpl::Page::Writer Writer = Page.TryBeginWriting ();
143+ EXPECT_TRUE (Writer) << " Should be able to begin writing to a new page" ;
144+
145+ Uint32 NumWriteDataCallbackCalled = 0 ;
146+
147+ auto WriteDataCallback = MakeCallback ([&](void * pDstData, Uint32 NumBytes) {
148+ std::memcpy (pDstData, &BufferData[CurrOffset], NumBytes);
149+ ++NumWriteDataCallbackCalled;
150+ });
151+
152+ Uint32 NumCopyBufferCallbackCalled = 0 ;
153+ Uint32 CopyBufferCallbackDstOffset = 0 ;
154+
155+ auto CopyBufferCallback = MakeCallback ([&](IDeviceContext* pContext,
156+ IBuffer* pSrcBuffer,
157+ Uint32 SrcOffset,
158+ Uint32 NumBytes) {
159+ EXPECT_EQ (NumBytes, UpdateSizes[NumCopyBufferCallbackCalled]);
160+ pContext->CopyBuffer (pSrcBuffer, SrcOffset, RESOURCE_STATE_TRANSITION_MODE_TRANSITION,
161+ pBuffer, CopyBufferCallbackDstOffset, NumBytes, RESOURCE_STATE_TRANSITION_MODE_TRANSITION);
162+ CopyBufferCallbackDstOffset += NumBytes;
163+ ++NumCopyBufferCallbackCalled;
164+ });
165+
166+ Uint32 NumUploadEnqueuedCallbackCalled = 0 ;
167+ Uint32 UploadEnqueuedCallbackDstOffset = 0 ;
168+
169+ auto UploadEnqueuedCallback = MakeCallback (
170+ [&](IBuffer* pDstBuffer,
171+ Uint32 DstOffset,
172+ Uint32 NumBytes) {
173+ EXPECT_EQ (NumBytes, UpdateSizes[NumUploadEnqueuedCallbackCalled]);
174+ EXPECT_EQ (DstOffset, UploadEnqueuedCallbackDstOffset);
175+ UploadEnqueuedCallbackDstOffset += NumBytes;
176+ ++NumUploadEnqueuedCallbackCalled;
177+ });
178+
179+ for (Uint32 NumBytes : UpdateSizes)
180+ {
181+ ScheduleBufferUpdateInfo UpdateInfo;
182+ UpdateInfo.NumBytes = NumBytes;
183+
184+ if (UseCopyCallback)
185+ {
186+ UpdateInfo.CopyBuffer = CopyBufferCallback;
187+ UpdateInfo.pCopyBufferData = CopyBufferCallback;
188+ }
189+ else
190+ {
191+ UpdateInfo.pDstBuffer = pBuffer;
192+ UpdateInfo.DstOffset = CurrOffset;
193+ }
194+
195+ if (UseWriteCallback)
196+ {
197+ UpdateInfo.WriteDataCallback = WriteDataCallback;
198+ UpdateInfo.pWriteDataCallbackUserData = WriteDataCallback;
199+ }
200+ else
201+ {
202+ UpdateInfo.pSrcData = &BufferData[CurrOffset];
203+ }
204+
205+ UpdateInfo.UploadEnqueued = UploadEnqueuedCallback;
206+ UpdateInfo.pUploadEnqueuedData = UploadEnqueuedCallback;
207+
208+ EXPECT_TRUE (Writer.ScheduleBufferUpdate (UpdateInfo));
209+
210+ CurrOffset += NumBytes;
211+ }
212+ VERIFY_EXPR (CurrOffset == BufferData.size ());
213+
214+ {
215+ ScheduleBufferUpdateInfo UpdateInfo;
216+ UpdateInfo.pDstBuffer = pBuffer;
217+ UpdateInfo.NumBytes = 16 ;
218+ UpdateInfo.DstOffset = 0 ;
219+ UpdateInfo.pSrcData = &BufferData[0 ];
220+ EXPECT_FALSE (Writer.ScheduleBufferUpdate (UpdateInfo)) << " Should not be able to schedule updates when the page is full" ;
221+ }
222+
223+ EXPECT_EQ (Page.GetNumPendingOps (), UpdateSizes.size ());
224+ EXPECT_TRUE (Writer.EndWriting () == GPUUploadManagerImpl::Page::WritingStatus::NotSealed) << " Page should not be sealed" ;
225+
226+ EXPECT_EQ (Page.TrySeal (), GPUUploadManagerImpl::Page::SealStatus::Ready) << " Page with no active writers should be ready immediately" ;
227+ EXPECT_EQ (Page.GetNumPendingOps (), UpdateSizes.size ());
228+ Page.ExecutePendingOps (pContext, 1 );
229+ EXPECT_EQ (Page.GetNumPendingOps (), size_t {0 });
230+ EXPECT_EQ (NumUploadEnqueuedCallbackCalled, UseCopyCallback ? 0u : kNumUpdates );
231+ Page.ReleaseStagingBuffer (pContext);
232+
233+ EXPECT_EQ (UseWriteCallback ? kNumUpdates : 0u , NumWriteDataCallbackCalled);
234+ EXPECT_EQ (UseCopyCallback ? kNumUpdates : 0u , NumCopyBufferCallbackCalled);
235+
236+ VerifyBufferContents (pBuffer, BufferData);
237+ }
238+
239+ TEST (GPUUploadManagerTest, Writer_ScheduleBufferUpdates)
240+ {
241+ TestWriterScheduleBufferUpdates (/* UseWriteCallback = */ false , /* UseCopyCallback = */ false );
242+ }
243+
244+ TEST (GPUUploadManagerTest, Writer_ScheduleBufferUpdatesWithWriteBufferCallback)
245+ {
246+ TestWriterScheduleBufferUpdates (/* UseWriteCallback = */ true , /* UseCopyCallback = */ false );
247+ }
248+
249+ TEST (GPUUploadManagerTest, Writer_ScheduleBufferUpdatesWithCopyBufferCallback)
250+ {
251+ TestWriterScheduleBufferUpdates (/* UseWriteCallback = */ false , /* UseCopyCallback = */ true );
252+ }
253+
254+ TEST (GPUUploadManagerTest, Writer_ScheduleBufferUpdatesWithWriteAndCopyCallbacks)
255+ {
256+ TestWriterScheduleBufferUpdates (/* UseWriteCallback = */ true , /* UseCopyCallback = */ true );
257+ }
258+
108259TEST (GPUUploadManagerTest, ScheduleBufferUpdates)
109260{
110261 GPUTestingEnvironment* pEnv = GPUTestingEnvironment::GetInstance ();
@@ -184,22 +335,22 @@ TEST(GPUUploadManagerTest, ScheduleBufferUpdatesWithCopyBufferCallback)
184335
185336 Uint32 CurrOffset = 0 ;
186337
187- auto GetDstBufferInfo = MakeCallback ([&](IDeviceContext* pContext,
188- IBuffer* pSrcBuffer,
189- Uint32 SrcOffset,
190- Uint32 NumBytes) {
338+ auto CopyBufferCallback = MakeCallback ([&](IDeviceContext* pContext,
339+ IBuffer* pSrcBuffer,
340+ Uint32 SrcOffset,
341+ Uint32 NumBytes) {
191342 pContext->CopyBuffer (pSrcBuffer, SrcOffset, RESOURCE_STATE_TRANSITION_MODE_TRANSITION,
192343 pBuffer, CurrOffset, NumBytes, RESOURCE_STATE_TRANSITION_MODE_TRANSITION);
193344 CurrOffset += NumBytes;
194345 });
195346
196- pUploadManager->ScheduleBufferUpdate ({pContext, 256 , &BufferData[0 ], GetDstBufferInfo, GetDstBufferInfo });
197- pUploadManager->ScheduleBufferUpdate ({pContext, 256 , &BufferData[256 ], GetDstBufferInfo, GetDstBufferInfo });
198- pUploadManager->ScheduleBufferUpdate ({pContext, 1024 , &BufferData[512 ], GetDstBufferInfo, GetDstBufferInfo });
199- pUploadManager->ScheduleBufferUpdate ({pContext, 512 , &BufferData[1536 ], GetDstBufferInfo, GetDstBufferInfo });
200- pUploadManager->ScheduleBufferUpdate ({pContext, 2048 , &BufferData[2048 ], GetDstBufferInfo, GetDstBufferInfo });
201- pUploadManager->ScheduleBufferUpdate ({pContext, 4096 , &BufferData[4096 ], GetDstBufferInfo, GetDstBufferInfo });
202- pUploadManager->ScheduleBufferUpdate ({pContext, 8192 , &BufferData[8192 ], GetDstBufferInfo, GetDstBufferInfo });
347+ pUploadManager->ScheduleBufferUpdate ({pContext, 256 , &BufferData[0 ], CopyBufferCallback, CopyBufferCallback });
348+ pUploadManager->ScheduleBufferUpdate ({pContext, 256 , &BufferData[256 ], CopyBufferCallback, CopyBufferCallback });
349+ pUploadManager->ScheduleBufferUpdate ({pContext, 1024 , &BufferData[512 ], CopyBufferCallback, CopyBufferCallback });
350+ pUploadManager->ScheduleBufferUpdate ({pContext, 512 , &BufferData[1536 ], CopyBufferCallback, CopyBufferCallback });
351+ pUploadManager->ScheduleBufferUpdate ({pContext, 2048 , &BufferData[2048 ], CopyBufferCallback, CopyBufferCallback });
352+ pUploadManager->ScheduleBufferUpdate ({pContext, 4096 , &BufferData[4096 ], CopyBufferCallback, CopyBufferCallback });
353+ pUploadManager->ScheduleBufferUpdate ({pContext, 8192 , &BufferData[8192 ], CopyBufferCallback, CopyBufferCallback });
203354
204355 pUploadManager->RenderThreadUpdate (pContext);
205356 pUploadManager->RenderThreadUpdate (pContext);
@@ -802,8 +953,8 @@ void TestWriterScheduleTextureUpdates(Uint32 Flags = TEST_TEXTURE_UPDATES_FLAGS_
802953 Page->Reset (pContext);
803954 Page->Unseal ();
804955
805- bool WriteDataCallbackCalled = false ;
806- bool CopyTextureCallbackCalled = false ;
956+ Uint32 NumWriteDataCallbackCalled = 0 ;
957+ Uint32 NumCopyTextureCallbackCalled = 0 ;
807958
808959 auto WriteDataCallback = MakeCallback ([&](void * pDstData, Uint32 Stride, Uint32 DepthStride, const Box& DstBox) {
809960 for (Uint32 row = 0 ; row < DstBox.Height (); ++row)
@@ -812,15 +963,15 @@ void TestWriterScheduleTextureUpdates(Uint32 Flags = TEST_TEXTURE_UPDATES_FLAGS_
812963 void * pDstRow = static_cast <Uint8*>(pDstData) + row * Stride;
813964 std::memcpy (pDstRow, pSrcRow, DstBox.Width () * ElementSize);
814965 }
815- WriteDataCallbackCalled = true ;
966+ ++NumWriteDataCallbackCalled ;
816967 });
817968
818969 struct CopyTextureCallbackData
819970 {
820971 ITexture* const pDstTexture;
821- bool & CopyTextureCallbackCalled ;
972+ Uint32 & NumCopyTextureCallbackCalled ;
822973 };
823- CopyTextureCallbackData CopyCallbackData{pTexture, CopyTextureCallbackCalled };
974+ CopyTextureCallbackData CopyCallbackData{pTexture, NumCopyTextureCallbackCalled };
824975
825976 auto CopyTextureCallback = [](IDeviceContext* pContext,
826977 Uint32 DstMipLevel,
@@ -832,7 +983,7 @@ void TestWriterScheduleTextureUpdates(Uint32 Flags = TEST_TEXTURE_UPDATES_FLAGS_
832983 pContext->UpdateTexture (pCallbackData->pDstTexture , DstMipLevel, DstSlice, DstBox, SrcData,
833984 RESOURCE_STATE_TRANSITION_MODE_TRANSITION,
834985 RESOURCE_STATE_TRANSITION_MODE_TRANSITION);
835- pCallbackData->CopyTextureCallbackCalled = true ;
986+ ++ pCallbackData->NumCopyTextureCallbackCalled ;
836987 };
837988
838989 auto CopyD3D11TextureCallback = [](IDeviceContext* pContext,
@@ -865,9 +1016,18 @@ void TestWriterScheduleTextureUpdates(Uint32 Flags = TEST_TEXTURE_UPDATES_FLAGS_
8651016 CopyAttribs.DstTextureTransitionMode = RESOURCE_STATE_TRANSITION_MODE_TRANSITION;
8661017
8671018 pContext->CopyTexture (CopyAttribs);
868- pCallbackData->CopyTextureCallbackCalled = true ;
1019+ ++ pCallbackData->NumCopyTextureCallbackCalled ;
8691020 };
8701021
1022+ Uint32 NumUploadEnqueuedCallbackCalled = 0 ;
1023+
1024+ auto UploadEnqueuedCallback = MakeCallback ([&](ITexture* pDstTexture,
1025+ Uint32 DstMipLevel,
1026+ Uint32 DstSlice,
1027+ const Box& DstBox) {
1028+ ++NumUploadEnqueuedCallbackCalled;
1029+ });
1030+
8711031 {
8721032 GPUUploadManagerImpl::Page::Writer Writer = Page->TryBeginWriting ();
8731033 EXPECT_TRUE (Writer) << " Should be able to begin writing to a new page" ;
@@ -899,6 +1059,10 @@ void TestWriterScheduleTextureUpdates(Uint32 Flags = TEST_TEXTURE_UPDATES_FLAGS_
8991059 UpdateInfo.pSrcData = &Mip0Data[(UpdateInfo.DstBox .MinX + UpdateInfo.DstBox .MinY * TexDesc.Width ) * ElementSize];
9001060 UpdateInfo.Stride = TexDesc.Width * ElementSize;
9011061 }
1062+
1063+ UpdateInfo.UploadEnqueued = UploadEnqueuedCallback;
1064+ UpdateInfo.pUploadEnqueuedData = UploadEnqueuedCallback;
1065+
9021066 return Writer.ScheduleTextureUpdate (UpdateInfo, GetBufferToTextureCopyInfo (TexDesc.Format , UpdateInfo.DstBox , 1024 ), 1024 );
9031067 };
9041068
@@ -920,10 +1084,11 @@ void TestWriterScheduleTextureUpdates(Uint32 Flags = TEST_TEXTURE_UPDATES_FLAGS_
9201084 EXPECT_EQ (Page->GetNumPendingOps (), size_t {4 });
9211085 Page->ExecutePendingOps (pContext, 1 );
9221086 EXPECT_EQ (Page->GetNumPendingOps (), size_t {0 });
1087+ EXPECT_EQ (NumUploadEnqueuedCallbackCalled, (Flags & TEST_TEXTURE_UPDATES_FLAGS_USE_COPY_CALLBACK) ? 0u : 4u );
9231088 Page->ReleaseStagingBuffer (pContext);
9241089
925- EXPECT_EQ ((Flags & TEST_TEXTURE_UPDATES_FLAGS_USE_WRITE_DATA_CALLBACK) != 0 , WriteDataCallbackCalled );
926- EXPECT_EQ ((Flags & TEST_TEXTURE_UPDATES_FLAGS_USE_COPY_CALLBACK) != 0 , CopyTextureCallbackCalled );
1090+ EXPECT_EQ ((Flags & TEST_TEXTURE_UPDATES_FLAGS_USE_WRITE_DATA_CALLBACK) ? 4u : 0u , NumWriteDataCallbackCalled );
1091+ EXPECT_EQ ((Flags & TEST_TEXTURE_UPDATES_FLAGS_USE_COPY_CALLBACK) ? 4u : 0u , NumCopyTextureCallbackCalled );
9271092
9281093 VerifyTextureContents (pTexture, SubresData);
9291094}
@@ -943,7 +1108,7 @@ TEST(GPUUploadManagerTest, Writer_ScheduleTextureUpdates_WithCopyCallback)
9431108 TestWriterScheduleTextureUpdates (TEST_TEXTURE_UPDATES_FLAGS_USE_COPY_CALLBACK);
9441109}
9451110
946- TEST (GPUUploadManagerTest, Writer_ScheduleTextureUpdates_WithWriteAndCopyCallback )
1111+ TEST (GPUUploadManagerTest, Writer_ScheduleTextureUpdates_WithWriteAndCopyCallbacks )
9471112{
9481113 TestWriterScheduleTextureUpdates (TEST_TEXTURE_UPDATES_FLAGS_USE_WRITE_DATA_CALLBACK | TEST_TEXTURE_UPDATES_FLAGS_USE_COPY_CALLBACK);
9491114}
0 commit comments