Skip to content

Commit a5f4ce8

Browse files
GPUUploadManager: split uploads into normal and large streams
1 parent 7176f8e commit a5f4ce8

File tree

4 files changed

+355
-190
lines changed

4 files changed

+355
-190
lines changed

Graphics/GraphicsTools/include/GPUUploadManagerImpl.hpp

Lines changed: 73 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838

3939
#include <memory>
4040
#include <vector>
41+
#include <array>
4142
#include <mutex>
4243
#include <map>
4344
#include <unordered_map>
@@ -70,7 +71,7 @@ class GPUUploadManagerImpl final : public ObjectBase<IGPUUploadManager>
7071
public:
7172
explicit Page(Uint32 Size, bool PersistentMapped = false) noexcept;
7273

73-
Page(IRenderDevice* pDevice, Uint32 Size);
74+
Page(size_t StreamIndex, IRenderDevice* pDevice, Uint32 Size);
7475
~Page();
7576

7677
enum class WritingStatus
@@ -142,6 +143,8 @@ class GPUUploadManagerImpl final : public ObjectBase<IGPUUploadManager>
142143
// Returns true if the page was not previously enqueued, false otherwise.
143144
bool TryEnqueue();
144145

146+
size_t GetStreamIndex() const { return m_StreamIdx; }
147+
145148
Uint64 GetFenceValue() const { return m_FenceValue; }
146149
Uint32 GetSize() const { return m_Size; }
147150

@@ -177,6 +180,7 @@ class GPUUploadManagerImpl final : public ObjectBase<IGPUUploadManager>
177180
WritingStatus EndWriting();
178181

179182
private:
183+
const size_t m_StreamIdx = 0;
180184
const Uint32 m_Size = 0;
181185
const bool m_PersistentMapped = false;
182186

@@ -238,26 +242,14 @@ class GPUUploadManagerImpl final : public ObjectBase<IGPUUploadManager>
238242
};
239243

240244
private:
241-
void ScheduleUpdate(IDeviceContext* pContext,
242-
Uint32 UpdateSize,
243-
const void* pUpdateInfo,
244-
bool ScheduleUpdate(Page::Writer& Writer, const void* pUpdateInfo));
245-
246-
void ReclaimCompletedPages(IDeviceContext* pContext);
247-
bool SealAndSwapCurrentPage(IDeviceContext* pContext);
248-
void AddFreePages(IDeviceContext* pContext);
249-
void ProcessPendingPages(IDeviceContext* pContext);
250-
bool TryRotatePage(IDeviceContext* pContext, Page* ExpectedCurrent, Uint32 RequiredSize);
251-
bool TryEnqueuePage(Page* P);
252-
Page* AcquireFreePage(IDeviceContext* pContext, Uint32 RequiredSize = 0);
253-
Page* CreatePage(IDeviceContext* pContext, Uint32 RequiredSize = 0);
254-
void ProcessPagesToRelease(IDeviceContext* pContext);
255-
void UpdateBucketInfo();
245+
class UploadStream;
256246

257-
private:
258-
const Uint32 m_PageSize;
259-
const Uint32 m_MaxPageCount;
247+
void ReclaimCompletedPages(IDeviceContext* pContext);
248+
void ProcessPendingPages(IDeviceContext* pContext);
249+
250+
UploadStream& GetStreamForUpdateSize(Uint32 UpdateSize);
260251

252+
private:
261253
RefCntAutoPtr<IRenderDevice> m_pDevice;
262254
RefCntAutoPtr<IDeviceContext> m_pContext;
263255

@@ -281,7 +273,6 @@ class GPUUploadManagerImpl final : public ObjectBase<IGPUUploadManager>
281273
std::map<Uint32, std::vector<Page*>> m_PagesBySize;
282274
std::atomic<size_t> m_Size{0};
283275
};
284-
FreePages m_FreePages;
285276

286277
// Pages that have been submitted for execution and are being processed by the GPU.
287278
std::vector<Page*> m_InFlightPages;
@@ -290,24 +281,75 @@ class GPUUploadManagerImpl final : public ObjectBase<IGPUUploadManager>
290281
RefCntAutoPtr<IFence> m_pFence;
291282
Uint64 m_NextFenceValue = 1;
292283

