From fdbd5b4074cc3d41b77ee97e58d03d5c00fadee8 Mon Sep 17 00:00:00 2001 From: allen hux Date: Mon, 12 Sep 2022 11:59:32 -0700 Subject: [PATCH] Re-arch SamplerFeedbackStreaming.h toward a dll-ready interface. Bug fix with barriers for uploading static assets (e.g. index buffers / vertex buffers). --- TileUpdateManager/InternalResources.h | 5 +- TileUpdateManager/SamplerFeedbackStreaming.h | 108 ++++++++----------- TileUpdateManager/StreamingHeap.cpp | 17 ++- TileUpdateManager/StreamingHeap.h | 13 ++- TileUpdateManager/StreamingResource.cpp | 44 +++----- TileUpdateManager/StreamingResourceBase.h | 59 ++++++---- TileUpdateManager/TileUpdateManager.cpp | 66 ++++++------ TileUpdateManager/TileUpdateManagerBase.cpp | 5 +- TileUpdateManager/TileUpdateManagerBase.h | 75 ++++++++----- TileUpdateManager/XeTexture.cpp | 8 +- props/expanse.props | 2 +- src/Scene.cpp | 24 +++-- src/Scene.h | 2 +- src/SceneObject.cpp | 2 +- src/SceneObject.h | 9 +- 15 files changed, 233 insertions(+), 206 deletions(-) diff --git a/TileUpdateManager/InternalResources.h b/TileUpdateManager/InternalResources.h index 848620b..2389315 100644 --- a/TileUpdateManager/InternalResources.h +++ b/TileUpdateManager/InternalResources.h @@ -30,10 +30,7 @@ #include "Streaming.h" -// FIXME: resolve to buffer only supported in Win11 and some insider versions of Win10 -// When resolving to texture, must copy to cpu-readable buffer from gpu texture (which cannot be in the readback heap) -// Buffer mode resolves directly to cpu-readable buffer -#define RESOLVE_TO_TEXTURE 1 +#include "SamplerFeedbackStreaming.h" // for RESOLVE_TO_TEXTURE namespace Streaming { diff --git a/TileUpdateManager/SamplerFeedbackStreaming.h b/TileUpdateManager/SamplerFeedbackStreaming.h index 0ed2248..0abd555 100644 --- a/TileUpdateManager/SamplerFeedbackStreaming.h +++ b/TileUpdateManager/SamplerFeedbackStreaming.h @@ -36,6 +36,7 @@ Draw loop: 1. BeginFrame() with the TileUpdateManager (TUM) 2. Draw your assets using the streaming textures, min-mip-map, and sampler feedback SRVs + Optionally call TUM::QueueFeedback() to get sampler feedback for this draw. SRVs can be created using StreamingResource methods 3. EndFrame() (with the TUM) returns 2 command lists: beforeDraw and afterDraw 4. ExecuteCommandLists() with [beforeDraw, yourCommandList, afterDraw] command lists. @@ -43,83 +44,69 @@ Draw loop: #pragma once -#include "TileUpdateManagerBase.h" -#include "StreamingResourceBase.h" -#include "StreamingHeap.h" +// FIXME: resolve to buffer only supported in Win11 and some insider versions of Win10 +// When resolving to texture, must copy to cpu-readable buffer from gpu texture (which cannot be in the readback heap) +// Setting this to 0 resolves directly to cpu-readable buffer +#define RESOLVE_TO_TEXTURE 1 //================================================== // a streaming resource is associated with a single heap (in this implementation) // multiple streaming resources can use the same heap // TileUpdateManager is used to create these //================================================== -class StreamingHeap : private Streaming::Heap +struct StreamingHeap { -public: - virtual ~StreamingHeap() {} - - UINT GetNumTilesAllocated(); -private: - StreamingHeap() = delete; - StreamingHeap(const StreamingHeap&) = delete; - StreamingHeap(StreamingHeap&&) = delete; - StreamingHeap& operator=(const StreamingHeap&) = delete; - StreamingHeap& operator=(StreamingHeap&&) = delete; - - // required to cast to base class - friend class TileUpdateManager; + virtual void Destroy() = 0; + + virtual UINT GetNumTilesAllocated() const = 0; }; //============================================================================= // a fine-grained streaming, tiled resource // TileUpdateManager is used to create these //============================================================================= -class StreamingResource : private Streaming::StreamingResourceBase +struct StreamingResource { -public: + virtual void Destroy() = 0; + //-------------------------------------------- // applications need access to the resources to create descriptors //-------------------------------------------- - void CreateFeedbackView(ID3D12Device* in_pDevice, D3D12_CPU_DESCRIPTOR_HANDLE in_descriptor); - void CreateStreamingView(ID3D12Device* in_pDevice, D3D12_CPU_DESCRIPTOR_HANDLE in_descriptor); + virtual void CreateFeedbackView(ID3D12Device* in_pDevice, D3D12_CPU_DESCRIPTOR_HANDLE in_descriptor) = 0; + virtual void CreateStreamingView(ID3D12Device* in_pDevice, D3D12_CPU_DESCRIPTOR_HANDLE in_descriptor) = 0; // shader reading min-mip-map buffer will want its dimensions - UINT GetMinMipMapWidth() const; - UINT GetMinMipMapHeight() const; + virtual UINT GetMinMipMapWidth() const = 0; + virtual UINT GetMinMipMapHeight() const = 0; // shader reading min-mip-map buffer will need an offset into the min-mip-map (residency map) // NOTE: all min mip maps are stored in a single buffer. offset into the buffer. - // this saves a massive amount of GPU memory, since each min mip map is much smaller than 64KB - UINT GetMinMipMapOffset() const; + virtual UINT GetMinMipMapOffset() const = 0; // check if the packed mips are loaded. application likely will not want to use this texture before they have loaded - bool GetPackedMipsResident() const; + virtual bool GetPackedMipsResident() const = 0; // if a resource isn't visible, evict associated data // call any time - void QueueEviction(); + virtual void QueueEviction() = 0; - ID3D12Resource* GetTiledResource() const; + virtual ID3D12Resource* GetTiledResource() const = 0; - ID3D12Resource* GetMinMipMap() const; + virtual ID3D12Resource* GetMinMipMap() const = 0; //-------------------------------------------- // for visualization //-------------------------------------------- // number of tiles reserved (not necessarily committed) for this resource - UINT GetNumTilesVirtual() const; + virtual UINT GetNumTilesVirtual() const = 0; #if RESOLVE_TO_TEXTURE - ID3D12Resource* GetResolvedFeedback(); + virtual ID3D12Resource* GetResolvedFeedback() const = 0; #endif - - virtual ~StreamingResource(); -private: - StreamingResource() = delete; - StreamingResource(const StreamingResource&) = delete; - StreamingResource(StreamingResource&&) = delete; - StreamingResource& operator=(const StreamingResource&) = delete; - StreamingResource& operator=(StreamingResource&&) = delete; }; +//============================================================================= +// describe TileUpdateManager (default values are recommended) +//============================================================================= struct TileUpdateManagerDesc { // maximum number of in-flight batches @@ -143,10 +130,12 @@ struct TileUpdateManagerDesc bool m_useDirectStorage{ false }; }; -class TileUpdateManager : private Streaming::TileUpdateManagerBase +//============================================================================= +// manages all the streaming resources +//============================================================================= +struct TileUpdateManager { -public: - TileUpdateManager( + static TileUpdateManager* Create( // query resource for tiling properties. use its device to create internal resources ID3D12Device8* in_pDevice, @@ -155,18 +144,18 @@ class TileUpdateManager : private Streaming::TileUpdateManagerBase const TileUpdateManagerDesc& in_desc); - virtual ~TileUpdateManager(); + virtual void Destroy() = 0; //-------------------------------------------- // Create a heap used by 1 or more StreamingResources // parameter is number of 64KB tiles to manage //-------------------------------------------- - StreamingHeap* CreateStreamingHeap(UINT in_maxNumTilesHeap); + virtual StreamingHeap* CreateStreamingHeap(UINT in_maxNumTilesHeap) = 0; //-------------------------------------------- // Create StreamingResources using a common TileUpdateManager //-------------------------------------------- - StreamingResource* CreateStreamingResource(const std::wstring& in_filename, StreamingHeap* in_pHeap); + virtual StreamingResource* CreateStreamingResource(const std::wstring& in_filename, StreamingHeap* in_pHeap) = 0; //-------------------------------------------- // Call BeginFrame() first, @@ -176,12 +165,12 @@ class TileUpdateManager : private Streaming::TileUpdateManagerBase // (which only happens if StreamingResources are created/destroyed) // NOTE: the root signature should set the associated descriptor range as descriptor and data volatile //-------------------------------------------- - void BeginFrame(ID3D12DescriptorHeap* in_pDescriptorHeap, D3D12_CPU_DESCRIPTOR_HANDLE in_minmipmapDescriptorHandle); + virtual void BeginFrame(ID3D12DescriptorHeap* in_pDescriptorHeap, D3D12_CPU_DESCRIPTOR_HANDLE in_minmipmapDescriptorHandle) = 0; // application must explicitly request feedback for each resource each frame // this allows the application to limit how much time is spent on feedback, or stop processing e.g. for off-screen objects // descriptor required to create Clear() and Resolve() commands - void QueueFeedback(StreamingResource* in_pResource, D3D12_GPU_DESCRIPTOR_HANDLE in_gpuDescriptor); + virtual void QueueFeedback(StreamingResource* in_pResource, D3D12_GPU_DESCRIPTOR_HANDLE in_gpuDescriptor) = 0; //-------------------------------------------- // Call EndFrame() last, paired with each BeginFrame() and after all draw commands @@ -198,39 +187,34 @@ class TileUpdateManager : private Streaming::TileUpdateManagerBase ID3D12CommandList* m_beforeDrawCommands; ID3D12CommandList* m_afterDrawCommands; }; - CommandLists EndFrame(); + virtual CommandLists EndFrame() = 0; //-------------------------------------------- // choose DirectStorage vs. manual tile loading //-------------------------------------------- - void UseDirectStorage(bool in_useDS); + virtual void UseDirectStorage(bool in_useDS) = 0; //-------------------------------------------- // are we between BeginFrame and EndFrame? useful for debugging //-------------------------------------------- - bool GetWithinFrame() const; + virtual bool GetWithinFrame() const = 0; //-------------------------------------------- // GPU time for resolving feedback buffers last frame // use this to time-limit gpu feedback processing // to determine per-resolve time, divide this time by the number of QueueFeedback() calls during the frame //-------------------------------------------- - float GetGpuTime() const; + virtual float GetGpuTime() const = 0; //-------------------------------------------- // for visualization //-------------------------------------------- - void SetVisualizationMode(UINT in_mode); + virtual void SetVisualizationMode(UINT in_mode) = 0; - float GetGpuStreamingTime() const; - float GetCpuProcessFeedbackTime(); // approx. cpu time spent processing feedback last frame. expected usage is to average over many frames + virtual float GetGpuStreamingTime() const = 0; + virtual float GetCpuProcessFeedbackTime() = 0; // approx. cpu time spent processing feedback last frame. expected usage is to average over many frames - UINT GetTotalNumUploads() const; - UINT GetTotalNumEvictions() const; - float GetTotalTileCopyLatency() const; -private: - TileUpdateManager(const TileUpdateManager&) = delete; - TileUpdateManager(TileUpdateManager&&) = delete; - TileUpdateManager& operator=(const TileUpdateManager&) = delete; - TileUpdateManager& operator=(TileUpdateManager&&) = delete; + virtual UINT GetTotalNumUploads() const = 0; + virtual UINT GetTotalNumEvictions() const = 0; + virtual float GetTotalTileCopyLatency() const = 0; }; diff --git a/TileUpdateManager/StreamingHeap.cpp b/TileUpdateManager/StreamingHeap.cpp index 0732a9a..dde68bc 100644 --- a/TileUpdateManager/StreamingHeap.cpp +++ b/TileUpdateManager/StreamingHeap.cpp @@ -28,6 +28,14 @@ #include "StreamingHeap.h" +//----------------------------------------------------------------------------- +// call destructor on derived object +//----------------------------------------------------------------------------- +void Streaming::Heap::Destroy() +{ + delete this; +} + //----------------------------------------------------------------------------- // create an "atlas" texture that covers the entire heap //----------------------------------------------------------------------------- @@ -218,12 +226,3 @@ ID3D12Resource* Streaming::Heap::ComputeCoordFromTileIndex(D3D12_TILED_RESOURCE_ return pAtlas->ComputeCoordFromTileIndex(out_coord, in_index); } - -//----------------------------------------------------------------------------- -// public API implementation -//----------------------------------------------------------------------------- -#include "SamplerFeedbackStreaming.h" -UINT StreamingHeap::GetNumTilesAllocated() -{ - return GetAllocator().GetAllocated(); -} diff --git a/TileUpdateManager/StreamingHeap.h b/TileUpdateManager/StreamingHeap.h index 24d961f..18e00b2 100644 --- a/TileUpdateManager/StreamingHeap.h +++ b/TileUpdateManager/StreamingHeap.h @@ -28,6 +28,7 @@ #include "Streaming.h" // for ComPtr #include "SimpleAllocator.h" +#include "SamplerFeedbackStreaming.h" //================================================== // Streaming Heap wraps the D3D heap, Allocator, and Atlas @@ -60,9 +61,18 @@ namespace Streaming // Heap to hold tiles for 1 or more resources // contains atlases for the format(s) of the resources - class Heap + class Heap : public ::StreamingHeap { public: + //----------------------------------------------------------------- + // external APIs + //----------------------------------------------------------------- + virtual void Destroy() override; + virtual UINT GetNumTilesAllocated() const override { return m_heapAllocator.GetAllocated(); } + //----------------------------------------------------------------- + // end external APIs + //----------------------------------------------------------------- + Heap(ID3D12CommandQueue* in_pQueue, UINT in_maxNumTilesHeap); virtual ~Heap(); @@ -72,6 +82,7 @@ namespace Streaming ID3D12Resource* ComputeCoordFromTileIndex(D3D12_TILED_RESOURCE_COORDINATE& out_coord, UINT in_index, const DXGI_FORMAT in_format); ID3D12Heap* GetHeap() const { return m_tileHeap.Get(); } SimpleAllocator& GetAllocator() { return m_heapAllocator; } + private: SimpleAllocator m_heapAllocator; diff --git a/TileUpdateManager/StreamingResource.cpp b/TileUpdateManager/StreamingResource.cpp index 65e7f79..c2ec90c 100644 --- a/TileUpdateManager/StreamingResource.cpp +++ b/TileUpdateManager/StreamingResource.cpp @@ -24,28 +24,32 @@ // //********************************************************* -// Implementation of the few methods required for the ::StreamingResource public (external) interface +// Implementation of the few methods required for the ::StreamingResourceBase public (external) interface #include "pch.h" -#include "SamplerFeedbackStreaming.h" +#include "StreamingResourceBase.h" #include "TileUpdateManagerSR.h" //----------------------------------------------------------------------------- +// public interface to destroy object //----------------------------------------------------------------------------- -StreamingResource::~StreamingResource() {} +void Streaming::StreamingResourceBase::Destroy() +{ + delete this; +} //----------------------------------------------------------------------------- // create views of resources used directly by the application //----------------------------------------------------------------------------- -void StreamingResource::CreateFeedbackView(ID3D12Device* in_pDevice, D3D12_CPU_DESCRIPTOR_HANDLE in_descriptorHandle) +void Streaming::StreamingResourceBase::CreateFeedbackView(ID3D12Device* in_pDevice, D3D12_CPU_DESCRIPTOR_HANDLE in_descriptorHandle) { in_pDevice->CopyDescriptorsSimple(1, in_descriptorHandle, m_resources->GetClearUavHeap()->GetCPUDescriptorHandleForHeapStart(), D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); } -void StreamingResource::CreateStreamingView(ID3D12Device* in_pDevice, D3D12_CPU_DESCRIPTOR_HANDLE in_descriptorHandle) +void Streaming::StreamingResourceBase::CreateStreamingView(ID3D12Device* in_pDevice, D3D12_CPU_DESCRIPTOR_HANDLE in_descriptorHandle) { D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc{}; srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D; @@ -58,7 +62,7 @@ void StreamingResource::CreateStreamingView(ID3D12Device* in_pDevice, D3D12_CPU_ //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- -ID3D12Resource* StreamingResource::GetMinMipMap() const +ID3D12Resource* Streaming::StreamingResourceBase::GetMinMipMap() const { return m_pTileUpdateManager->GetResidencyMap().GetResource(); } @@ -66,12 +70,12 @@ ID3D12Resource* StreamingResource::GetMinMipMap() const //----------------------------------------------------------------------------- // shader reading min-mip-map buffer will want its dimensions //----------------------------------------------------------------------------- -UINT StreamingResource::GetMinMipMapWidth() const +UINT Streaming::StreamingResourceBase::GetMinMipMapWidth() const { return GetNumTilesWidth(); } -UINT StreamingResource::GetMinMipMapHeight() const +UINT Streaming::StreamingResourceBase::GetMinMipMapHeight() const { return GetNumTilesHeight(); } @@ -80,7 +84,7 @@ UINT StreamingResource::GetMinMipMapHeight() const // IMPORTANT: all min mip maps are stored in a single buffer. offset into the buffer. // this saves a massive amount of GPU memory, since each min mip map is much smaller than 64KB //----------------------------------------------------------------------------- -UINT StreamingResource::GetMinMipMapOffset() const +UINT Streaming::StreamingResourceBase::GetMinMipMapOffset() const { return m_residencyMapOffsetBase; } @@ -88,7 +92,7 @@ UINT StreamingResource::GetMinMipMapOffset() const //----------------------------------------------------------------------------- // // check if the packed mips are loaded. application likely will not want to use this texture before they have loaded //----------------------------------------------------------------------------- -bool StreamingResource::GetPackedMipsResident() const +bool Streaming::StreamingResourceBase::GetPackedMipsResident() const { return (PackedMipStatus::RESIDENT == m_packedMipStatus) || (PackedMipStatus::NEEDS_TRANSITION == m_packedMipStatus); } @@ -97,30 +101,14 @@ bool StreamingResource::GetPackedMipsResident() const // if an object isn't visible, set all refcounts to 0 // this will schedule all tiles to be evicted //----------------------------------------------------------------------------- -void StreamingResource::QueueEviction() +void Streaming::StreamingResourceBase::QueueEviction() { m_setZeroRefCounts = true; } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- -UINT StreamingResource::GetNumTilesVirtual() const +UINT Streaming::StreamingResourceBase::GetNumTilesVirtual() const { return m_resources->GetNumTilesVirtual(); } - -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -ID3D12Resource* StreamingResource::GetTiledResource() const -{ - return m_resources->GetTiledResource(); -} - -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -#if RESOLVE_TO_TEXTURE -ID3D12Resource* StreamingResource::GetResolvedFeedback() -{ - return m_resources->GetResolvedFeedback(); -} -#endif diff --git a/TileUpdateManager/StreamingResourceBase.h b/TileUpdateManager/StreamingResourceBase.h index 353e5ef..e23fed2 100644 --- a/TileUpdateManager/StreamingResourceBase.h +++ b/TileUpdateManager/StreamingResourceBase.h @@ -35,6 +35,7 @@ Base class for StreamingResource #include #include +#include "SamplerFeedbackStreaming.h" #include "InternalResources.h" namespace Streaming @@ -49,10 +50,26 @@ namespace Streaming // unpacked mips are dynamically loaded/evicted, preserving a min-mip-map // packed mips are not evicted from the heap (as little as 1 tile for a 16k x 16k texture) //============================================================================= - class StreamingResourceBase + class StreamingResourceBase : public ::StreamingResource { public: - // share heap & other resources with another TileUpdateManager + //----------------------------------------------------------------- + // external APIs + //----------------------------------------------------------------- + virtual void Destroy() override; + virtual void CreateFeedbackView(ID3D12Device* in_pDevice, D3D12_CPU_DESCRIPTOR_HANDLE in_descriptor) override; + virtual void CreateStreamingView(ID3D12Device* in_pDevice, D3D12_CPU_DESCRIPTOR_HANDLE in_descriptor) override; + virtual UINT GetMinMipMapWidth() const override; + virtual UINT GetMinMipMapHeight() const override; + virtual UINT GetMinMipMapOffset() const override; + virtual bool GetPackedMipsResident() const override; + virtual void QueueEviction() override; + virtual ID3D12Resource* GetMinMipMap() const override; + virtual UINT GetNumTilesVirtual() const override; + //----------------------------------------------------------------- + // end external APIs + //----------------------------------------------------------------- + StreamingResourceBase( // method that will fill a tile-worth of bits, for streaming const std::wstring& in_filename, @@ -97,11 +114,11 @@ namespace Streaming void ReadbackFeedback(ID3D12GraphicsCommandList* out_pCmdList); // TUM needs this for barrier before/after copy - ID3D12Resource* GetResolvedFeedback() { return m_resources->GetResolvedFeedback(); } + ID3D12Resource* GetResolvedFeedback() const override { return m_resources->GetResolvedFeedback(); } #endif // TUM needs this for barrier on packed mips - ID3D12Resource* GetTiledResource() const { return m_resources->GetTiledResource(); } + ID3D12Resource* GetTiledResource() const override { return m_resources->GetTiledResource(); } //------------------------------------- // end called by TUM::EndFrame() @@ -142,11 +159,8 @@ namespace Streaming std::unique_ptr m_pTextureFileInfo; std::unique_ptr m_resources; std::unique_ptr m_pFileHandle; - const std::wstring m_filename; Streaming::Heap* m_pHeap{ nullptr }; - void SetResidencyChanged(); - // packed mip status enum class PackedMipStatus : UINT32 { @@ -158,6 +172,14 @@ namespace Streaming }; PackedMipStatus m_packedMipStatus{ PackedMipStatus::UNINITIALIZED }; + UINT m_packedMipsUncompressedSize{ 0 }; + + // bytes for packed mips + std::vector m_packedMips; + std::vector m_packedMipHeapIndices; + + Streaming::TileUpdateManagerSR* m_pTileUpdateManager; + //================================================== // TileMappingState keeps reference counts and heap indices for resources in a min-mip-map //================================================== @@ -223,9 +245,19 @@ namespace Streaming }; TileMappingState m_tileMappingState; - Streaming::TileUpdateManagerSR* m_pTileUpdateManager; + void SetResidencyChanged(); - std::vector m_packedMipHeapIndices; + //-------------------------------------------------------- + // for public interface + //-------------------------------------------------------- + UINT m_residencyMapOffsetBase{ 0 }; + + // used by QueueEviction() + std::atomic m_setZeroRefCounts{ false }; + + private: + + const std::wstring m_filename; // do not immediately decmap: // need to withhold until in-flight command buffers have completed @@ -253,11 +285,6 @@ namespace Streaming //-------------------------------------------------------- // for public interface //-------------------------------------------------------- - UINT m_residencyMapOffsetBase{ 0 }; - - // used by QueueEviction() - std::atomic m_setZeroRefCounts{ false }; - // minimum mip level referred to by this tile // this tile "holds references" to this mip level and all mips greater than this value // with a 16kx16k limit, DX will never see 255 mip levels. but, we want a byte so we can modify cache-coherently @@ -269,10 +296,6 @@ namespace Streaming UINT8 m_maxMip; std::vector> m_minMipMap; // local version of min mip map, rectified in UpdateMinMipMap() - // bytes for packed mips - std::vector m_packedMips; - UINT m_packedMipsUncompressedSize{ 0 }; - private: // non-packed mip copy complete notification std::atomic m_tileResidencyChanged{ false }; diff --git a/TileUpdateManager/TileUpdateManager.cpp b/TileUpdateManager/TileUpdateManager.cpp index 6657900..484f183 100644 --- a/TileUpdateManager/TileUpdateManager.cpp +++ b/TileUpdateManager/TileUpdateManager.cpp @@ -24,39 +24,45 @@ // //********************************************************* -// Implementation of the few methods required for the ::TileUpdateManager public (external) interface +//============================================================================= +// Implementation of the ::TileUpdateManager public (external) interface +//============================================================================= #include "pch.h" -#include "SamplerFeedbackStreaming.h" - +#include "TileUpdateManagerBase.h" +#include "TileUpdateManagerSR.h" +#include "StreamingResourceBase.h" #include "DataUploader.h" -#include "InternalResources.h" // RESOLVE_TO_TEXTURE defined here. - -#define COPY_RESIDENCY_MAPS 0 +#include "StreamingHeap.h" -//============================================================================= +//-------------------------------------------- // instantiate streaming library -//============================================================================= -TileUpdateManager::TileUpdateManager( +//-------------------------------------------- +TileUpdateManager* TileUpdateManager::Create( // query resource for tiling properties. use its device to create internal resources ID3D12Device8* in_pDevice, // the Direct command queue the application is using to render, which TUM monitors to know when new feedback is ready ID3D12CommandQueue* in_pDirectCommandQueue, - const TileUpdateManagerDesc& in_desc) : TileUpdateManagerBase(in_pDevice, in_pDirectCommandQueue, in_desc) + const TileUpdateManagerDesc& in_desc) { - UseDirectStorage(in_desc.m_useDirectStorage); + auto p = new Streaming::TileUpdateManagerBase(in_pDevice, in_pDirectCommandQueue, in_desc); + p->UseDirectStorage(in_desc.m_useDirectStorage); + return p; } -TileUpdateManager::~TileUpdateManager() {} +void Streaming::TileUpdateManagerBase::Destroy() +{ + delete this; +} //-------------------------------------------- // Create a heap used by 1 or more StreamingResources // parameter is number of 64KB tiles to manage //-------------------------------------------- -StreamingHeap* TileUpdateManager::CreateStreamingHeap(UINT in_maxNumTilesHeap) +StreamingHeap* Streaming::TileUpdateManagerBase::CreateStreamingHeap(UINT in_maxNumTilesHeap) { auto pStreamingHeap = new Streaming::Heap(m_pDataUploader->GetMappingQueue(), in_maxNumTilesHeap); return (StreamingHeap*)pStreamingHeap; @@ -65,13 +71,13 @@ StreamingHeap* TileUpdateManager::CreateStreamingHeap(UINT in_maxNumTilesHeap) //-------------------------------------------- // Create StreamingResources using a common TileUpdateManager //-------------------------------------------- -StreamingResource* TileUpdateManager::CreateStreamingResource(const std::wstring& in_filename, StreamingHeap* in_pHeap) +StreamingResource* Streaming::TileUpdateManagerBase::CreateStreamingResource(const std::wstring& in_filename, StreamingHeap* in_pHeap) { // if threads are running, stop them. they have state that depends on knowing the # of StreamingResources Finish(); Streaming::FileHandle* pFileHandle = m_pDataUploader->OpenFile(in_filename); - auto pRsrc = new Streaming::StreamingResourceBase(in_filename, pFileHandle, (Streaming::TileUpdateManagerSR*)this, in_pHeap); + auto pRsrc = new Streaming::StreamingResourceBase(in_filename, pFileHandle, (Streaming::TileUpdateManagerSR*)this, (Streaming::Heap*)in_pHeap); m_streamingResources.push_back(pRsrc); m_numStreamingResourcesChanged = true; @@ -80,19 +86,11 @@ StreamingResource* TileUpdateManager::CreateStreamingResource(const std::wstring return (StreamingResource*)pRsrc; } -//----------------------------------------------------------------------------- -// when debugging, useful to know if between TUM:Begin/End Frame -//----------------------------------------------------------------------------- -bool TileUpdateManager::GetWithinFrame() const -{ - return TileUpdateManagerBase::GetWithinFrame(); -} - //----------------------------------------------------------------------------- // set which file streaming system to use // will reset even if previous setting was the same. so? //----------------------------------------------------------------------------- -void TileUpdateManager::UseDirectStorage(bool in_useDS) +void Streaming::TileUpdateManagerBase::UseDirectStorage(bool in_useDS) { Finish(); auto streamerType = Streaming::DataUploader::StreamerType::Reference; @@ -114,7 +112,7 @@ void TileUpdateManager::UseDirectStorage(bool in_useDS) //----------------------------------------------------------------------------- // note to self to create Clear() and Resolve() commands during EndFrame() //----------------------------------------------------------------------------- -void TileUpdateManager::QueueFeedback(StreamingResource* in_pResource, D3D12_GPU_DESCRIPTOR_HANDLE in_gpuDescriptor) +void Streaming::TileUpdateManagerBase::QueueFeedback(StreamingResource* in_pResource, D3D12_GPU_DESCRIPTOR_HANDLE in_gpuDescriptor) { auto pResource = (Streaming::StreamingResourceBase*)in_pResource; @@ -143,7 +141,7 @@ void TileUpdateManager::QueueFeedback(StreamingResource* in_pResource, D3D12_GPU // returns (approximate) cpu time for processing feedback in the previous frame // since processing happens asynchronously, this time should be averaged //----------------------------------------------------------------------------- -float TileUpdateManager::GetCpuProcessFeedbackTime() +float Streaming::TileUpdateManagerBase::GetCpuProcessFeedbackTime() { return m_processFeedbackFrameTime; } @@ -151,14 +149,14 @@ float TileUpdateManager::GetCpuProcessFeedbackTime() //----------------------------------------------------------------------------- // performance and visualization //----------------------------------------------------------------------------- -float TileUpdateManager::GetGpuStreamingTime() const { return m_pDataUploader->GetGpuStreamingTime(); } -float TileUpdateManager::GetTotalTileCopyLatency() const { return m_pDataUploader->GetApproximateTileCopyLatency(); } +float Streaming::TileUpdateManagerBase::GetGpuStreamingTime() const { return m_pDataUploader->GetGpuStreamingTime(); } +float Streaming::TileUpdateManagerBase::GetTotalTileCopyLatency() const { return m_pDataUploader->GetApproximateTileCopyLatency(); } // the total time the GPU spent resolving feedback during the previous frame -float TileUpdateManager::GetGpuTime() const { return m_gpuTimerResolve.GetTimes()[m_renderFrameIndex].first; } -UINT TileUpdateManager::GetTotalNumUploads() const { return m_pDataUploader->GetTotalNumUploads(); } -UINT TileUpdateManager::GetTotalNumEvictions() const { return m_pDataUploader->GetTotalNumEvictions(); } -void TileUpdateManager::SetVisualizationMode(UINT in_mode) +float Streaming::TileUpdateManagerBase::GetGpuTime() const { return m_gpuTimerResolve.GetTimes()[m_renderFrameIndex].first; } +UINT Streaming::TileUpdateManagerBase::GetTotalNumUploads() const { return m_pDataUploader->GetTotalNumUploads(); } +UINT Streaming::TileUpdateManagerBase::GetTotalNumEvictions() const { return m_pDataUploader->GetTotalNumEvictions(); } +void Streaming::TileUpdateManagerBase::SetVisualizationMode(UINT in_mode) { ASSERT(!GetWithinFrame()); Finish(); @@ -174,7 +172,7 @@ void TileUpdateManager::SetVisualizationMode(UINT in_mode) // Call this method once for each TileUpdateManager that shares heap/upload buffers // expected to be called once per frame, before anything is drawn. //----------------------------------------------------------------------------- -void TileUpdateManager::BeginFrame(ID3D12DescriptorHeap* in_pDescriptorHeap, +void Streaming::TileUpdateManagerBase::BeginFrame(ID3D12DescriptorHeap* in_pDescriptorHeap, D3D12_CPU_DESCRIPTOR_HANDLE in_minmipmapDescriptorHandle) { ASSERT(!GetWithinFrame()); @@ -220,7 +218,7 @@ void TileUpdateManager::BeginFrame(ID3D12DescriptorHeap* in_pDescriptorHeap, // Call this method once corresponding to BeginFrame() // expected to be called once per frame, after everything was drawn. //----------------------------------------------------------------------------- -TileUpdateManager::CommandLists TileUpdateManager::EndFrame() +TileUpdateManager::CommandLists Streaming::TileUpdateManagerBase::EndFrame() { ASSERT(GetWithinFrame()); // NOTE: we are "within frame" until the end of EndFrame() diff --git a/TileUpdateManager/TileUpdateManagerBase.cpp b/TileUpdateManager/TileUpdateManagerBase.cpp index 4685b4b..ff85c6d 100644 --- a/TileUpdateManager/TileUpdateManagerBase.cpp +++ b/TileUpdateManager/TileUpdateManagerBase.cpp @@ -26,14 +26,12 @@ #include "pch.h" -#include "SamplerFeedbackStreaming.h" // required for TileUpdateManagerDesc +#include "TileUpdateManagerBase.h" #include "DataUploader.h" #include "StreamingResourceBase.h" #include "XeTexture.h" #include "StreamingHeap.h" -#define COPY_RESIDENCY_MAPS 0 - //============================================================================= // constructor for streaming library base class //============================================================================= @@ -359,3 +357,4 @@ void Streaming::TileUpdateManagerBase::CreateMinMipMapView(D3D12_CPU_DESCRIPTOR_ m_device->CreateShaderResourceView(m_residencyMap.GetResource(), &srvDesc, in_descriptorHandle); #endif } + diff --git a/TileUpdateManager/TileUpdateManagerBase.h b/TileUpdateManager/TileUpdateManagerBase.h index d0fe865..e9e301e 100644 --- a/TileUpdateManager/TileUpdateManagerBase.h +++ b/TileUpdateManager/TileUpdateManagerBase.h @@ -48,17 +48,19 @@ Draw loop: #include #include +#include "SamplerFeedbackStreaming.h" #include "D3D12GpuTimer.h" #include "Timer.h" #include "Streaming.h" // for ComPtr +#define COPY_RESIDENCY_MAPS 0 + //============================================================================= // manager for tiled resources // contains shared objects, especially the heap // performs asynchronous copies // use this to create the StreamingResource //============================================================================= -struct TileUpdateManagerDesc; // defined in SamplerFeedbackStreaming.h namespace Streaming { class StreamingResourceBase; @@ -66,13 +68,30 @@ namespace Streaming class Heap; struct UpdateList; - class TileUpdateManagerBase + class TileUpdateManagerBase : public ::TileUpdateManager { public: - //-------------------------------------------- - // are we between BeginFrame and EndFrame? useful for debugging - //-------------------------------------------- - bool GetWithinFrame() const { return m_withinFrame; } + //----------------------------------------------------------------- + // external APIs + //----------------------------------------------------------------- + virtual void Destroy() override; + virtual StreamingHeap* CreateStreamingHeap(UINT in_maxNumTilesHeap) override; + virtual StreamingResource* CreateStreamingResource(const std::wstring& in_filename, StreamingHeap* in_pHeap) override; + virtual void BeginFrame(ID3D12DescriptorHeap* in_pDescriptorHeap, D3D12_CPU_DESCRIPTOR_HANDLE in_minmipmapDescriptorHandle) override; + virtual void QueueFeedback(StreamingResource* in_pResource, D3D12_GPU_DESCRIPTOR_HANDLE in_gpuDescriptor) override; + virtual CommandLists EndFrame() override; + virtual void UseDirectStorage(bool in_useDS) override; + virtual bool GetWithinFrame() const override { return m_withinFrame; } + virtual float GetGpuTime() const override; + virtual void SetVisualizationMode(UINT in_mode) override; + virtual float GetGpuStreamingTime() const override; + virtual float GetCpuProcessFeedbackTime() override; + virtual UINT GetTotalNumUploads() const override; + virtual UINT GetTotalNumEvictions() const override; + virtual float GetTotalTileCopyLatency() const override; + //----------------------------------------------------------------- + // end external APIs + //----------------------------------------------------------------- //-------------------------------------------- // force all outstanding commands to complete. @@ -80,7 +99,6 @@ namespace Streaming //-------------------------------------------- void Finish(); - protected: TileUpdateManagerBase( // query resource for tiling properties. use its device to create internal resources ID3D12Device8* in_pDevice, @@ -93,15 +111,35 @@ namespace Streaming virtual ~TileUpdateManagerBase(); protected: + ComPtr m_device; + + const UINT m_numSwapBuffers; + + // track the objects that this resource created + // used to discover which resources have been updated within a frame + std::vector m_streamingResources; + UINT64 m_frameFenceValue{ 0 }; + + std::unique_ptr m_pDataUploader; + + // each StreamingResource writes current uploaded tile state to min mip map, separate data for each frame + // internally, use a single buffer containing all the residency maps + Streaming::UploadBuffer m_residencyMap; + + Streaming::SynchronizationFlag m_residencyChangedFlag; + + // allocating/deallocating StreamingResources requires reallocation of shared resources + bool m_numStreamingResourcesChanged{ false }; + + std::atomic m_packedMipTransition{ false }; // flag that we need to transition a resource due to packed mips + + private: // direct queue is used to monitor progress of render frames so we know when feedback buffers are ready to be used ComPtr m_directCommandQueue; // the frame fence is used to optimize readback of feedback by StreamingResource // only read back the feedback after the frame that writes to it has completed ComPtr m_frameFence; - UINT64 m_frameFenceValue{ 0 }; - - const UINT m_numSwapBuffers; struct FeedbackReadback { @@ -110,25 +148,11 @@ namespace Streaming }; std::vector m_feedbackReadbacks; - std::unique_ptr m_pDataUploader; - // packed-mip transition barriers Streaming::BarrierList m_packedMipTransitionBarriers; - // track the objects that this resource created - // used to discover which resources have been updated within a frame - std::vector m_streamingResources; - - // each StreamingResource writes current uploaded tile state to min mip map, separate data for each frame - // internally, use a single buffer containing all the residency maps - Streaming::UploadBuffer m_residencyMap; ComPtr m_residencyMapLocal; // GPU copy of residency state - // allocating/deallocating StreamingResources requires reallocation of shared resources - bool m_numStreamingResourcesChanged{ false }; - - std::atomic m_packedMipTransition{ false }; // flag that we need to transition a resource due to packed mips - Streaming::SynchronizationFlag m_processFeedbackFlag; std::atomic m_havePackedMipsToLoad{ false }; @@ -175,9 +199,6 @@ namespace Streaming }; std::vector m_commandLists; - ComPtr m_device; - Streaming::SynchronizationFlag m_residencyChangedFlag; - private: const UINT m_maxTileMappingUpdatesPerApiCall; std::atomic m_threadsRunning{ false }; diff --git a/TileUpdateManager/XeTexture.cpp b/TileUpdateManager/XeTexture.cpp index 620dd85..fbc5eff 100644 --- a/TileUpdateManager/XeTexture.cpp +++ b/TileUpdateManager/XeTexture.cpp @@ -45,19 +45,21 @@ DDS_HEADER_DXT10 structure Streaming::XeTexture::XeTexture(const std::wstring& in_fileName) { std::ifstream inFile(in_fileName.c_str(), std::ios::binary); + if (inFile.fail()) { Error(in_fileName + L" File doesn't exist (?)"); } + inFile.read((char*)&m_fileHeader, sizeof(m_fileHeader)); - if (!inFile.good()) { Error(in_fileName + L"Unexpected Error"); } + if (!inFile.good()) { Error(in_fileName + L" Unexpected Error reading header"); } if (m_fileHeader.m_magic != XetFileHeader::GetMagic()) { Error(in_fileName + L" Not a valid XET file"); } if (m_fileHeader.m_version != XetFileHeader::GetVersion()) { Error(in_fileName + L" Incorrect XET version"); } m_subresourceInfo.resize(m_fileHeader.m_ddsHeader.mipMapCount); inFile.read((char*)m_subresourceInfo.data(), m_subresourceInfo.size() * sizeof(m_subresourceInfo[0])); - if (!inFile.good()) { Error(in_fileName + L"Unexpected Error"); } + if (!inFile.good()) { Error(in_fileName + L" Unexpected Error reading subresource info"); } m_tileOffsets.resize(m_fileHeader.m_mipInfo.m_numTilesForStandardMips + 1); // plus 1 for the packed mips offset & size inFile.read((char*)m_tileOffsets.data(), m_tileOffsets.size() * sizeof(m_tileOffsets[0])); - if (!inFile.good()) { Error(in_fileName + L"Unexpected Error"); } + if (!inFile.good()) { Error(in_fileName + L" Unexpected Error reading packed mip info"); } } //----------------------------------------------------------------------------- diff --git a/props/expanse.props b/props/expanse.props index 3f7cd4a..20aa312 100644 --- a/props/expanse.props +++ b/props/expanse.props @@ -7,7 +7,7 @@ - $(ProjectDir)../imgui;$(ProjectDir)../include;$(ProjectDir)../DirectXTK12;$(ProjectDir)../TileUpdateManager + $(SolutionDir)imgui;$(SolutionDir)include;$(SolutionDir)DirectXTK12;$(SolutionDir)TileUpdateManager $(OutDir);%(AdditionalLibraryDirectories) diff --git a/src/Scene.cpp b/src/Scene.cpp index b15ad55..43041cc 100644 --- a/src/Scene.cpp +++ b/src/Scene.cpp @@ -234,8 +234,10 @@ Scene::~Scene() for (auto h : m_sharedHeaps) { - delete h; + h->Destroy(); } + + m_pTileUpdateManager->Destroy(); } //----------------------------------------------------------------------------- @@ -662,7 +664,7 @@ void Scene::StartStreamingLibrary() tumDesc.m_addAliasingBarriers = m_args.m_addAliasingBarriers; tumDesc.m_useDirectStorage = m_args.m_useDirectStorage; - m_pTileUpdateManager = std::make_unique(m_device.Get(), m_commandQueue.Get(), tumDesc); + m_pTileUpdateManager = TileUpdateManager::Create(m_device.Get(), m_commandQueue.Get(), tumDesc); // create 1 or more heaps to contain our StreamingResources for (UINT i = 0; i < m_args.m_numHeaps; i++) @@ -801,13 +803,13 @@ void Scene::LoadSpheres() if ((nullptr == m_pSky) && (m_args.m_skyTexture.size())) // only 1 sky { auto tf = m_args.m_mediaDir + L"\\\\" + m_args.m_skyTexture; - m_pSky = new SceneObjects::Sky(tf, m_pTileUpdateManager.get(), pHeap, m_device.Get(), m_assetUploader, m_args.m_sampleCount, descCPU); + m_pSky = new SceneObjects::Sky(tf, m_pTileUpdateManager, pHeap, m_device.Get(), m_assetUploader, m_args.m_sampleCount, descCPU); o = m_pSky; } else if (nullptr == m_pTerrainSceneObject) { - m_pTerrainSceneObject = new SceneObjects::Terrain(m_args.m_terrainTexture, m_pTileUpdateManager.get(), pHeap, m_device.Get(), m_args.m_sampleCount, descCPU, m_args, m_assetUploader); + m_pTerrainSceneObject = new SceneObjects::Terrain(m_args.m_terrainTexture, m_pTileUpdateManager, pHeap, m_device.Get(), m_args.m_sampleCount, descCPU, m_args, m_assetUploader); m_terrainObjectIndex = objectIndex; o = m_pTerrainSceneObject; } @@ -818,12 +820,12 @@ void Scene::LoadSpheres() if (nullptr == m_pEarth) { sphereProperties.m_mirrorU = false; - o = new SceneObjects::Planet(textureFilename, m_pTileUpdateManager.get(), pHeap, m_device.Get(), m_assetUploader, m_args.m_sampleCount, descCPU, sphereProperties); + o = new SceneObjects::Planet(textureFilename, m_pTileUpdateManager, pHeap, m_device.Get(), m_assetUploader, m_args.m_sampleCount, descCPU, sphereProperties); m_pEarth = o; } else { - o = new SceneObjects::Planet(textureFilename, m_pTileUpdateManager.get(), pHeap, m_device.Get(), descCPU, m_pEarth); + o = new SceneObjects::Planet(textureFilename, m_pTileUpdateManager, pHeap, m_device.Get(), descCPU, m_pEarth); } o->GetModelMatrix() = SetSphereMatrix(); } @@ -841,12 +843,12 @@ void Scene::LoadSpheres() if (nullptr == m_pFirstSphere) { sphereProperties.m_mirrorU = true; - o = new SceneObjects::Planet(textureFilename, m_pTileUpdateManager.get(), pHeap, m_device.Get(), m_assetUploader, m_args.m_sampleCount, descCPU, sphereProperties); + o = new SceneObjects::Planet(textureFilename, m_pTileUpdateManager, pHeap, m_device.Get(), m_assetUploader, m_args.m_sampleCount, descCPU, sphereProperties); m_pFirstSphere = o; } else { - o = new SceneObjects::Planet(textureFilename, m_pTileUpdateManager.get(), pHeap, m_device.Get(), descCPU, m_pFirstSphere); + o = new SceneObjects::Planet(textureFilename, m_pTileUpdateManager, pHeap, m_device.Get(), descCPU, m_pFirstSphere); } o->GetModelMatrix() = SetSphereMatrix(); } @@ -895,9 +897,6 @@ void Scene::LoadSpheres() m_numSpheresLoaded--; } } - - // check the non-streaming uploader to see if anything needs to be uploaded or any memory can be freed - m_assetUploader.WaitForUploads(m_commandQueue.Get(), m_commandList.Get()); } //----------------------------------------------------------------------------- @@ -1666,6 +1665,9 @@ bool Scene::Draw() m_commandAllocators[m_frameIndex]->Reset(); m_commandList->Reset((ID3D12CommandAllocator*)m_commandAllocators[m_frameIndex].Get(), nullptr); + // check the non-streaming uploader to see if anything needs to be uploaded or any memory can be freed + m_assetUploader.WaitForUploads(m_commandQueue.Get(), m_commandList.Get()); + m_renderThreadTimes.Set(RenderEvents::FrameBegin); // get the total time the GPU spent processing feedback during the previous frame (by calling before TUM::BeginFrame) diff --git a/src/Scene.h b/src/Scene.h index c9a5af5..a76d559 100644 --- a/src/Scene.h +++ b/src/Scene.h @@ -196,7 +196,7 @@ class Scene ComPtr m_samplerHeap; void SetSampler(); - std::unique_ptr m_pTileUpdateManager; + struct TileUpdateManager* m_pTileUpdateManager{ nullptr }; UINT DetermineMaxNumFeedbackResolves(); void DrawObjects(); // draw all the objects diff --git a/src/SceneObject.cpp b/src/SceneObject.cpp index ef986aa..7ef6802 100644 --- a/src/SceneObject.cpp +++ b/src/SceneObject.cpp @@ -161,7 +161,7 @@ SceneObjects::BaseObject::BaseObject( // The tile update manager queries the streaming texture for its tile dimensions // The feedback resource will be allocated with a mip region size matching the tile size - m_pStreamingResource = std::unique_ptr(in_pTileUpdateManager->CreateStreamingResource(in_filename, in_pStreamingHeap)); + m_pStreamingResource = in_pTileUpdateManager->CreateStreamingResource(in_filename, in_pStreamingHeap); // sampler feedback view CD3DX12_CPU_DESCRIPTOR_HANDLE feedbackHandle(in_srvBaseCPU, (UINT)Descriptors::HeapOffsetFeedback, m_srvUavCbvDescriptorSize); diff --git a/src/SceneObject.h b/src/SceneObject.h index 4737bfb..e8fdce6 100644 --- a/src/SceneObject.h +++ b/src/SceneObject.h @@ -66,7 +66,10 @@ namespace SceneObjects class BaseObject { public: - virtual ~BaseObject() {} + virtual ~BaseObject() + { + m_pStreamingResource->Destroy(); + } bool GetPackedMipsPresent() const { return m_pStreamingResource->GetPackedMipsResident(); } @@ -83,7 +86,7 @@ namespace SceneObjects ID3D12Resource* GetResolvedFeedback() const { return m_pStreamingResource->GetResolvedFeedback(); } #endif - StreamingResource* GetStreamingResource() const { return m_pStreamingResource.get(); } + StreamingResource* GetStreamingResource() const { return m_pStreamingResource; } void CopyGeometry(const BaseObject* in_pObjectForSharedHeap); @@ -123,7 +126,7 @@ namespace SceneObjects const DirectX::XMMATRIX& in_projection, const DirectX::XMMATRIX& in_view); - std::unique_ptr m_pStreamingResource; + StreamingResource* m_pStreamingResource{ nullptr }; void CreatePipelineState( const wchar_t* in_ps, const wchar_t* in_psFB, const wchar_t* in_vs,