3535#include " RefCntAutoPtr.hpp"
3636#include " MPSCQueue.hpp"
3737#include " ThreadSignal.hpp"
38+ #include " DynamicAtlasManager.hpp"
3839
3940#include < memory>
4041#include < vector>
41- #include < array>
4242#include < mutex>
43+ #include < shared_mutex>
4344#include < map>
4445#include < unordered_map>
4546#include < variant>
@@ -64,14 +65,23 @@ class GPUUploadManagerImpl final : public ObjectBase<IGPUUploadManager>
6465
6566 virtual void DILIGENT_CALL_TYPE ScheduleTextureUpdate (const ScheduleTextureUpdateInfo& UpdateInfo) override final ;
6667
67- virtual void DILIGENT_CALL_TYPE GetStats (GPUUploadManagerStats& Stats) const override final ;
68+ virtual void DILIGENT_CALL_TYPE GetStats (GPUUploadManagerStats& Stats) override final ;
6869
70+ private:
71+ class UploadStream ;
72+
73+ public:
6974 class Page
7075 {
7176 public:
7277 explicit Page (Uint32 Size, bool PersistentMapped = false ) noexcept ;
7378
74- Page (size_t StreamIndex, IRenderDevice* pDevice, Uint32 Size);
79+ Page (UploadStream& Stream, IRenderDevice* pDevice, Uint32 Size);
80+
81+ // Special page for texture updates in Direct3D11, which require a staging texture.
82+ // The texture dimensions are Size x Size.
83+ Page (UploadStream& Stream, IRenderDevice* pDevice, Uint32 Size, TEXTURE_FORMAT Format);
84+
7585 ~Page ();
7686
7787 enum class WritingStatus
@@ -143,7 +153,7 @@ class GPUUploadManagerImpl final : public ObjectBase<IGPUUploadManager>
143153 // Returns true if the page was not previously enqueued, false otherwise.
144154 bool TryEnqueue ();
145155
146- size_t GetStreamIndex () const { return m_StreamIdx ; }
156+ UploadStream* GetStream () const { return m_pStream ; }
147157
148158 Uint64 GetFenceValue () const { return m_FenceValue; }
149159 Uint32 GetSize () const { return m_Size; }
@@ -179,13 +189,40 @@ class GPUUploadManagerImpl final : public ObjectBase<IGPUUploadManager>
179189
180190 WritingStatus EndWriting ();
181191
192+ void UnmapStagingResource (IDeviceContext* pContext);
193+
182194 private:
183- const size_t m_StreamIdx = 0 ;
195+ UploadStream* const m_pStream = nullptr ;
196+
184197 const Uint32 m_Size = 0 ;
185198 const bool m_PersistentMapped = false ;
186199
187200 RefCntAutoPtr<IBuffer> m_pStagingBuffer;
188201
202+ // Direct3D11 does not support buffer to texture copies, so we need a
203+ // staging texture to perform texture updates.
204+ struct StagingTextureAtlas
205+ {
206+ StagingTextureAtlas (IRenderDevice* pDevice, Uint32 Width, Uint32 Height, TEXTURE_FORMAT Format, const std::string& Name);
207+ ~StagingTextureAtlas ();
208+
209+ void * Map (IDeviceContext* pContext);
210+ void Unmap (IDeviceContext* pContext);
211+ void Reset ();
212+
213+ DynamicAtlasManager::Region Allocate (Uint32 Width, Uint32 Height);
214+
215+ RefCntAutoPtr<ITexture> pTex;
216+
217+ Uint32 RowStride = 0 ;
218+ Uint32 DepthStride = 0 ;
219+
220+ private:
221+ std::mutex MgrMtx;
222+ DynamicAtlasManager Mgr;
223+ };
224+ std::unique_ptr<StagingTextureAtlas> m_pStagingAtlas;
225+
189226 void * m_pData = nullptr ;
190227
191228 std::atomic<Uint32> m_Offset{0 };
@@ -217,11 +254,14 @@ class GPUUploadManagerImpl final : public ObjectBase<IGPUUploadManager>
217254 PendingBufferOp () noexcept = default ;
218255 };
219256
220-
221257 struct PendingTextureOp
222258 {
223259 RefCntAutoPtr<ITexture> pDstTexture;
224260
261+ // For Direct3D11, coordinates of the source region within the staging texture.
262+ Uint32 SrcX = 0 ;
263+ Uint32 SrcY = 0 ;
264+
225265 Uint32 SrcOffset = 0 ;
226266 Uint32 SrcStride = 0 ;
227267 Uint32 SrcDepthStride = 0 ;
@@ -230,20 +270,21 @@ class GPUUploadManagerImpl final : public ObjectBase<IGPUUploadManager>
230270 Uint32 DstSlice = 0 ;
231271 Box DstBox;
232272
233- CopyStagingTextureCallbackType CopyTexture = nullptr ;
234- void * pCopyTextureData = nullptr ;
273+ CopyStagingTextureCallbackType CopyTexture = nullptr ;
274+ CopyStagingD3D11TextureCallbackType CopyD3D11Texture = nullptr ;
275+ void * pCopyTextureData = nullptr ;
235276
236277 GPUTextureUploadEnqueuedCallbackType UploadEnqueued = nullptr ;
237278 void * pUploadEnqueuedData = nullptr ;
238279 };
239280
240281 using PendingOp = std::variant<PendingBufferOp, PendingTextureOp>;
241282 MPSCQueue<PendingOp> m_PendingOps;
283+
284+ static std::atomic<int > sm_PageCounter;
242285 };
243286
244287private:
245- class UploadStream ;
246-
247288 void ReclaimCompletedPages (IDeviceContext* pContext);
248289 void ProcessPendingPages (IDeviceContext* pContext);
249290
@@ -285,10 +326,11 @@ class GPUUploadManagerImpl final : public ObjectBase<IGPUUploadManager>
285326 {
286327 public:
287328 UploadStream (GPUUploadManagerImpl& Mgr,
288- size_t StreamIdx ,
329+ IDeviceContext* pContext ,
289330 Uint32 PageSize,
290331 Uint32 MaxPageCount,
291- Uint32 InitialPageCount) noexcept ;
332+ Uint32 InitialPageCount,
333+ TEXTURE_FORMAT Format = TEX_FORMAT_UNKNOWN) noexcept ;
292334
293335 Page* CreatePage (IDeviceContext* pContext, Uint32 RequiredSize = 0 );
294336 Page* AcquireFreePage (IDeviceContext* pContext, Uint32 RequiredSize = 0 );
@@ -313,9 +355,9 @@ class GPUUploadManagerImpl final : public ObjectBase<IGPUUploadManager>
313355
314356 private:
315357 GPUUploadManagerImpl& m_Mgr;
316- const size_t m_StreamIdx;
317358 const Uint32 m_PageSize;
318359 const Uint32 m_MaxPageCount;
360+ const TEXTURE_FORMAT m_Format;
319361
320362 std::atomic<Page*> m_pCurrentPage{nullptr };
321363
@@ -336,20 +378,48 @@ class GPUUploadManagerImpl final : public ObjectBase<IGPUUploadManager>
336378 Uint32 m_PeakPageCount = 0 ;
337379 };
338380
339- enum class UploadStreamType : Uint32
381+ using UploadStreamUniquePtr = std::unique_ptr<UploadStream>;
382+ std::vector<UploadStreamUniquePtr> m_Streams;
383+
384+ UploadStream* m_pNormalStream = nullptr ;
385+ UploadStream* m_pLargeStream = nullptr ;
386+
387+ class TextureUploadStreams
340388 {
341- Normal = 0 ,
342- Large = 1 ,
343- Count
389+ public:
390+ TextureUploadStreams (GPUUploadManagerImpl& Mgr, Uint32 PageSizeInBytes, Uint32 MaxPageCount) :
391+ m_Mgr{Mgr},
392+ m_PageSizeInBytes{PageSizeInBytes},
393+ m_MaxPageCount{MaxPageCount}
394+ {}
395+
396+ UploadStream* GetStreamForFormat (IDeviceContext* pContext, TEXTURE_FORMAT Format);
397+
398+ void MoveNewStreamsToManager ();
399+ void SetStopping ();
400+
401+ private:
402+ GPUUploadManagerImpl& m_Mgr;
403+ const Uint32 m_PageSizeInBytes;
404+ const Uint32 m_MaxPageCount;
405+
406+ std::shared_mutex m_Mtx;
407+ std::unordered_map<TEXTURE_FORMAT, UploadStream*> m_StreamsByFormat;
408+
409+ // New streams created by worker threads that are not yet added to parent m_Streams vector.
410+ std::mutex m_NewStreamsMtx;
411+ std::vector<std::unique_ptr<UploadStream>> m_NewStreams;
412+ std::atomic<bool > m_HasNewStreams{false };
413+ std::atomic<bool > m_Stopping{false };
344414 };
345- std::array<UploadStream, static_cast < size_t >(UploadStreamType::Count)> m_Streams ;
415+ std::unique_ptr<TextureUploadStreams> m_pTextureStreams ;
346416
347417 // The number of running ScheduleBufferUpdate operations.
348418 std::atomic<Uint32> m_NumRunningUpdates{0 };
349419 std::atomic<bool > m_Stopping{false };
350420 Threading::Signal m_LastRunningThreadFinishedSignal;
351421
352- mutable std::array <GPUUploadManagerStreamStats, static_cast < size_t >(UploadStreamType::Count) > m_StreamStats;
422+ std::vector <GPUUploadManagerStreamStats> m_StreamStats;
353423};
354424
355425} // namespace Diligent
0 commit comments