293-
std::atomic<Page*> m_pCurrentPage{nullptr};
294-
Threading::TickSignal m_PageRotatedSignal;
284+
class UploadStream
285+
{
286+
public:
287+
UploadStream(GPUUploadManagerImpl& Mgr,
288+
size_t StreamIdx,
289+
Uint32 PageSize,
290+
Uint32 MaxPageCount,
291+
Uint32 InitialPageCount) noexcept;
292+
293+
Page* CreatePage(IDeviceContext* pContext, Uint32 RequiredSize = 0);
294+
Page* AcquireFreePage(IDeviceContext* pContext, Uint32 RequiredSize = 0);
295+
bool SealAndSwapCurrentPage(IDeviceContext* pContext);
296+
bool TryRotatePage(IDeviceContext* pContext, Page* ExpectedCurrent, Uint32 RequiredSize);
297+
bool TryEnqueuePage(Page* P);
298+
void ProcessPagesToRelease(IDeviceContext* pContext);
299+
void AddFreePages(IDeviceContext* pContext);
300+
void AddFreePage(Page* pPage) { m_FreePages.Push(pPage); }
301+
302+
void ScheduleUpdate(IDeviceContext* pContext,
303+
Uint32 UpdateSize,
304+
const void* pUpdateInfo,
305+
bool ScheduleUpdate(Page::Writer& Writer, const void* pUpdateInfo));
306+
void ReleaseStagingBuffers();
307+
void SignalPageRotated() { m_PageRotatedSignal.Tick(); }
308+
void SignalStop();
309+
310+
Uint32 GetPageSize() const { return m_PageSize; }
311+
312+
void GetStats(GPUUploadManagerStreamStats& Stats) const;
313+
314+
private:
315+
GPUUploadManagerImpl& m_Mgr;
316+
const size_t m_StreamIdx;
317+
const Uint32 m_PageSize;
318+
const Uint32 m_MaxPageCount;
319+
320+
std::atomic<Page*> m_pCurrentPage{nullptr};
295321

296-
std::unordered_map<Page*, std::unique_ptr<Page>> m_Pages;
297-
std::map<Uint32, Uint32> m_PageSizeToCount;
298-
std::vector<GPUUploadManagerBucketInfo> m_BucketInfo;
322+
Threading::TickSignal m_PageRotatedSignal;
323+
324+
std::unordered_map<Page*, std::unique_ptr<Page>> m_Pages;
325+
std::map<Uint32, Uint32> m_PageSizeToCount;
326+
mutable std::vector<GPUUploadManagerBucketInfo> m_BucketInfo;
327+
328+
std::atomic<Uint32> m_NumRunningUpdates{0};
329+
std::atomic<Uint32> m_MaxPendingUpdateSize{0};
330+
std::atomic<Uint32> m_TotalPendingUpdateSize{0};
331+
332+
FreePages m_FreePages;
333+
334+
std::atomic<Uint32> m_PeakUpdateSize{0};
335+
Uint32 m_PeakTotalPendingUpdateSize = 0;
336+
Uint32 m_PeakPageCount = 0;
337+
};
338+
339+
enum class UploadStreamType : Uint32
340+
{
341+
Normal = 0,
342+
Large = 1,
343+
Count
344+
};
345+
std::array<UploadStream, static_cast<size_t>(UploadStreamType::Count)> m_Streams;
299346

300347
// The number of running ScheduleBufferUpdate operations.
301348
std::atomic<Uint32> m_NumRunningUpdates{0};
302349
std::atomic<bool> m_Stopping{false};
303350
Threading::Signal m_LastRunningThreadFinishedSignal;
304351

305-
std::atomic<Uint32> m_MaxPendingUpdateSize{0};
306-
std::atomic<Uint32> m_TotalPendingUpdateSize{0};
307-
308-
std::atomic<Uint32> m_PeakUpdateSize{0};
309-
Uint32 m_PeakTotalPendingUpdateSize = 0;
310-
Uint32 m_PeakPageCount = 0;
352+
mutable std::array<GPUUploadManagerStreamStats, static_cast<size_t>(UploadStreamType::Count)> m_StreamStats;
311353
};
312354

313355
} // namespace Diligent

Graphics/GraphicsTools/interface/GPUUploadManager.h

Lines changed: 37 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -42,19 +42,30 @@ struct GPUUploadManagerCreateInfo
4242
/// Pointer to the device context. Must not be null.
4343
IDeviceContext* pContext DEFAULT_INITIALIZER(nullptr);
4444

45-
/// Size of the staging buffer page.
45+
/// Size of the upload page.
4646
Uint32 PageSize DEFAULT_INITIALIZER(4 * 1024 * 1024);
4747

