diff options
| author | Egor Yusov <egor.yusov@gmail.com> | 2018-10-02 06:17:55 +0000 |
|---|---|---|
| committer | Egor Yusov <egor.yusov@gmail.com> | 2018-10-02 06:17:55 +0000 |
| commit | 9286fdcd21cfa7cdbc70a42d6bd1ea2d7b907e5e (patch) | |
| tree | 38179e316803efc4731aa2513c39ac5a5a0d0384 /Graphics/GraphicsEngineD3D12 | |
| parent | Removed ForceRelease parameter of IDeviceContext::FinishFrame() (diff) | |
| download | DiligentCore-9286fdcd21cfa7cdbc70a42d6bd1ea2d7b907e5e.tar.gz DiligentCore-9286fdcd21cfa7cdbc70a42d6bd1ea2d7b907e5e.zip | |
Reworked D3D12DynamicHeap to use release queues
Diffstat (limited to 'Graphics/GraphicsEngineD3D12')
6 files changed, 108 insertions, 89 deletions
diff --git a/Graphics/GraphicsEngineD3D12/include/D3D12DynamicHeap.h b/Graphics/GraphicsEngineD3D12/include/D3D12DynamicHeap.h index 74bba43f..a7d54d27 100644 --- a/Graphics/GraphicsEngineD3D12/include/D3D12DynamicHeap.h +++ b/Graphics/GraphicsEngineD3D12/include/D3D12DynamicHeap.h @@ -26,10 +26,13 @@ #include <mutex> #include <map> #include <deque> +#include <atomic> namespace Diligent { +class RenderDeviceD3D12Impl; + struct D3D12DynamicAllocation { D3D12DynamicAllocation()noexcept{} @@ -110,10 +113,10 @@ private: class D3D12DynamicMemoryManager { public: - D3D12DynamicMemoryManager(IMemoryAllocator& Allocator, - ID3D12Device* pd3d12Device, - Uint32 NumPagesToReserve, - Uint64 PageSize); + D3D12DynamicMemoryManager(IMemoryAllocator& Allocator, + RenderDeviceD3D12Impl& DeviceD3D12Impl, + Uint32 NumPagesToReserve, + Uint64 PageSize); ~D3D12DynamicMemoryManager(); D3D12DynamicMemoryManager (const D3D12DynamicMemoryManager&) = delete; @@ -121,54 +124,26 @@ public: D3D12DynamicMemoryManager& operator= (const D3D12DynamicMemoryManager&) = delete; D3D12DynamicMemoryManager& operator= ( D3D12DynamicMemoryManager&&) = delete; - void DiscardPages(std::vector<D3D12DynamicPage>& Pages, Uint64 FenceValue) - { - std::lock_guard<std::mutex> Lock(m_StalePagesMtx); - for(auto& Page : Pages) - m_StalePages.emplace_back(FenceValue, std::move(Page)); - } - - void ReleaseStalePages(Uint64 LastCompletedFenceValue) - { - std::lock_guard<std::mutex> AvailablePagesLock(m_AvailablePagesMtx); - std::lock_guard<std::mutex> StalePagesLock(m_StalePagesMtx); - while (!m_StalePages.empty()) - { - auto& FirstPage = m_StalePages.front(); - if (FirstPage.FenceValue <= LastCompletedFenceValue) - { - auto PageSize = FirstPage.Page.GetSize(); - m_AvailablePages.emplace(PageSize, std::move(FirstPage.Page)); - m_StalePages.pop_front(); - } - else - break; - } - } + void ReleasePages(std::vector<D3D12DynamicPage>& Pages, Uint64 QueueMask); - void Destroy(Uint64 LastCompletedFenceValue); + void Destroy(); D3D12DynamicPage AllocatePage(Uint64 SizeInBytes); +#ifdef DEVELOPMENT + int32_t GetAllocatedPageCounter()const{return m_AllocatedPageCounter;} +#endif + private: - CComPtr<ID3D12Device> m_pd3d12Device; + RenderDeviceD3D12Impl& m_DeviceD3D12Impl; std::mutex m_AvailablePagesMtx; using AvailablePagesMapElemType = std::pair<Uint64, D3D12DynamicPage>; std::multimap<Uint64, D3D12DynamicPage, std::less<Uint64>, STDAllocatorRawMem<AvailablePagesMapElemType> > m_AvailablePages; - std::mutex m_StalePagesMtx; - struct StalePageInfo - { - StalePageInfo(Uint64 _FenceValue, D3D12DynamicPage&& _Page) : - FenceValue(_FenceValue), - Page (std::move(_Page)) - {} - - Uint64 FenceValue; - D3D12DynamicPage Page; - }; - std::deque<StalePageInfo, STDAllocatorRawMem<StalePageInfo> > m_StalePages; +#ifdef DEVELOPMENT + std::atomic_int32_t m_AllocatedPageCounter = 0; +#endif }; @@ -189,7 +164,7 @@ public: ~D3D12DynamicHeap(); D3D12DynamicAllocation Allocate(Uint64 SizeInBytes, Uint64 Alignment, Uint64 DvpCtxFrameNumber); - void FinishFrame(Uint64 FenceValue); + void ReleaseAllocatedPages(Uint64 QueueMask); static constexpr Uint64 InvalidOffset = static_cast<Uint64>(-1); diff --git a/Graphics/GraphicsEngineD3D12/include/DeviceContextD3D12Impl.h b/Graphics/GraphicsEngineD3D12/include/DeviceContextD3D12Impl.h index fa9f4d2c..a6dafd81 100644 --- a/Graphics/GraphicsEngineD3D12/include/DeviceContextD3D12Impl.h +++ b/Graphics/GraphicsEngineD3D12/include/DeviceContextD3D12Impl.h @@ -30,6 +30,7 @@ #include "DeviceContextD3D12.h" #include "DeviceContextBase.h" +#include "DeviceContextNextGenBase.h" #include "GenerateMips.h" #include "BufferD3D12Impl.h" #include "TextureViewD3D12Impl.h" @@ -40,16 +41,17 @@ namespace Diligent { /// Implementation of the Diligent::IDeviceContext interface -class DeviceContextD3D12Impl final : public DeviceContextBase<IDeviceContextD3D12, BufferD3D12Impl, TextureViewD3D12Impl, PipelineStateD3D12Impl> +class DeviceContextD3D12Impl final : public DeviceContextNextGenBase< DeviceContextBase<IDeviceContextD3D12, BufferD3D12Impl, TextureViewD3D12Impl, PipelineStateD3D12Impl> > { public: - using TDeviceContextBase = DeviceContextBase<IDeviceContextD3D12, BufferD3D12Impl, TextureViewD3D12Impl, PipelineStateD3D12Impl>; + using TDeviceContextBase = DeviceContextNextGenBase< DeviceContextBase<IDeviceContextD3D12, BufferD3D12Impl, TextureViewD3D12Impl, PipelineStateD3D12Impl> >; DeviceContextD3D12Impl(IReferenceCounters* pRefCounters, class RenderDeviceD3D12Impl* pDevice, bool bIsDeferred, const EngineD3D12Attribs& Attribs, - Uint32 ContextId); + Uint32 ContextId, + Uint32 CommandQueueId); ~DeviceContextD3D12Impl(); virtual void QueryInterface( const Diligent::INTERFACE_ID &IID, IObject **ppInterface )override final; @@ -188,13 +190,8 @@ private: return m_pCurrCmdCtx; } size_t m_NumCommandsInCurCtx = 0; - const Uint32 m_NumCommandsToFlush = 192; CommandContext* m_pCurrCmdCtx = nullptr; - // The fence value that was signalled last time a command list was submitted for execution - Uint64 m_LastSubmittedFenceValue = 0; - Atomics::AtomicInt64 m_ContextFrameNumber = 0; - CComPtr<ID3D12Resource> m_CommittedD3D12IndexBuffer; VALUE_TYPE m_CommittedIBFormat = VT_UNDEFINED; Uint32 m_CommittedD3D12IndexDataStartOffset = 0; @@ -215,7 +212,6 @@ private: class ShaderResourceCacheD3D12 *m_pCommittedResourceCache = nullptr; FixedBlockMemoryAllocator m_CmdListAllocator; - const Uint32 m_ContextId; std::vector<std::pair<Uint64, RefCntAutoPtr<IFence> > > m_PendingFences; diff --git a/Graphics/GraphicsEngineD3D12/src/D3D12DynamicHeap.cpp b/Graphics/GraphicsEngineD3D12/src/D3D12DynamicHeap.cpp index 98b6a945..6103e9b1 100644 --- a/Graphics/GraphicsEngineD3D12/src/D3D12DynamicHeap.cpp +++ b/Graphics/GraphicsEngineD3D12/src/D3D12DynamicHeap.cpp @@ -70,17 +70,16 @@ D3D12DynamicPage::D3D12DynamicPage(ID3D12Device* pd3d12Device, Uint64 Size) LOG_INFO_MESSAGE("Created dynamic memory page. Size: ", FormatMemorySize(Size,2), "; GPU virtual address 0x", std::hex, m_GPUVirtualAddress); } -D3D12DynamicMemoryManager::D3D12DynamicMemoryManager(IMemoryAllocator& Allocator, - ID3D12Device* pd3d12Device, - Uint32 NumPagesToReserve, - Uint64 PageSize) : - m_pd3d12Device(pd3d12Device), - m_AvailablePages(STD_ALLOCATOR_RAW_MEM(AvailablePagesMapElemType, Allocator, "Allocator for multimap<AvailablePagesMapElemType>")), - m_StalePages(STD_ALLOCATOR_RAW_MEM(StalePageInfo, Allocator, "Allocator for deque<StalePageInfo>")) +D3D12DynamicMemoryManager::D3D12DynamicMemoryManager(IMemoryAllocator& Allocator, + RenderDeviceD3D12Impl& DeviceD3D12Impl, + Uint32 NumPagesToReserve, + Uint64 PageSize) : + m_DeviceD3D12Impl(DeviceD3D12Impl), + m_AvailablePages(STD_ALLOCATOR_RAW_MEM(AvailablePagesMapElemType, Allocator, "Allocator for multimap<AvailablePagesMapElemType>")) { for(Uint32 i=0; i < NumPagesToReserve; ++i) { - D3D12DynamicPage Page(m_pd3d12Device, PageSize); + D3D12DynamicPage Page(m_DeviceD3D12Impl.GetD3D12Device(), PageSize); auto Size = Page.GetSize(); m_AvailablePages.emplace(Size, std::move(Page)); } @@ -89,6 +88,9 @@ D3D12DynamicMemoryManager::D3D12DynamicMemoryManager(IMemoryAllocator& Allocato D3D12DynamicPage D3D12DynamicMemoryManager::AllocatePage(Uint64 SizeInBytes) { std::lock_guard<std::mutex> AvailablePagesLock(m_AvailablePagesMtx); +#ifdef DEVELOPMENT + ++m_AllocatedPageCounter; +#endif auto PageIt = m_AvailablePages.lower_bound(SizeInBytes); // Returns an iterator pointing to the first element that is not less than key if (PageIt != m_AvailablePages.end()) { @@ -99,14 +101,56 @@ D3D12DynamicPage D3D12DynamicMemoryManager::AllocatePage(Uint64 SizeInBytes) } else { - return D3D12DynamicPage{m_pd3d12Device, SizeInBytes}; + return D3D12DynamicPage{m_DeviceD3D12Impl.GetD3D12Device(), SizeInBytes}; + } +} + +void D3D12DynamicMemoryManager::ReleasePages(std::vector<D3D12DynamicPage>& Pages, Uint64 QueueMask) +{ + struct StalePage + { + D3D12DynamicPage Page; + D3D12DynamicMemoryManager* Mgr; + + StalePage(D3D12DynamicPage&& _Page, D3D12DynamicMemoryManager* _Mgr)noexcept : + Page (std::move(_Page)), + Mgr (_Mgr) + { + } + + StalePage (const StalePage&) = delete; + StalePage& operator= (const StalePage&) = delete; + StalePage& operator= ( StalePage&&) = delete; + + StalePage(StalePage&& rhs)noexcept : + Page (std::move(rhs.Page)), + Mgr (rhs.Mgr) + { + rhs.Mgr = nullptr; + } + + ~StalePage() + { + if (Mgr != nullptr) + { + std::lock_guard<std::mutex> Lock(Mgr->m_AvailablePagesMtx); +#ifdef DEVELOPMENT + --Mgr->m_AllocatedPageCounter; +#endif + auto PageSize = Page.GetSize(); + Mgr->m_AvailablePages.emplace(PageSize, std::move(Page)); + } + } + }; + for(auto& Page : Pages) + { + m_DeviceD3D12Impl.SafeReleaseDeviceObject(StalePage{std::move(Page), this}, QueueMask); } } -void D3D12DynamicMemoryManager::Destroy(Uint64 LastCompletedFenceValue) +void D3D12DynamicMemoryManager::Destroy() { - ReleaseStalePages(LastCompletedFenceValue); - DEV_CHECK_ERR(m_StalePages.empty(), "Not all stale pages have been released and are still in use. The device must be idled before calling Destroy()"); + DEV_CHECK_ERR(m_AllocatedPageCounter == 0, m_AllocatedPageCounter, " page(s) have not been returned to the manager."); Uint64 TotalAllocatedSize = 0; for(const auto& Page : m_AvailablePages) TotalAllocatedSize += Page.second.GetSize(); @@ -114,13 +158,13 @@ void D3D12DynamicMemoryManager::Destroy(Uint64 LastCompletedFenceValue) LOG_INFO_MESSAGE("Dynamic memory manager usage stats:\n" " Total allocated memory: ", FormatMemorySize(TotalAllocatedSize, 2)); - m_StalePages.clear(); m_AvailablePages.clear(); } D3D12DynamicMemoryManager::~D3D12DynamicMemoryManager() { - VERIFY(m_AvailablePages.empty() && m_StalePages.empty(), "Not all pages are destroyed. Dynamic memory manager must be explicitly destroyed with Destroy() method"); + DEV_CHECK_ERR(m_AllocatedPageCounter == 0, m_AllocatedPageCounter, " page(s) have not been released. If there are outstanding references to the pages in release queues, the app will crash when the page is returned to the manager."); + VERIFY(m_AvailablePages.empty(), "Not all pages are destroyed. Dynamic memory manager must be explicitly destroyed with Destroy() method"); } @@ -185,9 +229,9 @@ D3D12DynamicAllocation D3D12DynamicHeap::Allocate(Uint64 SizeInBytes, Uint64 Ali return D3D12DynamicAllocation{}; } -void D3D12DynamicHeap::FinishFrame(Uint64 FenceValue) +void D3D12DynamicHeap::ReleaseAllocatedPages(Uint64 QueueMask) { - m_DynamicMemMgr.DiscardPages(m_AllocatedPages, FenceValue); + m_DynamicMemMgr.ReleasePages(m_AllocatedPages, QueueMask); m_AllocatedPages.clear(); m_CurrOffset = InvalidOffset; diff --git a/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp index 494c1df9..04bfa5eb 100644 --- a/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp +++ b/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp @@ -55,17 +55,24 @@ namespace Diligent RenderDeviceD3D12Impl* pDeviceD3D12Impl, bool bIsDeferred, const EngineD3D12Attribs& Attribs, - Uint32 ContextId) : - TDeviceContextBase(pRefCounters, pDeviceD3D12Impl, bIsDeferred), + Uint32 ContextId, + Uint32 CommandQueueId) : + TDeviceContextBase + { + pRefCounters, + pDeviceD3D12Impl, + ContextId, + CommandQueueId, + bIsDeferred ? std::numeric_limits<decltype(m_NumCommandsToFlush)>::max() : Attribs.NumCommandsToFlushCmdList, + bIsDeferred + }, m_DynamicHeap(pDeviceD3D12Impl->GetDynamicMemoryManager(), GetDynamicHeapName(bIsDeferred, ContextId), Attribs.DynamicHeapPageSize), m_NumCommandsInCurCtx(0), - m_NumCommandsToFlush(bIsDeferred ? std::numeric_limits<decltype(m_NumCommandsToFlush)>::max() : Attribs.NumCommandsToFlushCmdList), m_pCurrCmdCtx(pDeviceD3D12Impl->AllocateCommandContext()), m_CommittedIBFormat(VT_UNDEFINED), m_CommittedD3D12IndexDataStartOffset(0), m_MipsGenerator(pDeviceD3D12Impl->GetD3D12Device()), - m_CmdListAllocator(GetRawAllocator(), sizeof(CommandListD3D12Impl), 64 ), - m_ContextId(ContextId) + m_CmdListAllocator(GetRawAllocator(), sizeof(CommandListD3D12Impl), 64 ) { auto *pd3d12Device = pDeviceD3D12Impl->GetD3D12Device(); @@ -503,7 +510,7 @@ namespace Diligent if (m_NumCommandsInCurCtx != 0) { m_pCurrCmdCtx->FlushResourceBarriers(); - m_LastSubmittedFenceValue = pDeviceD3D12Impl->CloseAndExecuteCommandContext(m_pCurrCmdCtx, true, &m_PendingFences); + auto FenceValue = pDeviceD3D12Impl->CloseAndExecuteCommandContext(m_pCurrCmdCtx, true, &m_PendingFences); m_PendingFences.clear(); } else @@ -530,9 +537,9 @@ namespace Diligent void DeviceContextD3D12Impl::FinishFrame() { - //Uint64 FenceValue = ForceRelease ? std::numeric_limits<Uint64>::max() : m_pDevice.RawPtr<RenderDeviceD3D12Impl>()->GetCompletedFenceValue(); - m_DynamicHeap.FinishFrame(m_LastSubmittedFenceValue); - Atomics::AtomicIncrement(m_ContextFrameNumber); + VERIFY_EXPR(m_bIsDeferred || m_SubmittedBuffersCmdQueueMask == (Uint64{1}<<m_CommandQueueId)); + m_DynamicHeap.ReleaseAllocatedPages(m_SubmittedBuffersCmdQueueMask); + EndFrame(); } void DeviceContextD3D12Impl::SetVertexBuffers( Uint32 StartSlot, Uint32 NumBuffersSet, IBuffer** ppBuffers, Uint32* pOffsets, Uint32 Flags ) @@ -1022,8 +1029,9 @@ namespace Diligent CommandContext* pCmdContext = nullptr; RefCntAutoPtr<DeviceContextD3D12Impl> pDeferredCtx; pCmdListD3D12->Close(pCmdContext, pDeferredCtx); - pDeferredCtx->m_LastSubmittedFenceValue = - m_pDevice.RawPtr<RenderDeviceD3D12Impl>()->CloseAndExecuteCommandContext(pCmdContext, true, nullptr); + auto FenceValue = m_pDevice.RawPtr<RenderDeviceD3D12Impl>()->CloseAndExecuteCommandContext(pCmdContext, true, nullptr); + // Set the bit in the deferred context cmd queue mask corresponding to cmd queue of this context + pDeferredCtx->m_SubmittedBuffersCmdQueueMask |= Uint64{1} << m_CommandQueueId; } void DeviceContextD3D12Impl::SignalFence(IFence* pFence, Uint64 Value) diff --git a/Graphics/GraphicsEngineD3D12/src/RenderDeviceD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/RenderDeviceD3D12Impl.cpp index 792ad326..993f1ac2 100644 --- a/Graphics/GraphicsEngineD3D12/src/RenderDeviceD3D12Impl.cpp +++ b/Graphics/GraphicsEngineD3D12/src/RenderDeviceD3D12Impl.cpp @@ -83,7 +83,7 @@ RenderDeviceD3D12Impl :: RenderDeviceD3D12Impl(IReferenceCounters* pRef }, m_ContextPool(STD_ALLOCATOR_RAW_MEM(ContextPoolElemType, GetRawAllocator(), "Allocator for vector<unique_ptr<CommandContext>>")), m_AvailableContexts(STD_ALLOCATOR_RAW_MEM(CommandContext*, GetRawAllocator(), "Allocator for vector<CommandContext*>")), - m_DynamicMemoryManager(GetRawAllocator(), m_pd3d12Device, CreationAttribs.NumDynamicHeapPagesToReserve, CreationAttribs.DynamicHeapPageSize) + m_DynamicMemoryManager(GetRawAllocator(), *this, CreationAttribs.NumDynamicHeapPagesToReserve, CreationAttribs.DynamicHeapPageSize) { m_DeviceCaps.DevType = DeviceType::D3D12; m_DeviceCaps.MajorVersion = 12; @@ -104,8 +104,8 @@ RenderDeviceD3D12Impl::~RenderDeviceD3D12Impl() // release queues FinishFrame(true); - // TODO: Rework - m_DynamicMemoryManager.Destroy(GetCompletedFenceValue(0)); + DEV_CHECK_ERR(m_DynamicMemoryManager.GetAllocatedPageCounter() == 0, "All allocated dynamic pages must have been returned to the manager at this point."); + m_DynamicMemoryManager.Destroy(); m_ContextPool.clear(); DestroyCommandQueues(); @@ -204,6 +204,7 @@ void RenderDeviceD3D12Impl::IdleGPU(bool ReleaseStaleObjects) void RenderDeviceD3D12Impl::FinishFrame(bool ReleaseAllResources) { + // TODO: remove { if (auto pImmediateCtx = m_wpImmediateContext.Lock()) { @@ -234,11 +235,6 @@ void RenderDeviceD3D12Impl::FinishFrame(bool ReleaseAllResources) PurgeReleaseQueues(ReleaseAllResources); - // Dynamic memory is used to update resource contents as well as to allocate - // space for dynamic resources. - // Initial resource data is uploaded using temporary one-time upload buffers - m_DynamicMemoryManager.ReleaseStalePages(CompletedFenceValue); - for(Uint32 CPUHeap=0; CPUHeap < _countof(m_CPUDescriptorHeaps); ++CPUHeap) { // This is OK if other thread disposes descriptor heap allocation at this time diff --git a/Graphics/GraphicsEngineD3D12/src/RenderDeviceFactoryD3D12.cpp b/Graphics/GraphicsEngineD3D12/src/RenderDeviceFactoryD3D12.cpp index 4dc46ff0..c79679fc 100644 --- a/Graphics/GraphicsEngineD3D12/src/RenderDeviceFactoryD3D12.cpp +++ b/Graphics/GraphicsEngineD3D12/src/RenderDeviceFactoryD3D12.cpp @@ -309,7 +309,7 @@ void EngineFactoryD3D12Impl::AttachToD3D12Device(void* pd3d1 RenderDeviceD3D12Impl *pRenderDeviceD3D12( NEW_RC_OBJ(RawMemAllocator, "RenderDeviceD3D12Impl instance", RenderDeviceD3D12Impl)(RawMemAllocator, EngineAttribs, d3d12Device, CommandQueueCount, ppCommandQueues, NumDeferredContexts ) ); pRenderDeviceD3D12->QueryInterface(IID_RenderDevice, reinterpret_cast<IObject**>(ppDevice) ); - RefCntAutoPtr<DeviceContextD3D12Impl> pImmediateCtxD3D12( NEW_RC_OBJ(RawMemAllocator, "DeviceContextD3D12Impl instance", DeviceContextD3D12Impl)(pRenderDeviceD3D12, false, EngineAttribs, 0) ); + RefCntAutoPtr<DeviceContextD3D12Impl> pImmediateCtxD3D12( NEW_RC_OBJ(RawMemAllocator, "DeviceContextD3D12Impl instance", DeviceContextD3D12Impl)(pRenderDeviceD3D12, false, EngineAttribs, 0, 0) ); // We must call AddRef() (implicitly through QueryInterface()) because pRenderDeviceD3D12 will // keep a weak reference to the context pImmediateCtxD3D12->QueryInterface(IID_DeviceContext, reinterpret_cast<IObject**>(ppContexts) ); @@ -317,7 +317,7 @@ void EngineFactoryD3D12Impl::AttachToD3D12Device(void* pd3d1 for (Uint32 DeferredCtx = 0; DeferredCtx < NumDeferredContexts; ++DeferredCtx) { - RefCntAutoPtr<DeviceContextD3D12Impl> pDeferredCtxD3D12( NEW_RC_OBJ(RawMemAllocator, "DeviceContextD3D12Impl instance", DeviceContextD3D12Impl)(pRenderDeviceD3D12, true, EngineAttribs, 1+DeferredCtx) ); + RefCntAutoPtr<DeviceContextD3D12Impl> pDeferredCtxD3D12( NEW_RC_OBJ(RawMemAllocator, "DeviceContextD3D12Impl instance", DeviceContextD3D12Impl)(pRenderDeviceD3D12, true, EngineAttribs, 1+DeferredCtx, 0) ); // We must call AddRef() (implicitly through QueryInterface()) because pRenderDeviceD3D12 will // keep a weak reference to the context pDeferredCtxD3D12->QueryInterface(IID_DeviceContext, reinterpret_cast<IObject**>(ppContexts + 1 + DeferredCtx) ); |