48+
/// Size of the large upload page.
49+
Uint32 LargePageSize DEFAULT_INITIALIZER(16 * 1024 * 1024);
50+
4851
/// Initial number of upload pages. If the manager runs out of pages to write to,
4952
/// it will create new ones as needed. This parameter controls how many pages are created at startup.
5053
Uint32 InitialPageCount DEFAULT_INITIALIZER(1);
5154

52-
/// Maximum number of pages that the manager should maintain.
55+
/// Initial number of large upload pages.
56+
Uint32 InitialLargePageCount DEFAULT_INITIALIZER(1);
57+
58+
/// Maximum number of pages that the manager should maintain. If 0, there is no limit to the number
59+
/// of pages that can be created.
5360
///
5461
/// Note the manager may temporarily exceed this limit in certain scenarios (for example, if large
5562
/// update is scheduled while the maximum is already reached), but it will reduce the number of
5663
/// pages to the maximum as soon as possible.
5764
Uint32 MaxPageCount DEFAULT_INITIALIZER(64);
65+
66+
/// Maximum number of large pages that the manager should maintain. If 0, there is no limit to the number
67+
/// of large pages that can be created.
68+
Uint32 MaxLargePageCount DEFAULT_INITIALIZER(16);
5869
};
5970
typedef struct GPUUploadManagerCreateInfo GPUUploadManagerCreateInfo;
6071

@@ -408,18 +419,18 @@ struct GPUUploadManagerBucketInfo
408419
typedef struct GPUUploadManagerBucketInfo GPUUploadManagerBucketInfo;
409420

410421

411-
/// GPU upload manager statistics.
412-
struct GPUUploadManagerStats
422+
/// GPU upload manager stream statistics.
423+
struct GPUUploadManagerStreamStats
413424
{
425+
/// Page size in bytes for this stream.
426+
Uint32 PageSize DEFAULT_INITIALIZER(0);
427+
414428
/// The number of pages in the manager.
415429
Uint32 NumPages DEFAULT_INITIALIZER(0);
416430

417431
/// The number of free pages that are ready to be written to.
418432
Uint32 NumFreePages DEFAULT_INITIALIZER(0);
419433

420-
/// The number of pages that are currently being used by the GPU for copy operations.
421-
Uint32 NumInFlightPages DEFAULT_INITIALIZER(0);
422-
423434
/// The peak number of pages that were created by the manager. This value can exceed the maximum page count,
424435
/// but only temporarily when the manager needs to create new pages to accommodate large updates.
425436
Uint32 PeakNumPages DEFAULT_INITIALIZER(0);
@@ -435,11 +446,23 @@ struct GPUUploadManagerStats
435446
Uint32 NumBuckets DEFAULT_INITIALIZER(0);
436447

437448
/// Information about each bucket. The array contains NumBuckets valid entries.
438-
/// The pointer is valid only until the next call to RenderThreadUpdate() or
439-
/// ScheduleBufferUpdate() with a non-null device context, which may change the number
440-
/// of buckets.
449+
/// The pointer is valid only until the next call to GetStats().
441450
const GPUUploadManagerBucketInfo* pBucketInfo DEFAULT_INITIALIZER(nullptr);
442451
};
452+
typedef struct GPUUploadManagerStreamStats GPUUploadManagerStreamStats;
453+
454+
/// GPU upload manager statistics.
455+
struct GPUUploadManagerStats
456+
{
457+
/// An array of NumStreams stream statistics.
458+
const GPUUploadManagerStreamStats* pStreamStats DEFAULT_INITIALIZER(nullptr);
459+
460+
/// The number of streams in the pStreamStats array.
461+
Uint32 NumStreams DEFAULT_INITIALIZER(0);
462+
463+
/// The number of pages that are currently being used by the GPU for copy operations.
464+
Uint32 NumInFlightPages DEFAULT_INITIALIZER(0);
465+
};
443466
typedef struct GPUUploadManagerStats GPUUploadManagerStats;
444467

445468

@@ -518,6 +541,10 @@ DILIGENT_END_INTERFACE
518541

519542
// clang-format on
520543

544+
#else
545+
546+
std::string GetManagerStatsString(const GPUUploadManagerStats& Stats);
547+
521548
#endif
522549

523550
/// Creates an instance of the GPU upload manager.

0 commit comments

Comments
 (0)