From 109a75aac22463802f03dfc6588951ed0b04892a Mon Sep 17 00:00:00 2001 From: Egor Yusov Date: Sat, 20 May 2017 14:00:37 -0700 Subject: Merge from dev branch --- .../GraphicsEngineD3D12/include/BufferD3D12Impl.h | 3 +- .../include/BufferViewD3D12Impl.h | 3 +- .../GraphicsEngineD3D12/include/CommandContext.h | 242 +-------------------- .../include/CommandListD3D12Impl.h | 2 +- .../include/CommandListManager.h | 12 +- .../include/D3D12ResourceBase.h | 2 +- .../include/D3D12TypeConversions.h | 2 +- .../include/D3D12TypeDefinitions.h | 2 +- Graphics/GraphicsEngineD3D12/include/D3D12Utils.h | 2 +- .../GraphicsEngineD3D12/include/DescriptorHeap.h | 220 ++++++++++++++++--- .../include/DeviceContextD3D12Impl.h | 2 +- .../include/DynamicUploadHeap.h | 4 +- .../GraphicsEngineD3D12/include/GenerateMips.h | 2 +- .../include/PipelineStateD3D12Impl.h | 2 +- .../include/RenderDeviceD3D12Impl.h | 87 ++++++-- .../GraphicsEngineD3D12/include/RootSignature.h | 9 +- .../GraphicsEngineD3D12/include/SamplerD3D12Impl.h | 2 +- .../GraphicsEngineD3D12/include/ShaderD3D12Impl.h | 2 +- .../include/ShaderResourceBindingD3D12Impl.h | 2 +- .../include/ShaderResourceCacheD3D12.h | 69 +++--- .../include/ShaderResourceLayoutD3D12.h | 82 ++++--- .../include/ShaderResourcesD3D12.h | 2 +- .../include/SwapChainD3D12Impl.h | 2 +- .../GraphicsEngineD3D12/include/TextureD3D12Impl.h | 4 +- .../include/TextureViewD3D12Impl.h | 5 +- Graphics/GraphicsEngineD3D12/include/pch.h | 2 +- .../GraphicsEngineD3D12/interface/BufferD3D12.h | 2 +- .../interface/BufferViewD3D12.h | 2 +- .../interface/PipelineStateD3D12.h | 2 +- .../interface/RenderDeviceD3D12.h | 2 +- .../interface/RenderDeviceFactoryD3D12.h | 2 +- .../GraphicsEngineD3D12/interface/SamplerD3D12.h | 2 +- .../GraphicsEngineD3D12/interface/ShaderD3D12.h | 2 +- .../interface/ShaderResourceBindingD3D12.h | 2 +- .../GraphicsEngineD3D12/interface/SwapChainD3D12.h | 2 +- .../GraphicsEngineD3D12/interface/TextureD3D12.h | 2 +- .../interface/TextureViewD3D12.h | 2 +- .../GraphicsEngineD3D12/src/BufferD3D12Impl.cpp | 4 +- .../src/BufferViewD3D12Impl.cpp | 2 +- .../GraphicsEngineD3D12/src/CommandContext.cpp | 147 +------------ .../GraphicsEngineD3D12/src/CommandListManager.cpp | 27 ++- .../GraphicsEngineD3D12/src/D3D12ResourceBase.cpp | 2 +- .../src/D3D12TypeConversions.cpp | 2 +- Graphics/GraphicsEngineD3D12/src/D3D12Utils.cpp | 2 +- Graphics/GraphicsEngineD3D12/src/DLLMain.cpp | 2 +- .../GraphicsEngineD3D12/src/DescriptorHeap.cpp | 122 +++++++++-- .../src/DeviceContextD3D12Impl.cpp | 4 +- .../GraphicsEngineD3D12/src/DynamicUploadHeap.cpp | 31 ++- Graphics/GraphicsEngineD3D12/src/GenerateMips.cpp | 2 +- .../src/PipelineStateD3D12Impl.cpp | 5 +- .../src/RenderDeviceD3D12Impl.cpp | 195 +++++++++-------- .../src/RenderDeviceFactoryD3D12.cpp | 4 +- Graphics/GraphicsEngineD3D12/src/RootSignature.cpp | 70 ++++-- .../GraphicsEngineD3D12/src/SamplerD3D12Impl.cpp | 2 +- .../GraphicsEngineD3D12/src/ShaderD3D12Impl.cpp | 3 +- .../src/ShaderResourceBindingD3D12Impl.cpp | 3 +- .../src/ShaderResourceCacheD3D12.cpp | 9 +- .../src/ShaderResourceLayoutD3D12.cpp | 134 ++++++++---- .../src/ShaderResourcesD3D12.cpp | 2 +- .../GraphicsEngineD3D12/src/SwapChainD3D12Impl.cpp | 2 +- .../GraphicsEngineD3D12/src/TextureD3D12Impl.cpp | 2 +- .../src/TextureViewD3D12Impl.cpp | 2 +- Graphics/GraphicsEngineD3D12/src/pch.cpp | 2 +- 63 files changed, 826 insertions(+), 746 deletions(-) (limited to 'Graphics/GraphicsEngineD3D12') diff --git a/Graphics/GraphicsEngineD3D12/include/BufferD3D12Impl.h b/Graphics/GraphicsEngineD3D12/include/BufferD3D12Impl.h index 9ee4e25d..289bf152 100644 --- a/Graphics/GraphicsEngineD3D12/include/BufferD3D12Impl.h +++ b/Graphics/GraphicsEngineD3D12/include/BufferD3D12Impl.h @@ -1,4 +1,4 @@ -/* Copyright 2015-2016 Egor Yusov +/* Copyright 2015-2017 Egor Yusov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -108,6 +108,7 @@ private: #endif friend class DeviceContextD3D12Impl; + // Array of dynamic allocations for every device context std::vector > m_DynamicData; }; diff --git a/Graphics/GraphicsEngineD3D12/include/BufferViewD3D12Impl.h b/Graphics/GraphicsEngineD3D12/include/BufferViewD3D12Impl.h index f5aff0ab..0c102f41 100644 --- a/Graphics/GraphicsEngineD3D12/include/BufferViewD3D12Impl.h +++ b/Graphics/GraphicsEngineD3D12/include/BufferViewD3D12Impl.h @@ -1,4 +1,4 @@ -/* Copyright 2015-2016 Egor Yusov +/* Copyright 2015-2017 Egor Yusov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -53,6 +53,7 @@ public: virtual D3D12_CPU_DESCRIPTOR_HANDLE GetCPUDescriptorHandle()override{return m_DescriptorHandle.GetCpuHandle();} protected: + // Allocation in a CPU-only descriptor heap DescriptorHeapAllocation m_DescriptorHandle; }; diff --git a/Graphics/GraphicsEngineD3D12/include/CommandContext.h b/Graphics/GraphicsEngineD3D12/include/CommandContext.h index 755e8076..41be0796 100644 --- a/Graphics/GraphicsEngineD3D12/include/CommandContext.h +++ b/Graphics/GraphicsEngineD3D12/include/CommandContext.h @@ -1,4 +1,4 @@ -/* Copyright 2015-2016 Egor Yusov +/* Copyright 2015-2017 Egor Yusov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,20 +21,6 @@ * of the possibility of such damages. */ -// -// Copyright (c) Microsoft. All rights reserved. -// This code is licensed under the MIT License (MIT). -// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF -// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY -// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR -// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. -// -// Developed by Minigraph -// -// Author: James Stanard -// -// Adapted to Diligent Engine: Egor Yusov -// #pragma once @@ -77,7 +63,7 @@ public: CommandContext( IMemoryAllocator &MemAllocator, class CommandListManager& CmdListManager, GPUDescriptorHeap GPUDescriptorHeaps[], - Uint32 DynamicDescriptorAllocationChunkSize[]); + const Uint32 DynamicDescriptorAllocationChunkSize[]); ~CommandContext(void); @@ -97,25 +83,11 @@ public: m_pCommandList->CopyResource(pDstRes, pSrcRes); } - //void CopyBuffer( GpuResource& Dest, GpuResource& Src ); - //void CopyBufferRegion( GpuResource& Dest, size_t DestOffset, GpuResource& Src, size_t SrcOffset, size_t NumBytes ); - //void CopySubresource(GpuResource& Dest, UINT DestSubIndex, GpuResource& Src, UINT SrcSubIndex); - //void CopyCounter(GpuResource& Dest, size_t DestOffset, StructuredBuffer& Src); - //void ResetCounter(StructuredBuffer& Buf, uint32_t Value = 0); - - //static void InitializeTextureArraySlice(GpuResource& Dest, UINT SliceIndex, GpuResource& Src); - void TransitionResource(ITextureD3D12 *pTexture, D3D12_RESOURCE_STATES NewState, bool FlushImmediate = false); void TransitionResource(IBufferD3D12 *pBuffer, D3D12_RESOURCE_STATES NewState, bool FlushImmediate = false); //void BeginResourceTransition(GpuResource& Resource, D3D12_RESOURCE_STATES NewState, bool FlushImmediate = false); void FlushResourceBarriers(); - //void InsertTimeStamp( ID3D12QueryHeap* pQueryHeap, uint32_t QueryIdx ); - //void ResolveTimeStamps( ID3D12Resource* pReadbackHeap, ID3D12QueryHeap* pQueryHeap, uint32_t NumQueries ); - //void PIXBeginEvent(const wchar_t* label); - //void PIXEndEvent(void); - //void PIXSetMarker(const wchar_t* label); - struct ShaderDescriptorHeaps { ID3D12DescriptorHeap* pSrvCbvUavHeap; @@ -144,7 +116,7 @@ public: void SetID(const Char* ID) { m_ID = ID; } ID3D12GraphicsCommandList *GetCommandList(){return m_pCommandList;} - void DiscardUsedDescriptorHeaps(Uint64 FrameNumber); + void DiscardDynamicDescriptors(Uint64 FrameNumber); DescriptorHeapAllocation AllocateDynamicGPUVisibleDescriptor( D3D12_DESCRIPTOR_HEAP_TYPE Type, UINT Count = 1 ); void InsertUAVBarrier(D3D12ResourceBase& Resource, IDeviceObject &Object, bool FlushImmediate = false); @@ -153,9 +125,6 @@ protected: void TransitionResource(D3D12ResourceBase& Resource, IDeviceObject &Object, D3D12_RESOURCE_STATES NewState, bool FlushImmediate); void InsertAliasBarrier(D3D12ResourceBase& Before, D3D12ResourceBase& After, IDeviceObject &BeforeObj, IDeviceObject &AfterObj, bool FlushImmediate = false); - //void FinishTimeStampQueryBatch(); - //void BindDescriptorHeaps( void ); - CComPtr m_pCommandList; CComPtr m_pCurrentAllocator; @@ -274,18 +243,11 @@ public: m_pCommandList->SetGraphicsRootConstantBufferView(RootIndex, CBV); } - //void SetDynamicConstantBufferView( UINT RootIndex, size_t BufferSize, const void* BufferData ); - //void SetBufferSRV( UINT RootIndex, const GpuBuffer& SRV ); - //void SetBufferUAV( UINT RootIndex, const GpuBuffer& UAV ); void SetDescriptorTable( UINT RootIndex, D3D12_GPU_DESCRIPTOR_HANDLE FirstHandle ) { m_pCommandList->SetGraphicsRootDescriptorTable( RootIndex, FirstHandle ); } - - //void SetDynamicDescriptor( UINT RootIndex, UINT Offset, D3D12_CPU_DESCRIPTOR_HANDLE Handle ); - //void SetDynamicDescriptors( UINT RootIndex, UINT Offset, UINT Count, const D3D12_CPU_DESCRIPTOR_HANDLE Handles[] ); - void SetIndexBuffer( const D3D12_INDEX_BUFFER_VIEW& IBView ) { m_pCommandList->IASetIndexBuffer(&IBView); @@ -296,10 +258,6 @@ public: m_pCommandList->IASetVertexBuffers(StartSlot, Count, VBViews); } - //void SetDynamicVB( UINT Slot, size_t NumVertices, size_t VertexStride, const void* VBData ); - //void SetDynamicIB( size_t IndexCount, const uint16_t* IBData ); - //void SetDynamicSRV(UINT RootIndex, size_t BufferSize, const void* BufferData); - void Draw(UINT VertexCountPerInstance, UINT InstanceCount, UINT StartVertexLocation, UINT StartInstanceLocation) { @@ -373,19 +331,11 @@ public: m_pCommandList->SetComputeRootConstantBufferView(RootIndex, CBV); } - //void SetDynamicConstantBufferView( UINT RootIndex, size_t BufferSize, const void* BufferData ); - //void SetDynamicSRV( UINT RootIndex, size_t BufferSize, const void* BufferData ); - //void SetBufferSRV( UINT RootIndex, const GpuBuffer& SRV ); - //void SetBufferUAV( UINT RootIndex, const GpuBuffer& UAV ); void SetDescriptorTable( UINT RootIndex, D3D12_GPU_DESCRIPTOR_HANDLE FirstHandle ) { m_pCommandList->SetComputeRootDescriptorTable( RootIndex, FirstHandle ); } - - //void SetDynamicDescriptor( UINT RootIndex, UINT Offset, D3D12_CPU_DESCRIPTOR_HANDLE Handle ); - //void SetDynamicDescriptors( UINT RootIndex, UINT Offset, UINT Count, const D3D12_CPU_DESCRIPTOR_HANDLE Handles[] ); - void Dispatch( size_t GroupCountX = 1, size_t GroupCountY = 1, size_t GroupCountZ = 1 ) { FlushResourceBarriers(); @@ -403,112 +353,6 @@ inline ComputeContext& CommandContext::AsComputeContext() return static_cast(*this); } -#if 0 - -inline void GraphicsContext::SetDynamicConstantBufferView( UINT RootIndex, size_t BufferSize, const void* BufferData ) -{ - ASSERT(BufferData != nullptr && Math::IsAligned(BufferData, 16)); - DynAlloc cb = m_CpuLinearAllocator.Allocate(BufferSize); - //SIMDMemCopy(cb.DataPtr, BufferData, Math::AlignUp(BufferSize, 16) >> 4); - memcpy(cb.DataPtr, BufferData, BufferSize); - m_pCommandList->SetGraphicsRootConstantBufferView(RootIndex, cb.GpuAddress); -} - -inline void ComputeContext::SetDynamicConstantBufferView( UINT RootIndex, size_t BufferSize, const void* BufferData ) -{ - ASSERT(BufferData != nullptr && Math::IsAligned(BufferData, 16)); - DynAlloc cb = m_CpuLinearAllocator.Allocate(BufferSize); - //SIMDMemCopy(cb.DataPtr, BufferData, Math::AlignUp(BufferSize, 16) >> 4); - memcpy(cb.DataPtr, BufferData, BufferSize); - m_pCommandList->SetComputeRootConstantBufferView(RootIndex, cb.GpuAddress); -} - -inline void GraphicsContext::SetDynamicVB( UINT Slot, size_t NumVertices, size_t VertexStride, const void* VertexData ) -{ - ASSERT(VertexData != nullptr && Math::IsAligned(VertexData, 16)); - - size_t BufferSize = Math::AlignUp(NumVertices * VertexStride, 16); - DynAlloc vb = m_CpuLinearAllocator.Allocate(BufferSize); - - SIMDMemCopy(vb.DataPtr, VertexData, BufferSize >> 4); - - D3D12_VERTEX_BUFFER_VIEW VBView; - VBView.BufferLocation = vb.GpuAddress; - VBView.SizeInBytes = (UINT)BufferSize; - VBView.StrideInBytes = (UINT)VertexStride; - - m_pCommandList->IASetVertexBuffers(Slot, 1, &VBView); -} - -inline void GraphicsContext::SetDynamicIB( size_t IndexCount, const uint16_t* IndexData ) -{ - ASSERT(IndexData != nullptr && Math::IsAligned(IndexData, 16)); - - size_t BufferSize = Math::AlignUp(IndexCount * sizeof(uint16_t), 16); - DynAlloc ib = m_CpuLinearAllocator.Allocate(BufferSize); - - SIMDMemCopy(ib.DataPtr, IndexData, BufferSize >> 4); - - D3D12_INDEX_BUFFER_VIEW IBView; - IBView.BufferLocation = ib.GpuAddress; - IBView.SizeInBytes = (UINT)(IndexCount * sizeof(uint16_t)); - IBView.Format = DXGI_FORMAT_R16_UINT; - - m_pCommandList->IASetIndexBuffer(&IBView); -} - -inline void GraphicsContext::SetDynamicSRV(UINT RootIndex, size_t BufferSize, const void* BufferData) -{ - ASSERT(BufferData != nullptr && Math::IsAligned(BufferData, 16)); - DynAlloc cb = m_CpuLinearAllocator.Allocate(BufferSize); - SIMDMemCopy(cb.DataPtr, BufferData, Math::AlignUp(BufferSize, 16) >> 4); - m_pCommandList->SetGraphicsRootShaderResourceView(RootIndex, cb.GpuAddress); -} - -inline void ComputeContext::SetDynamicSRV(UINT RootIndex, size_t BufferSize, const void* BufferData) -{ - ASSERT(BufferData != nullptr && Math::IsAligned(BufferData, 16)); - DynAlloc cb = m_CpuLinearAllocator.Allocate(BufferSize); - SIMDMemCopy(cb.DataPtr, BufferData, Math::AlignUp(BufferSize, 16) >> 4); - m_pCommandList->SetComputeRootShaderResourceView(RootIndex, cb.GpuAddress); -} - -inline void GraphicsContext::SetBufferSRV( UINT RootIndex, const GpuBuffer& SRV ) -{ - ASSERT((SRV.m_UsageState & (D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE | D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE)) != 0); - m_pCommandList->SetGraphicsRootShaderResourceView(RootIndex, SRV.GetGpuVirtualAddress()); -} - -inline void ComputeContext::SetBufferSRV( UINT RootIndex, const GpuBuffer& SRV ) -{ - ASSERT((SRV.m_UsageState & D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE) != 0); - m_pCommandList->SetComputeRootShaderResourceView(RootIndex, SRV.GetGpuVirtualAddress()); -} - -inline void GraphicsContext::SetBufferUAV( UINT RootIndex, const GpuBuffer& UAV ) -{ - ASSERT((UAV.m_UsageState & D3D12_RESOURCE_STATE_UNORDERED_ACCESS) != 0); - m_pCommandList->SetGraphicsRootUnorderedAccessView(RootIndex, UAV.GetGpuVirtualAddress()); -} - -inline void ComputeContext::SetBufferUAV( UINT RootIndex, const GpuBuffer& UAV ) -{ - ASSERT((UAV.m_UsageState & D3D12_RESOURCE_STATE_UNORDERED_ACCESS) != 0); - m_pCommandList->SetComputeRootUnorderedAccessView(RootIndex, UAV.GetGpuVirtualAddress()); -} - - - -inline void CommandContext::SetDescriptorHeap( D3D12_DESCRIPTOR_HEAP_TYPE Type, ID3D12DescriptorHeap* HeapPtr ) -{ - if (m_CurrentDescriptorHeaps[Type] != HeapPtr) - { - m_CurrentDescriptorHeaps[Type] = HeapPtr; - BindDescriptorHeaps(); - } -} -#endif - inline void CommandContext::SetDescriptorHeaps( ShaderDescriptorHeaps& Heaps ) { #ifdef _DEBUG @@ -530,84 +374,4 @@ inline void CommandContext::SetDescriptorHeaps( ShaderDescriptorHeaps& Heaps ) } } -#if 0 -inline void GraphicsContext::SetDynamicDescriptor( UINT RootIndex, UINT Offset, D3D12_CPU_DESCRIPTOR_HANDLE Handle ) -{ - SetDynamicDescriptors(RootIndex, Offset, 1, &Handle); -} - -inline void ComputeContext::SetDynamicDescriptor( UINT RootIndex, UINT Offset, D3D12_CPU_DESCRIPTOR_HANDLE Handle ) -{ - SetDynamicDescriptors(RootIndex, Offset, 1, &Handle); -} - -inline void GraphicsContext::SetDynamicDescriptors( UINT RootIndex, UINT Offset, UINT Count, const D3D12_CPU_DESCRIPTOR_HANDLE Handles[] ) -{ - m_DynamicDescriptorHeap.SetGraphicsDescriptorHandles(RootIndex, Offset, Count, Handles); -} - -inline void ComputeContext::SetDynamicDescriptors( UINT RootIndex, UINT Offset, UINT Count, const D3D12_CPU_DESCRIPTOR_HANDLE Handles[] ) -{ - m_DynamicDescriptorHeap.SetComputeDescriptorHandles(RootIndex, Offset, Count, Handles); -} - - -inline void CommandContext::CopyBuffer( GpuResource& Dest, GpuResource& Src ) -{ - TransitionResource(Dest, D3D12_RESOURCE_STATE_COPY_DEST); - TransitionResource(Src, D3D12_RESOURCE_STATE_COPY_SOURCE); - FlushResourceBarriers(); - m_pCommandList->CopyResource(Dest.GetResource(), Src.GetResource()); -} - - -inline void CommandContext::CopyCounter(GpuResource& Dest, size_t DestOffset, StructuredBuffer& Src) -{ - TransitionResource(Dest, D3D12_RESOURCE_STATE_COPY_DEST); - TransitionResource(Src.GetCounterBuffer(), D3D12_RESOURCE_STATE_COPY_SOURCE); - FlushResourceBarriers(); - m_pCommandList->CopyBufferRegion(Dest.GetResource(), DestOffset, Src.GetCounterBuffer().GetResource(), 0, 4); -} - -inline void CommandContext::ResetCounter(StructuredBuffer& Buf, uint32_t Value ) -{ - FillBuffer(Buf.GetCounterBuffer(), 0, Value, sizeof(uint32_t)); - TransitionResource(Buf.GetCounterBuffer(), D3D12_RESOURCE_STATE_UNORDERED_ACCESS); -} - -inline void CommandContext::InsertTimeStamp(ID3D12QueryHeap* pQueryHeap, uint32_t QueryIdx) -{ - m_pCommandList->EndQuery(pQueryHeap, D3D12_QUERY_TYPE_TIMESTAMP, QueryIdx); -} - -inline void CommandContext::ResolveTimeStamps(ID3D12Resource* pReadbackHeap, ID3D12QueryHeap* pQueryHeap, uint32_t NumQueries) -{ - m_pCommandList->ResolveQueryData(pQueryHeap, D3D12_QUERY_TYPE_TIMESTAMP, 0, NumQueries, pReadbackHeap, 0); -} - -inline void CommandContext::PIXBeginEvent(const wchar_t* label) -{ -#if defined(RELEASE) || _MSC_VER < 1800 - (label); -#else - ::PIXBeginEvent(m_pCommandList, 0, label); -#endif -} - -inline void CommandContext::PIXEndEvent(void) -{ -#if !defined(RELEASE) && _MSC_VER >= 1800 - ::PIXEndEvent(m_pCommandList); -#endif -} - -inline void CommandContext::PIXSetMarker(const wchar_t* label) -{ -#if defined(RELEASE) || _MSC_VER < 1800 - (label); -#else - ::PIXSetMarker(m_pCommandList, 0, label); -#endif -} -#endif } \ No newline at end of file diff --git a/Graphics/GraphicsEngineD3D12/include/CommandListD3D12Impl.h b/Graphics/GraphicsEngineD3D12/include/CommandListD3D12Impl.h index 00e5fcaa..e73e36d1 100644 --- a/Graphics/GraphicsEngineD3D12/include/CommandListD3D12Impl.h +++ b/Graphics/GraphicsEngineD3D12/include/CommandListD3D12Impl.h @@ -1,4 +1,4 @@ -/* Copyright 2015-2016 Egor Yusov +/* Copyright 2015-2017 Egor Yusov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Graphics/GraphicsEngineD3D12/include/CommandListManager.h b/Graphics/GraphicsEngineD3D12/include/CommandListManager.h index a9b79650..21866ad7 100644 --- a/Graphics/GraphicsEngineD3D12/include/CommandListManager.h +++ b/Graphics/GraphicsEngineD3D12/include/CommandListManager.h @@ -1,4 +1,4 @@ -/* Copyright 2015-2016 Egor Yusov +/* Copyright 2015-2017 Egor Yusov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -57,12 +57,16 @@ public: CommandListManager& operator = (CommandListManager&&) = delete; void CreateNewCommandList( ID3D12GraphicsCommandList** ppList, ID3D12CommandAllocator** ppAllocator ); - void DiscardAllocator( Uint64 FenceValueForReset, ID3D12CommandAllocator* pAllocator ); + + // Discards the allocator. + // CmdListNum is the serial number of the command list that was created by this allocator + void DiscardAllocator( Uint64 CmdListNum, ID3D12CommandAllocator* pAllocator ); + void RequestAllocator(ID3D12CommandAllocator** ppAllocator); private: - // Since there is only a "main pool" so far, everything below corresponds to that pool. It should be renamed and/or - // restructured if we add other pools. + // fist - the SERIAL NUMBER of command list that was created by the allocator + // second - the allocator to be discarded typedef std::pair > DiscardedAllocatorQueueElemType; std::deque< DiscardedAllocatorQueueElemType, STDAllocatorRawMem > m_DiscardedAllocators; diff --git a/Graphics/GraphicsEngineD3D12/include/D3D12ResourceBase.h b/Graphics/GraphicsEngineD3D12/include/D3D12ResourceBase.h index e8faa4a3..84629c48 100644 --- a/Graphics/GraphicsEngineD3D12/include/D3D12ResourceBase.h +++ b/Graphics/GraphicsEngineD3D12/include/D3D12ResourceBase.h @@ -1,4 +1,4 @@ -/* Copyright 2015-2016 Egor Yusov +/* Copyright 2015-2017 Egor Yusov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Graphics/GraphicsEngineD3D12/include/D3D12TypeConversions.h b/Graphics/GraphicsEngineD3D12/include/D3D12TypeConversions.h index d909bd42..d8741573 100644 --- a/Graphics/GraphicsEngineD3D12/include/D3D12TypeConversions.h +++ b/Graphics/GraphicsEngineD3D12/include/D3D12TypeConversions.h @@ -1,4 +1,4 @@ -/* Copyright 2015-2016 Egor Yusov +/* Copyright 2015-2017 Egor Yusov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Graphics/GraphicsEngineD3D12/include/D3D12TypeDefinitions.h b/Graphics/GraphicsEngineD3D12/include/D3D12TypeDefinitions.h index 892de4aa..761f750b 100644 --- a/Graphics/GraphicsEngineD3D12/include/D3D12TypeDefinitions.h +++ b/Graphics/GraphicsEngineD3D12/include/D3D12TypeDefinitions.h @@ -1,4 +1,4 @@ -/* Copyright 2015-2016 Egor Yusov +/* Copyright 2015-2017 Egor Yusov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Graphics/GraphicsEngineD3D12/include/D3D12Utils.h b/Graphics/GraphicsEngineD3D12/include/D3D12Utils.h index 64ee7c40..13dbd204 100644 --- a/Graphics/GraphicsEngineD3D12/include/D3D12Utils.h +++ b/Graphics/GraphicsEngineD3D12/include/D3D12Utils.h @@ -1,4 +1,4 @@ -/* Copyright 2015-2016 Egor Yusov +/* Copyright 2015-2017 Egor Yusov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Graphics/GraphicsEngineD3D12/include/DescriptorHeap.h b/Graphics/GraphicsEngineD3D12/include/DescriptorHeap.h index 4c4400ca..a9d895e3 100644 --- a/Graphics/GraphicsEngineD3D12/include/DescriptorHeap.h +++ b/Graphics/GraphicsEngineD3D12/include/DescriptorHeap.h @@ -1,4 +1,4 @@ -/* Copyright 2015-2016 Egor Yusov +/* Copyright 2015-2017 Egor Yusov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,6 +21,9 @@ * of the possibility of such damages. */ +// Descriptor heap management utilities. +// See http://diligentgraphics.com/diligent-engine/architecture/d3d12/managing-descriptor-heaps/ for details + #pragma once #include @@ -47,9 +50,19 @@ public: virtual Uint32 GetDescriptorSize()const = 0; }; + +// The class represents descriptor heap allocation (continuous descriptor range in a descriptor heap) +// +// m_FirstCpuHandle +// | +// | ~ ~ ~ ~ ~ X X X X X X X ~ ~ ~ ~ ~ ~ | D3D12 Descriptor Heap +// | +// m_FirstGpuHandle +// class DescriptorHeapAllocation { public: + // Creates null allocation DescriptorHeapAllocation() : m_NumHandles(1), // One null descriptor handle m_pDescriptorHeap(nullptr), @@ -59,20 +72,13 @@ public: m_FirstGpuHandle.ptr = 0; } - DescriptorHeapAllocation( IDescriptorAllocator *pAllocator, ID3D12DescriptorHeap *pHeap, D3D12_CPU_DESCRIPTOR_HANDLE CpuHandle, Uint32 NHandles ) : - m_FirstCpuHandle(CpuHandle), - m_pAllocator(pAllocator), - m_pDescriptorHeap(pHeap), - m_NumHandles(NHandles) - { - m_FirstGpuHandle.ptr = 0; - VERIFY_EXPR(m_pAllocator != nullptr && m_pDescriptorHeap != nullptr); - auto DescriptorSize = m_pAllocator->GetDescriptorSize(); - VERIFY(DescriptorSize < std::numeric_limits::max(), "DescriptorSize exceeds allowed limit") - m_DescriptorSize = static_cast( DescriptorSize ); - } - - DescriptorHeapAllocation( IDescriptorAllocator *pAllocator, ID3D12DescriptorHeap *pHeap, D3D12_CPU_DESCRIPTOR_HANDLE CpuHandle, D3D12_GPU_DESCRIPTOR_HANDLE GpuHandle, Uint32 NHandles, Uint16 AllocationManagerId = static_cast(-1) ) : + // Initializes non-null allocation + DescriptorHeapAllocation( IDescriptorAllocator *pAllocator, + ID3D12DescriptorHeap *pHeap, + D3D12_CPU_DESCRIPTOR_HANDLE CpuHandle, + D3D12_GPU_DESCRIPTOR_HANDLE GpuHandle, + Uint32 NHandles, + Uint16 AllocationManagerId = static_cast(-1) ) : m_FirstCpuHandle(CpuHandle), m_FirstGpuHandle(GpuHandle), m_pAllocator(pAllocator), @@ -86,6 +92,7 @@ public: m_DescriptorSize = static_cast( DescriptorSize ); } + // Move constructor (copy is not allowed) DescriptorHeapAllocation(DescriptorHeapAllocation &&Allocation) : m_FirstCpuHandle(Allocation.m_FirstCpuHandle), m_FirstGpuHandle(Allocation.m_FirstGpuHandle), @@ -104,6 +111,7 @@ public: Allocation.m_AllocationManagerId = static_cast(-1); } + // Move assignment (assignment is not allowed) DescriptorHeapAllocation& operator = (DescriptorHeapAllocation &&Allocation) { m_FirstCpuHandle = Allocation.m_FirstCpuHandle; @@ -125,12 +133,16 @@ public: return *this; } + // Destructor automatically releases this allocation through the allocator ~DescriptorHeapAllocation() { if(!IsNull() && m_pAllocator) m_pAllocator->Free(std::move(*this)); + // Allocation must have been disposed by the allocator + VERIFY(IsNull(), "Non-null descriptor is being destroyed") } + // Returns CPU descriptor handle at the specified offset D3D12_CPU_DESCRIPTOR_HANDLE GetCpuHandle(Uint32 Offset = 0) const { VERIFY_EXPR(Offset >= 0 && Offset < m_NumHandles); @@ -143,6 +155,7 @@ public: return CPUHandle; } + // Returns GPU descriptor handle at the specified offset D3D12_GPU_DESCRIPTOR_HANDLE GetGpuHandle(Uint32 Offset = 0) const { VERIFY_EXPR(Offset >= 0 && Offset < m_NumHandles); @@ -154,9 +167,10 @@ public: return GPUHandle; } + // Returns pointer to D3D12 descriptor heap that contains this allocation ID3D12DescriptorHeap *GetDescriptorHeap(){return m_pDescriptorHeap;} - size_t GetNumHandles(){return m_NumHandles;} + size_t GetNumHandles()const{return m_NumHandles;} bool IsNull() const { return m_FirstCpuHandle.ptr == 0; } bool IsShaderVisible() const { return m_FirstGpuHandle.ptr != 0; } @@ -164,29 +178,59 @@ public: UINT GetDescriptorSize()const{return m_DescriptorSize;} private: + // No copies, only moves are allowed DescriptorHeapAllocation(const DescriptorHeapAllocation&) = delete; DescriptorHeapAllocation& operator= (const DescriptorHeapAllocation&) = delete; + // First CPU descriptor handle in this allocation D3D12_CPU_DESCRIPTOR_HANDLE m_FirstCpuHandle = {0}; + + // First GPU descriptor handle in this allocation D3D12_GPU_DESCRIPTOR_HANDLE m_FirstGpuHandle = {0}; + // Keep strong reference to the parent heap to make sure it is alive while allocation is alive - TOO EXPENSIVE //RefCntAutoPtr m_pAllocator; + + // Pointer to the descriptor heap allocator that created this allocation IDescriptorAllocator* m_pAllocator = nullptr; + + // Pointer to the D3D12 descriptor heap that contains descriptors in this allocation ID3D12DescriptorHeap* m_pDescriptorHeap = nullptr; + + // Number of descriptors in the allocation Uint32 m_NumHandles = 0; + + // Allocation manager ID. One allocator may support several + // allocation managers. This field is required to identify + // the manager within the allocator that was used to create + // this allocation Uint16 m_AllocationManagerId = static_cast(-1); + + // Descriptor size Uint16 m_DescriptorSize = 0; }; +// The class performs suballocations within one D3D12 descriptor heap. +// It uses VariableSizeGPUAllocationsManager to manage free space in the heap +// +// | X X X X O O O X X O O X O O O O | D3D12 descriptor heap +// +// X - used descriptor +// O - available descriptor +// class DescriptorHeapAllocationManager { public: + // Creates a new D3D12 descriptor heap DescriptorHeapAllocationManager(IMemoryAllocator &Allocator, RenderDeviceD3D12Impl *pDeviceD3D12Impl, IDescriptorAllocator *pParentAllocator, size_t ThisManagerId, const D3D12_DESCRIPTOR_HEAP_DESC &HeapDesc); + + // Uses subrange of descriptors in the existing D3D12 descriptor heap + // that starts at offset FirstDescriptor and uses NumDescriptors descriptors DescriptorHeapAllocationManager(IMemoryAllocator &Allocator, RenderDeviceD3D12Impl *pDeviceD3D12Impl, IDescriptorAllocator *pParentAllocator, @@ -221,36 +265,83 @@ public: rhs.m_ThisManagerId = static_cast(-1); } + // No copies or move-assignments DescriptorHeapAllocationManager& operator = (DescriptorHeapAllocationManager&& rhs) = delete; DescriptorHeapAllocationManager(const DescriptorHeapAllocationManager&) = delete; DescriptorHeapAllocationManager& operator = (const DescriptorHeapAllocationManager&) = delete; ~DescriptorHeapAllocationManager(); + // Allocates Count descriptors DescriptorHeapAllocation Allocate( uint32_t Count ); + + // Releases descriptor heap allocation. + // Note that the allocation is not released immediately, but + // added to the release queue in the allocations manager void Free(DescriptorHeapAllocation&& Allocation); - void ReleaseStaleAllocations(Uint64 NumCompletedFrames); + + // Releases all stale allocation used by completed command lists + // The method takes the NUMBER of completed command lists (N) + // and releases all allocations whose number n < N + // (cmd list n == N is NOT released) + void ReleaseStaleAllocations(Uint64 NumCompletedCmdLists); + size_t GetNumAvailableDescriptors()const{return m_FreeBlockManager.GetFreeSize();} + size_t GetNumStaleDescriptors()const { return m_FreeBlockManager.GetStaleAllocationsSize(); } + Uint32 GetMaxDescriptors()const { return m_NumDescriptorsInAllocation; } private: + // Allocations manager used to handle descriptor allocations within the heap VariableSizeGPUAllocationsManager m_FreeBlockManager; + + // Heap description D3D12_DESCRIPTOR_HEAP_DESC m_HeapDesc; + + // Strong reference to D3D12 descriptor heap object CComPtr m_pd3d12DescriptorHeap; + + // First CPU descriptor handle in the available descriptor range D3D12_CPU_DESCRIPTOR_HANDLE m_FirstCPUHandle = {0}; + + // First GPU descriptor handle in the available descriptor range D3D12_GPU_DESCRIPTOR_HANDLE m_FirstGPUHandle = {0}; + UINT m_DescriptorSize = 0; + + // Number of descriptors in the allocation. + // If this manager was initialized as a subrange in the existing heap, + // this value may be different from m_HeapDesc.NumDescriptors Uint32 m_NumDescriptorsInAllocation = 0; + std::mutex m_AllocationMutex; RenderDeviceD3D12Impl *m_pDeviceD3D12Impl = nullptr; IDescriptorAllocator *m_pParentAllocator = nullptr; + + // External ID assigned to this descriptor allocations manager size_t m_ThisManagerId = static_cast(-1); }; -// This is an unbounded resource descriptor heap. It is intended to provide space for CPU-visible resource descriptors -// as resources are created as well as for static and mutable shader descriptor tables. +// CPU descriptor heap is intended to provide storage for resource view descriptor handles +// It contains a pool of DescriptorHeapAllocationManager object instances, where every instance manages +// its own CPU-only D3D12 descriptor heap: +// +// m_HeapPool[0] m_HeapPool[1] m_HeapPool[2] +// | X X X X X X X X |, | X X X O O X X O |, | X O O O O O O O | +// +// X - used descriptor m_AvailableHeaps = {1,2} +// O - available descriptor +// +// Allocation routine goes through the list of managers that have available descriptors and tries to process +// the request using every manager. If there are no available managers or no manager was able to handle the request, +// the function creates a new descriptor heap manager and lets it handle the request +// +// Render device contains four CPUDescriptorHeap object instances (one for each D3D12 heap type). The heaps are accessed +// when a texture or a buffer view is created. +// class CPUDescriptorHeap : public IDescriptorAllocator { public: + // Initializes the heap CPUDescriptorHeap(IMemoryAllocator &Allocator, RenderDeviceD3D12Impl *pDeviceD3D12Impl, Uint32 NumDescriptorsInHeap, @@ -268,24 +359,71 @@ public: virtual void Free(DescriptorHeapAllocation&& Allocation)override; virtual Uint32 GetDescriptorSize()const override{return m_DescriptorSize;} - void ReleaseStaleAllocations(Uint64 NumCompletedFrames); + // Releases all stale allocation used by completed command lists + // The method takes the NUMBER of completed command lists (N) + // and releases all allocations whose number n < N + // (cmd list n == N is NOT released) + void ReleaseStaleAllocations(Uint64 NumCompletedCmdLists); protected: + // Pool of descriptor heap managers std::vector > m_HeapPool; + // Indices of available descriptor heap managers std::set, STDAllocatorRawMem > m_AvailableHeaps; IMemoryAllocator &m_MemAllocator; std::mutex m_AllocationMutex; D3D12_DESCRIPTOR_HEAP_DESC m_HeapDesc; + RenderDeviceD3D12Impl *m_pDeviceD3D12Impl; UINT m_DescriptorSize; - RenderDeviceD3D12Impl *m_pDeviceD3D12Impl; - Uint32 m_MaxHeapSize = 0; + + // Maximum heap size during the application lifetime - for statistic purposes + Uint32 m_MaxHeapSize = 0; + Uint32 m_MaxStaleSize = 0; Uint32 m_CurrentSize = 0; // This size does not count stale allocation }; - +// GPU descriptor heap provides storage for shader-visible descriptors +// The heap contains single D3D12 descriptor heap that is broken into two parts. +// The first part stores static and mutable resource descriptor handles. +// The second part is intended to provide temporary storage for dynamic resources +// Space for dynamic resources is allocated in chunks, and then descriptors are suballocated within every +// chunk. DynamicSuballocationsManager facilitates this process +// +// +// static and mutable handles || dynamic space +// || chunk 0 chunk 1 chunk 2 unused +// | X O O X X O X O O O O X X X X O || | X X X O | | X X O O | | O O O O | O O O O || +// | | +// suballocation suballocation +// within chunk 0 within chunk 1 +// +// Render device contains two GPUDescriptorHeap instances (CBV_SRV_UAV and SAMPLER). The heaps +// are used to allocate GPU-visible descriptors for shader resource binding objects. The heaps +// are also used by the command contexts (through DynamicSuballocationsManager to allocated dynamic descriptors) +// +// _______________________________________________________________________________________________________________________________ +// | Render Device | +// | | +// | m_CPUDescriptorHeaps[CBV_SRV_UAV] | X X X X X X X X |, | X X X X X X X X |, | X O O X O O O O | | +// | m_CPUDescriptorHeaps[SAMPLER] | X X X X O O O X |, | X O O X O O O O | | +// | m_CPUDescriptorHeaps[RTV] | X X X O O O O O |, | O O O O O O O O | | +// | m_CPUDescriptorHeaps[DSV] | X X X O X O X O | | +// | ctx1 ctx2 | +// | m_GPUDescriptorHeaps[CBV_SRV_UAV] | X O O X X O X O O O O X X X X O || | X X X O | | X X O O | | O O O O | O O O O || | +// | m_GPUDescriptorHeaps[SAMPLER] | X X O O X O X X X O O X O O O O || | X X O O | | X O O O | | O O O O | O O O O || | +// | | +// |_______________________________________________________________________________________________________________________________| +// +// ________________________________________________ ________________________________________________ +// |Device Context 1 | |Device Context 2 | +// | | | | +// | m_DynamicGPUDescriptorAllocator[CBV_SRV_UAV] | | m_DynamicGPUDescriptorAllocator[CBV_SRV_UAV] | +// | m_DynamicGPUDescriptorAllocator[SAMPLER] | | m_DynamicGPUDescriptorAllocator[SAMPLER] | +// |________________________________________________| |________________________________________________| +// class GPUDescriptorHeap : public IDescriptorAllocator { public: @@ -309,31 +447,52 @@ public: DescriptorHeapAllocation AllocateDynamic( uint32_t Count ); - void ReleaseStaleAllocations(Uint64 NumCompletedFrames); + // Releases all stale allocation used by completed command lists + // The method takes the NUMBER of completed command lists (N) + // and releases all allocations whose number n < N + // (cmd list n == N is NOT released) + void ReleaseStaleAllocations(Uint64 NumCompletedCmdLists); - D3D12_DESCRIPTOR_HEAP_DESC &GetHeapDesc(){return m_HeapDesc;} + const D3D12_DESCRIPTOR_HEAP_DESC &GetHeapDesc()const{return m_HeapDesc;} + Uint32 GetMaxStaticDescriptors()const { return m_HeapAllocationManager.GetMaxDescriptors(); } + Uint32 GetMaxDynamicDescriptors()const { return m_DynamicAllocationsManager.GetMaxDescriptors(); } protected: D3D12_DESCRIPTOR_HEAP_DESC m_HeapDesc; CComPtr m_pd3d12DescriptorHeap; - UINT m_DescriptorSize = 0; - std::mutex m_Mutex; + std::mutex m_AllocMutex, m_DynAllocMutex; + // Allocation manager for static/mutable part DescriptorHeapAllocationManager m_HeapAllocationManager; + + // Allocation manager for dynamic part DescriptorHeapAllocationManager m_DynamicAllocationsManager; RenderDeviceD3D12Impl *m_pDeviceD3D12; Uint32 m_CurrentSize = 0; - Uint32 m_MaxHeapSize = 0; + // Maximum static/mutable part size during the application lifetime - for statistic purposes + Uint32 m_MaxHeapSize = 0; + Uint32 m_MaxStaleSize = 0; Uint32 m_CurrentDynamicSize = 0; - Uint32 m_MaxDynamicSize = 0; + // Maximum dynamic part size during the application lifetime - for statistic purposes + Uint32 m_MaxDynamicSize = 0; + Uint32 m_MaxDynamicStaleSize = 0; }; +// The class facilitates allocation of dynamic descriptor handles. It requests a chunk of heap +// from the master GPU descriptor heap and then performs linear suballocation within the chunk +// At the end of the frame all allocations are disposed. +// static and mutable handles || dynamic space +// || chunk 0 chunk 2 +// | || | X X X O | | O O O O | || GPU Descriptor Heap +// | | +// m_Suballocations[0] m_Suballocations[1] +// class DynamicSuballocationsManager : public IDescriptorAllocator { public: @@ -352,11 +511,14 @@ public: virtual Uint32 GetDescriptorSize()const override{return m_ParentGPUHeap.GetDescriptorSize();} private: + // List of chunks allocated from the master GPU descriptor heap. All chunks are disposed at the end + // of the frame std::vector > m_Suballocations; Uint32 m_CurrentSuballocationOffset = 0; Uint32 m_DynamicChunkSize = 0; + // Parent GPU descriptor heap that is used to allocate chunks GPUDescriptorHeap &m_ParentGPUHeap; }; diff --git a/Graphics/GraphicsEngineD3D12/include/DeviceContextD3D12Impl.h b/Graphics/GraphicsEngineD3D12/include/DeviceContextD3D12Impl.h index ffe8598a..14555715 100644 --- a/Graphics/GraphicsEngineD3D12/include/DeviceContextD3D12Impl.h +++ b/Graphics/GraphicsEngineD3D12/include/DeviceContextD3D12Impl.h @@ -1,4 +1,4 @@ -/* Copyright 2015-2016 Egor Yusov +/* Copyright 2015-2017 Egor Yusov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Graphics/GraphicsEngineD3D12/include/DynamicUploadHeap.h b/Graphics/GraphicsEngineD3D12/include/DynamicUploadHeap.h index 6adefccf..00140f8d 100644 --- a/Graphics/GraphicsEngineD3D12/include/DynamicUploadHeap.h +++ b/Graphics/GraphicsEngineD3D12/include/DynamicUploadHeap.h @@ -1,4 +1,4 @@ -/* Copyright 2015-2016 Egor Yusov +/* Copyright 2015-2017 Egor Yusov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -126,7 +126,7 @@ public: private: const bool m_bIsCPUAccessible; // When a chunk of dynamic memory is requested, the heap first tries to allocate the memory in the largest GPU buffer. - // If allocation fails, it a new ring buffer is created that provides enough space and requests memory from that buffer. + // If allocation fails, a new ring buffer is created that provides enough space and requests memory from that buffer. // Only the largest buffer is used for allocation and all other buffers are released when GPU is done with corresponding frames std::vector > m_RingBuffers; IMemoryAllocator &m_Allocator; diff --git a/Graphics/GraphicsEngineD3D12/include/GenerateMips.h b/Graphics/GraphicsEngineD3D12/include/GenerateMips.h index 22e81589..109858a9 100644 --- a/Graphics/GraphicsEngineD3D12/include/GenerateMips.h +++ b/Graphics/GraphicsEngineD3D12/include/GenerateMips.h @@ -1,4 +1,4 @@ -/* Copyright 2015-2016 Egor Yusov +/* Copyright 2015-2017 Egor Yusov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Graphics/GraphicsEngineD3D12/include/PipelineStateD3D12Impl.h b/Graphics/GraphicsEngineD3D12/include/PipelineStateD3D12Impl.h index 1ac6564f..84e2fb09 100644 --- a/Graphics/GraphicsEngineD3D12/include/PipelineStateD3D12Impl.h +++ b/Graphics/GraphicsEngineD3D12/include/PipelineStateD3D12Impl.h @@ -1,4 +1,4 @@ -/* Copyright 2015-2016 Egor Yusov +/* Copyright 2015-2017 Egor Yusov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Graphics/GraphicsEngineD3D12/include/RenderDeviceD3D12Impl.h b/Graphics/GraphicsEngineD3D12/include/RenderDeviceD3D12Impl.h index 0294a8b8..c353f64e 100644 --- a/Graphics/GraphicsEngineD3D12/include/RenderDeviceD3D12Impl.h +++ b/Graphics/GraphicsEngineD3D12/include/RenderDeviceD3D12Impl.h @@ -1,4 +1,4 @@ -/* Copyright 2015-2016 Egor Yusov +/* Copyright 2015-2017 Egor Yusov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -32,6 +32,7 @@ #include "CommandListManager.h" #include "CommandContext.h" #include "DynamicUploadHeap.h" +#include "Atomics.h" /// Namespace for the Direct3D11 implementation of the graphics engine namespace Diligent @@ -65,24 +66,22 @@ public: DescriptorHeapAllocation AllocateDescriptor( D3D12_DESCRIPTOR_HEAP_TYPE Type, UINT Count = 1 ); DescriptorHeapAllocation AllocateGPUDescriptors( D3D12_DESCRIPTOR_HEAP_TYPE Type, UINT Count = 1 ); - bool IsFenceComplete(Uint64 FenceValue); - bool IsFrameComplete(Uint64 Frame); + Uint64 GetNumCompletedCmdLists(); + Uint64 GetNextCmdListNumber() const {return static_cast(m_NextCmdList);} + Uint64 GetCurrentFrameNumber()const {return static_cast(m_CurrentFrameNumber);} ID3D12CommandQueue *GetCmdQueue(){return m_pd3d12CmdQueue;} - Uint64 IncrementFence(); - void WaitForFence(Uint64 FenceValue); void IdleGPU(bool ReleasePendingObjects = false); CommandContext* AllocateCommandContext(const Char *ID = ""); - Uint64 CloseAndExecuteCommandContext(CommandContext *pCtx); + void CloseAndExecuteCommandContext(CommandContext *pCtx); void DisposeCommandContext(CommandContext*); void SafeReleaseD3D12Object(ID3D12Object* pObj); - Uint64 FinishFrame(); + void FinishFrame(); DynamicUploadHeap* RequestUploadHeap(); void ReleaseUploadHeap(DynamicUploadHeap* pUploadHeap); - Uint64 GetCurrentFrame()const {return m_CurrentFrame;} private: virtual void TestTextureFormat( TEXTURE_FORMAT TexFormat ); @@ -97,20 +96,64 @@ private: CPUDescriptorHeap m_CPUDescriptorHeaps[D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES]; GPUDescriptorHeap m_GPUDescriptorHeaps[2]; // D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV == 0 // D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER == 1 - - std::mutex m_FenceMutex; - std::mutex m_EventMutex; - - CComPtr m_pFence; - Uint64 m_NextFenceValue; - Uint64 m_LastCompletedFenceValue; - HANDLE m_FenceEventHandle; - - CComPtr m_pNumCompletedFramesFence; - Uint64 m_CurrentFrame = 0; - Uint64 m_NumCompletedFrames = 0; - - + + const Uint32 m_DynamicDescriptorAllocationChunkSize[2]; + + std::mutex m_CmdQueueMutex; + + Atomics::AtomicInt64 m_CurrentFrameNumber; + + // 0-based ordinal number of the command list that will be submitted to the GPU next time + Atomics::AtomicInt64 m_NextCmdList; + + // Number of command lists that retired the GPU pipeline + // + // To check if frame X is completed, + // strong inequality must be used: + // X < m_NumCompletedCmdLists + // + volatile Uint64 m_NumCompletedCmdLists; + + // The following basic requirement guarantees correctness of resource deallocation: + // + // A resource is never released before the last draw command referencing it is invoked on the immediate context + // + // See http://diligentgraphics.com/diligent-engine/architecture/d3d12/managing-resource-lifetimes/ + + // + // CPU + // Last Reference + // of resource X + // | + // | Submit Cmd Submit Cmd Submit Cmd + // | List N List N+1 List N+2 + // V | | | + // m_NextCmdList | * N | N+1 | N+2 | + // + // + // m_NumCompletedCmdLists | N-2 | N-1 | N | N+1 | + // . . . . . + // -----------------------------.--------------.---------------.-------------------.----------------.------------- + // . . . . . + // + // GPU | Cmd List N-2 | Cmd List N-1 | Cmd List N | Cmd List N+1 | + // | + // | + // Resource X can + // be released + + // The fence is signaled right after the command list has been + // submitted to the command queue for execution. + // Note that the meaning of the fence value is the TOTAL NUMBER OF COMPLETED COMMAND LISTS, + // NOT the ordinal number of the LAST completed cmd list + // If ordinal number of the current cmd list is N, then N+1 is signaled, so the + // cmd list X is complete when X < m_NumCompletedCmdLists + // This is convenient as the default fence value is 0, and hence + // by default there are no completed cmd lists + CComPtr m_pCompletedCmdListFence; + + HANDLE m_WaitForGPUEventHandle; + CommandListManager m_CmdListManager; typedef std::unique_ptr > ContextPoolElemType; diff --git a/Graphics/GraphicsEngineD3D12/include/RootSignature.h b/Graphics/GraphicsEngineD3D12/include/RootSignature.h index 750b2b9d..b0a9e2ce 100644 --- a/Graphics/GraphicsEngineD3D12/include/RootSignature.h +++ b/Graphics/GraphicsEngineD3D12/include/RootSignature.h @@ -1,4 +1,4 @@ -/* Copyright 2015-2016 Egor Yusov +/* Copyright 2015-2017 Egor Yusov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -272,8 +272,15 @@ private: }; static const Uint8 InvalidRootTableIndex = static_cast(-1); + + // The array below contains array index of a CBV/SRV/UAV root table + // in m_RootParams (NOT the Root Index!), for every variable type + // (static, mutable, dynamic) and every shader type, + // or -1, if the table is not yet assigned to the combination Uint8 m_SrvCbvUavRootTablesMap[SHADER_VARIABLE_TYPE_NUM_TYPES * 6]; + // This array contains the same data for Sampler root table Uint8 m_SamplerRootTablesMap[SHADER_VARIABLE_TYPE_NUM_TYPES * 6]; + RootParamsManager m_RootParams; struct StaticSamplerAttribs diff --git a/Graphics/GraphicsEngineD3D12/include/SamplerD3D12Impl.h b/Graphics/GraphicsEngineD3D12/include/SamplerD3D12Impl.h index 11226b64..fc920441 100644 --- a/Graphics/GraphicsEngineD3D12/include/SamplerD3D12Impl.h +++ b/Graphics/GraphicsEngineD3D12/include/SamplerD3D12Impl.h @@ -1,4 +1,4 @@ -/* Copyright 2015-2016 Egor Yusov +/* Copyright 2015-2017 Egor Yusov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Graphics/GraphicsEngineD3D12/include/ShaderD3D12Impl.h b/Graphics/GraphicsEngineD3D12/include/ShaderD3D12Impl.h index b39c70d6..79ef7fec 100644 --- a/Graphics/GraphicsEngineD3D12/include/ShaderD3D12Impl.h +++ b/Graphics/GraphicsEngineD3D12/include/ShaderD3D12Impl.h @@ -1,4 +1,4 @@ -/* Copyright 2015-2016 Egor Yusov +/* Copyright 2015-2017 Egor Yusov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Graphics/GraphicsEngineD3D12/include/ShaderResourceBindingD3D12Impl.h b/Graphics/GraphicsEngineD3D12/include/ShaderResourceBindingD3D12Impl.h index 025db186..b5824b17 100644 --- a/Graphics/GraphicsEngineD3D12/include/ShaderResourceBindingD3D12Impl.h +++ b/Graphics/GraphicsEngineD3D12/include/ShaderResourceBindingD3D12Impl.h @@ -1,4 +1,4 @@ -/* Copyright 2015-2016 Egor Yusov +/* Copyright 2015-2017 Egor Yusov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Graphics/GraphicsEngineD3D12/include/ShaderResourceCacheD3D12.h b/Graphics/GraphicsEngineD3D12/include/ShaderResourceCacheD3D12.h index aed6d32e..d82de76f 100644 --- a/Graphics/GraphicsEngineD3D12/include/ShaderResourceCacheD3D12.h +++ b/Graphics/GraphicsEngineD3D12/include/ShaderResourceCacheD3D12.h @@ -1,4 +1,4 @@ -/* Copyright 2015-2016 Egor Yusov +/* Copyright 2015-2017 Egor Yusov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,14 +26,15 @@ /// \file /// Declaration of Diligent::ShaderResourceCacheD3D12 class +// http://diligentgraphics.com/diligent-engine/architecture/d3d12/shader-resource-cache/ // Shader resource cache stores D3D12 resources in a continuous chunk of memory: // // // __________________________________________________________ -// | m_pResources, m_NumResources | -// m_pMemory | | -// | | V +// m_pMemory | m_pResources, m_NumResources | +// | | | +// V | V // | RootTable[0] | .... | RootTable[Nrt-1] | Res[0] | ... | Res[n-1] | .... | Res[0] | ... | Res[m-1] | // | A \ // | | \ @@ -118,10 +119,11 @@ public: static const Uint32 InvalidDescriptorOffset = static_cast(-1); + //http://diligentgraphics.com/diligent-engine/architecture/d3d12/shader-resource-cache#Cache-Structure struct Resource { CachedResourceType Type = CachedResourceType::Unknown; - // CPU descriptor handle of a cached resource in external descriptor heap + // CPU descriptor handle of a cached resource in CPU-only descriptor heap // Note that for dynamic resources, this is the only available CPU descriptor handle D3D12_CPU_DESCRIPTOR_HANDLE CPUDescriptorHandle = {0}; RefCntAutoPtr pObject; @@ -136,10 +138,10 @@ public: {} inline Resource& GetResource(Uint32 OffsetFromTableStart, - const D3D12_DESCRIPTOR_HEAP_TYPE DescriptorHeapType, + const D3D12_DESCRIPTOR_HEAP_TYPE dbgDescriptorHeapType, const SHADER_TYPE dbgRefShaderType) { - VERIFY(m_dbgHeapType == DescriptorHeapType, "Incosistent descriptor heap type" ) + VERIFY(m_dbgHeapType == dbgDescriptorHeapType, "Incosistent descriptor heap type" ) VERIFY(m_dbgShaderType == dbgRefShaderType, "Incosistent shader type" ) VERIFY(OffsetFromTableStart < m_NumResources, "Root table at index is not large enough to store descriptor at offset ", OffsetFromTableStart ); @@ -148,16 +150,16 @@ public: inline Uint32 GetSize()const{return m_NumResources; } - // Offset from the start of the descriptor heap alloction to the start of the table - Uint32 TableStartOffset = InvalidDescriptorOffset; + // Offset from the start of the descriptor heap allocation to the start of the table + Uint32 m_TableStartOffset = InvalidDescriptorOffset; #ifdef _DEBUG void SetDebugAttribs(Uint32 MaxOffset, - const D3D12_DESCRIPTOR_HEAP_TYPE DescriptorHeapType, + const D3D12_DESCRIPTOR_HEAP_TYPE dbgDescriptorHeapType, const SHADER_TYPE dbgRefShaderType) { VERIFY_EXPR(m_NumResources == MaxOffset); - m_dbgHeapType = DescriptorHeapType; + m_dbgHeapType = dbgDescriptorHeapType; m_dbgShaderType = dbgRefShaderType; } @@ -185,23 +187,23 @@ public: void SetDescriptorHeapSpace(DescriptorHeapAllocation &&CbcSrvUavHeapSpace, DescriptorHeapAllocation &&SamplerHeapSpace) { - VERIFY(m_SamplerHeapSpace.GetCpuHandle().ptr == 0 && m_CbcSrvUavHeapSpace.GetCpuHandle().ptr == 0, "Space has already been allocated in GPU descriptor heaps"); + VERIFY(m_SamplerHeapSpace.GetCpuHandle().ptr == 0 && m_CbvSrvUavHeapSpace.GetCpuHandle().ptr == 0, "Space has already been allocated in GPU descriptor heaps"); #ifdef _DEBUG Uint32 NumSamplerDescriptors = 0, NumSrvCbvUavDescriptors = 0; for (Uint32 rt = 0; rt < m_NumTables; ++rt) { auto &Tbl = GetRootTable(rt); - if(Tbl.TableStartOffset != InvalidDescriptorOffset) + if(Tbl.m_TableStartOffset != InvalidDescriptorOffset) { if(Tbl.DbgGetHeapType() == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV) { - VERIFY(Tbl.TableStartOffset == NumSrvCbvUavDescriptors, "Descriptor space allocation is not continuous") - NumSrvCbvUavDescriptors = std::max(NumSrvCbvUavDescriptors, Tbl.TableStartOffset + Tbl.GetSize()); + VERIFY(Tbl.m_TableStartOffset == NumSrvCbvUavDescriptors, "Descriptor space allocation is not continuous") + NumSrvCbvUavDescriptors = std::max(NumSrvCbvUavDescriptors, Tbl.m_TableStartOffset + Tbl.GetSize()); } else { - VERIFY(Tbl.TableStartOffset == NumSamplerDescriptors, "Descriptor space allocation is not continuous") - NumSamplerDescriptors = std::max(NumSamplerDescriptors, Tbl.TableStartOffset + Tbl.GetSize()); + VERIFY(Tbl.m_TableStartOffset == NumSamplerDescriptors, "Descriptor space allocation is not continuous") + NumSamplerDescriptors = std::max(NumSamplerDescriptors, Tbl.m_TableStartOffset + Tbl.GetSize()); } } } @@ -209,12 +211,12 @@ public: VERIFY(NumSamplerDescriptors == SamplerHeapSpace.GetNumHandles() || NumSamplerDescriptors == 0 && SamplerHeapSpace.GetCpuHandle(0).ptr == 0, "Unexpected descriptor heap allocation size" ) #endif - m_CbcSrvUavHeapSpace = std::move(CbcSrvUavHeapSpace); + m_CbvSrvUavHeapSpace = std::move(CbcSrvUavHeapSpace); m_SamplerHeapSpace = std::move(SamplerHeapSpace); } - ID3D12DescriptorHeap* GetSrvCbvUavDescriptorHeap(){return m_CbcSrvUavHeapSpace.GetDescriptorHeap();} - ID3D12DescriptorHeap* GetSamplerDescriptorHeap(){return m_SamplerHeapSpace.GetDescriptorHeap();} + ID3D12DescriptorHeap* GetSrvCbvUavDescriptorHeap(){return m_CbvSrvUavHeapSpace.GetDescriptorHeap();} + ID3D12DescriptorHeap* GetSamplerDescriptorHeap() {return m_SamplerHeapSpace.GetDescriptorHeap();} // Returns CPU descriptor handle of a shader visible descriptor heap allocation template @@ -226,19 +228,19 @@ public: D3D12_CPU_DESCRIPTOR_HANDLE CPUDescriptorHandle = {0}; // Descriptor heap allocation is not assigned for dynamic resources or // in a special case when resource cache is used to store static - // variable assignments for a shader - if( RootParam.TableStartOffset != InvalidDescriptorOffset ) + // variable assignments for a shader. It is also not assigned to root views + if( RootParam.m_TableStartOffset != InvalidDescriptorOffset ) { - VERIFY(RootParam.TableStartOffset + OffsetFromTableStart < RootParam.m_NumResources, "Offset is out of range"); + VERIFY(RootParam.m_TableStartOffset + OffsetFromTableStart < RootParam.m_NumResources, "Offset is out of range"); if( HeapType == D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER ) { VERIFY_EXPR(!m_SamplerHeapSpace.IsNull()); - CPUDescriptorHandle = m_SamplerHeapSpace.GetCpuHandle(RootParam.TableStartOffset + OffsetFromTableStart); + CPUDescriptorHandle = m_SamplerHeapSpace.GetCpuHandle(RootParam.m_TableStartOffset + OffsetFromTableStart); } else if( HeapType == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV ) { - VERIFY_EXPR(!m_CbcSrvUavHeapSpace.IsNull()); - CPUDescriptorHandle = m_CbcSrvUavHeapSpace.GetCpuHandle(RootParam.TableStartOffset + OffsetFromTableStart); + VERIFY_EXPR(!m_CbvSrvUavHeapSpace.IsNull()); + CPUDescriptorHandle = m_CbvSrvUavHeapSpace.GetCpuHandle(RootParam.m_TableStartOffset + OffsetFromTableStart); } else { @@ -254,20 +256,20 @@ public: D3D12_GPU_DESCRIPTOR_HANDLE GetShaderVisibleTableGPUDescriptorHandle(Uint32 RootParamInd, Uint32 OffsetFromTableStart = 0) { auto &RootParam = GetRootTable(RootParamInd); - VERIFY_EXPR(RootParam.TableStartOffset != InvalidDescriptorOffset); - VERIFY(RootParam.TableStartOffset + OffsetFromTableStart < RootParam.m_NumResources, "Offset is out of range"); + VERIFY(RootParam.m_TableStartOffset != InvalidDescriptorOffset, "GPU descriptor handle must never be requested for dynamic resources"); + VERIFY(RootParam.m_TableStartOffset + OffsetFromTableStart < RootParam.m_NumResources, "Offset is out of range"); D3D12_GPU_DESCRIPTOR_HANDLE GPUDescriptorHandle = {0}; VERIFY( HeapType == RootParam.DbgGetHeapType(), "Invalid descriptor heap type"); if( HeapType == D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER ) { VERIFY_EXPR(!m_SamplerHeapSpace.IsNull()); - GPUDescriptorHandle = m_SamplerHeapSpace.GetGpuHandle(RootParam.TableStartOffset + OffsetFromTableStart); + GPUDescriptorHandle = m_SamplerHeapSpace.GetGpuHandle(RootParam.m_TableStartOffset + OffsetFromTableStart); } else if( HeapType == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV ) { - VERIFY_EXPR(!m_CbcSrvUavHeapSpace.IsNull()); - GPUDescriptorHandle = m_CbcSrvUavHeapSpace.GetGpuHandle(RootParam.TableStartOffset + OffsetFromTableStart); + VERIFY_EXPR(!m_CbvSrvUavHeapSpace.IsNull()); + GPUDescriptorHandle = m_CbvSrvUavHeapSpace.GetGpuHandle(RootParam.m_TableStartOffset + OffsetFromTableStart); } else { @@ -288,8 +290,11 @@ private: ShaderResourceCacheD3D12& operator = (const ShaderResourceCacheD3D12&) = delete; ShaderResourceCacheD3D12& operator = (ShaderResourceCacheD3D12&&) = delete; + // Allocation in a GPU-visible sampler descriptor heap DescriptorHeapAllocation m_SamplerHeapSpace; - DescriptorHeapAllocation m_CbcSrvUavHeapSpace; + + // Allocation in a GPU-visible CBV/SRV/UAV descriptor heap + DescriptorHeapAllocation m_CbvSrvUavHeapSpace; IMemoryAllocator *m_pAllocator=nullptr; void *m_pMemory = nullptr; diff --git a/Graphics/GraphicsEngineD3D12/include/ShaderResourceLayoutD3D12.h b/Graphics/GraphicsEngineD3D12/include/ShaderResourceLayoutD3D12.h index 90d1ba27..038fd041 100644 --- a/Graphics/GraphicsEngineD3D12/include/ShaderResourceLayoutD3D12.h +++ b/Graphics/GraphicsEngineD3D12/include/ShaderResourceLayoutD3D12.h @@ -1,4 +1,4 @@ -/* Copyright 2015-2016 Egor Yusov +/* Copyright 2015-2017 Egor Yusov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,6 +26,7 @@ /// \file /// Declaration of Diligent::ShaderResourceLayoutD3D12 class +// http://diligentgraphics.com/diligent-engine/architecture/d3d12/shader-resource-layout/ // All resources are stored in a single continuous chunk of memory using the following layout: // @@ -51,9 +52,9 @@ // // // Every SRV_CBV_UAV and Sampler structure holds a reference to D3DShaderResourceAttribs structure from ShaderResources. -// ShaderResourceLayoutD3D12 holds shared pointer to ShaderResources instance. Note that ShaderResources::SamplerId references -// a sampler in ShaderResources, while SRV_CBV_UAV::SamplerId references a sampler in ShaderResourceLayoutD3D12, and the -// two are not the same +// ShaderResourceLayoutD3D12 holds shared pointer to ShaderResourcesD3D12 instance. Note that ShaderResources::SamplerId +// references a sampler in ShaderResources, while SRV_CBV_UAV::SamplerId references a sampler in ShaderResourceLayoutD3D12, +// and the two are not the same // // // ________________SamplerId____________________ @@ -77,19 +78,28 @@ // | | | | // | ShaderResourceCacheD3D12 |---------------->| Resources | // |__________________________| |________________________________________________________________________| -// +// +// http://diligentgraphics.com/diligent-engine/architecture/d3d12/shader-resource-layout#Figure2 // Resources in the resource cache are identified by the root index and offset in the descriptor table // // -// ShaderResourceLayoutD3D12 is used by -// - ShaderD3D12Impl class instance to hold static resources of a shader; shader resource -// cache is used to store satatic resource bindings -// - PipelineStateD3D12Impl class instance to hold all kinds of resources. Root indices and -// descriptor table offsets are assigned during the initialization; no shader resource cache is used -// - ShaderResourceBindingD3D12Impl to hold all kind of resources; shader resource cache is assigned +// ShaderResourceLayoutD3D12 is used as follows: +// * Every pipeline state object (PipelineStateD3D12Impl) maintains shader resource layout for every active shader stage +// ** These resource layouts are not bound to a resource cache and are used as reference layouts for shader resource binding objects +// ** All variable types are preserved +// ** Root indices and descriptor table offsets are assigned during the initialization +// ** Resource cache is not assigned +// * Every shader object (ShaderD3D12Impl) contains shader resource layout that facilitates management of static shader resources +// ** The resource layout defines artificial layout and is bound to a resource cache that actually holds references to resources +// ** Resource cache is assigned and initialized +// * Every shader resource binding object (ShaderResourceBindingD3D12Impl) encompasses shader resource layout for every active shader +// stage in the parent pipeline state +// ** Resource layouts are initialized by clonning reference layouts from the pipeline state object and are bound to the resource +// cache that holds references to resources set by the application +// ** All shader variable types are clonned +// ** Resource cache is assigned, but not initialized; Initialization is performed by the root signature // - // Set this define to 1 to use unordered_map to store shader variables. // Note that sizeof(m_VariableHash)==128 (release mode, MS compiler, x64). #define USE_VARIABLE_HASH_MAP 0 @@ -118,7 +128,7 @@ public: ShaderResourceLayoutD3D12(IObject &Owner, IMemoryAllocator &ResourceLayoutDataAllocator); // This constructor is used by ShaderResourceBindingD3D12Impl to clone layout from the reference layout in PipelineStateD3D12Impl. - // Root indices and descriptor table offsets must be correct. Resource cache is not initialized. + // Root indices and descriptor table offsets must be correct. Resource cache is assigned, but not initialized. ShaderResourceLayoutD3D12(IObject &Owner, const ShaderResourceLayoutD3D12& SrcLayout, IMemoryAllocator &ResourceLayoutDataAllocator, @@ -136,8 +146,9 @@ public: // The method is called by // - ShaderD3D12Impl class instance to initialize static resource layout and initialize shader resource cache // to hold static resources - // - PipelineStateD3D12Impl class instance to hold all kind of resources. Root indices and - // descriptor table offsets are assigned during the initialization; no shader resource cache is provided + // - PipelineStateD3D12Impl class instance to reference all types of resources (static, mutable, dynamic). + // Root indices and descriptor table offsets are assigned during the initialization; + // no shader resource cache is provided void Initialize(ID3D12Device *pd3d12Device, const std::shared_ptr& pSrcResources, IMemoryAllocator &LayoutDataAllocator, @@ -149,10 +160,10 @@ public: // sizeof(SRV_CBV_UAV) == 32 (x64) struct SRV_CBV_UAV : ShaderVariableD3DBase { - SRV_CBV_UAV(const SRV_CBV_UAV&) = delete; - SRV_CBV_UAV(SRV_CBV_UAV&&) = delete; + SRV_CBV_UAV(const SRV_CBV_UAV&) = delete; + SRV_CBV_UAV(SRV_CBV_UAV&&) = delete; SRV_CBV_UAV& operator = (const SRV_CBV_UAV&) = delete; - SRV_CBV_UAV& operator = (SRV_CBV_UAV&&) = delete; + SRV_CBV_UAV& operator = (SRV_CBV_UAV&&) = delete; static const Uint32 ResTypeBits = 3; static const Uint32 RootIndBits = 16-ResTypeBits; @@ -170,6 +181,8 @@ public: const Uint32 OffsetFromTableStart; + // Special copy constructor. Note that sampler ID refers to the ID of the sampler + // within THIS layout, and may not be the same as in original layout SRV_CBV_UAV(ShaderResourceLayoutD3D12 &ParentLayout, const SRV_CBV_UAV &rhs, Uint32 SamId ) : ResType_RootIndex(rhs.ResType_RootIndex), SamplerId(static_cast(SamId)), @@ -182,8 +195,12 @@ public: VERIFY(IsValidRootIndex(), "Root index must be valid" ) } - SRV_CBV_UAV(ShaderResourceLayoutD3D12 &ParentLayout, const D3DShaderResourceAttribs &_Attribs, - CachedResourceType ResType, Uint32 RootIndex, Uint32 _OffsetFromTableStart, Uint32 _SamplerId) : + SRV_CBV_UAV(ShaderResourceLayoutD3D12 &ParentLayout, + const D3DShaderResourceAttribs &_Attribs, + CachedResourceType ResType, + Uint32 RootIndex, + Uint32 _OffsetFromTableStart, + Uint32 _SamplerId) : ResType_RootIndex( (static_cast(ResType) << RootIndBits) | (RootIndex & RootIndMask)), SamplerId( static_cast(_SamplerId) ), OffsetFromTableStart(_OffsetFromTableStart), @@ -206,9 +223,9 @@ public: BindResource(ppObjects[Elem], FirstElement+Elem, nullptr); } - bool IsValidSampler()const{return GetSamplerId() != InvalidSamplerId;} - bool IsValidRootIndex()const{return GetRootIndex() != InvalidRootIndex;} - bool IsValidOffset()const{return OffsetFromTableStart != InvalidOffset;} + bool IsValidSampler() const{return GetSamplerId() != InvalidSamplerId;} + bool IsValidRootIndex()const{return GetRootIndex() != InvalidRootIndex;} + bool IsValidOffset() const{return OffsetFromTableStart != InvalidOffset; } CachedResourceType GetResType()const { @@ -231,7 +248,10 @@ public: // | Root index | ResType | const Uint16 SamplerId; - void CacheCB(IDeviceObject *pBuffer, ShaderResourceCacheD3D12::Resource& DstRes, Uint32 ArrayInd, D3D12_CPU_DESCRIPTOR_HANDLE ShdrVisibleHeapCPUDescriptorHandle); + void CacheCB(IDeviceObject *pBuffer, + ShaderResourceCacheD3D12::Resource& DstRes, + Uint32 ArrayInd, + D3D12_CPU_DESCRIPTOR_HANDLE ShdrVisibleHeapCPUDescriptorHandle); template(-1); - static const Uint32 InvalidOffset = static_cast(-1); + static const Uint32 InvalidOffset = static_cast(-1); const Uint32 RootIndex; const Uint32 OffsetFromTableStart; @@ -282,8 +302,8 @@ public: VERIFY(IsValidOffset(), "Offset must be valid" ) } - bool IsValidRootIndex()const{return RootIndex != InvalidRootIndex;} - bool IsValidOffset()const{return OffsetFromTableStart != InvalidOffset;} + bool IsValidRootIndex()const{return RootIndex != InvalidRootIndex;} + bool IsValidOffset() const{return OffsetFromTableStart != InvalidOffset; } void CacheSampler(class ITextureViewD3D12 *pTexViewD3D12, Uint32 ArrayIndex, D3D12_CPU_DESCRIPTOR_HANDLE ShdrVisibleHeapCPUDescriptorHandle); }; @@ -317,7 +337,7 @@ private: std::unique_ptr > m_ResourceBuffer; Sampler* m_Samplers = nullptr; Uint16 m_NumCbvSrvUav[SHADER_VARIABLE_TYPE_NUM_TYPES] = {0,0,0}; - Uint16 m_NumSamplers[SHADER_VARIABLE_TYPE_NUM_TYPES] = {0,0,0}; + Uint16 m_NumSamplers [SHADER_VARIABLE_TYPE_NUM_TYPES] = {0,0,0}; Uint32 GetSrvCbvUavOffset(SHADER_VARIABLE_TYPE VarType, Uint32 r)const { diff --git a/Graphics/GraphicsEngineD3D12/include/ShaderResourcesD3D12.h b/Graphics/GraphicsEngineD3D12/include/ShaderResourcesD3D12.h index f58ce20d..940a1350 100644 --- a/Graphics/GraphicsEngineD3D12/include/ShaderResourcesD3D12.h +++ b/Graphics/GraphicsEngineD3D12/include/ShaderResourcesD3D12.h @@ -1,4 +1,4 @@ -/* Copyright 2015-2016 Egor Yusov +/* Copyright 2015-2017 Egor Yusov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Graphics/GraphicsEngineD3D12/include/SwapChainD3D12Impl.h b/Graphics/GraphicsEngineD3D12/include/SwapChainD3D12Impl.h index e7e8f312..197ccd68 100644 --- a/Graphics/GraphicsEngineD3D12/include/SwapChainD3D12Impl.h +++ b/Graphics/GraphicsEngineD3D12/include/SwapChainD3D12Impl.h @@ -1,4 +1,4 @@ -/* Copyright 2015-2016 Egor Yusov +/* Copyright 2015-2017 Egor Yusov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Graphics/GraphicsEngineD3D12/include/TextureD3D12Impl.h b/Graphics/GraphicsEngineD3D12/include/TextureD3D12Impl.h index 039de70f..29c0d117 100644 --- a/Graphics/GraphicsEngineD3D12/include/TextureD3D12Impl.h +++ b/Graphics/GraphicsEngineD3D12/include/TextureD3D12Impl.h @@ -1,4 +1,4 @@ -/* Copyright 2015-2016 Egor Yusov +/* Copyright 2015-2017 Egor Yusov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -44,11 +44,13 @@ class TextureD3D12Impl : public TextureBase TTextureBase; + // Creates a new D3D12 resource TextureD3D12Impl(FixedBlockMemoryAllocator &TexObjAllocator, FixedBlockMemoryAllocator &TexViewObjAllocator, class RenderDeviceD3D12Impl *pDeviceD3D12, const TextureDesc& TexDesc, const TextureData &InitData = TextureData()); + // Attaches to an existing D3D12 resource TextureD3D12Impl(FixedBlockMemoryAllocator &TexObjAllocator, FixedBlockMemoryAllocator &TexViewObjAllocator, class RenderDeviceD3D12Impl *pDeviceD3D12, diff --git a/Graphics/GraphicsEngineD3D12/include/TextureViewD3D12Impl.h b/Graphics/GraphicsEngineD3D12/include/TextureViewD3D12Impl.h index 6256ca0a..29bcbd9f 100644 --- a/Graphics/GraphicsEngineD3D12/include/TextureViewD3D12Impl.h +++ b/Graphics/GraphicsEngineD3D12/include/TextureViewD3D12Impl.h @@ -1,4 +1,4 @@ -/* Copyright 2015-2016 Egor Yusov +/* Copyright 2015-2017 Egor Yusov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -50,12 +50,9 @@ public: virtual void QueryInterface( const Diligent::INTERFACE_ID &IID, IObject **ppInterface )override; - //virtual ID3D12View* GetD3D12View()override; - void GenerateMips( IDeviceContext *pContext )override; virtual D3D12_CPU_DESCRIPTOR_HANDLE GetCPUDescriptorHandle()override{return m_Descriptor.GetCpuHandle();} - //virtual D3D12_GPU_DESCRIPTOR_HANDLE GetGPUDescriptorHandle()override{return m_Descriptor.GetGpuHandle();} protected: /// D3D12 view descriptor handle diff --git a/Graphics/GraphicsEngineD3D12/include/pch.h b/Graphics/GraphicsEngineD3D12/include/pch.h index f2f0b7f4..225f72b4 100644 --- a/Graphics/GraphicsEngineD3D12/include/pch.h +++ b/Graphics/GraphicsEngineD3D12/include/pch.h @@ -1,4 +1,4 @@ -/* Copyright 2015-2016 Egor Yusov +/* Copyright 2015-2017 Egor Yusov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Graphics/GraphicsEngineD3D12/interface/BufferD3D12.h b/Graphics/GraphicsEngineD3D12/interface/BufferD3D12.h index f3e69a13..823965a9 100644 --- a/Graphics/GraphicsEngineD3D12/interface/BufferD3D12.h +++ b/Graphics/GraphicsEngineD3D12/interface/BufferD3D12.h @@ -1,4 +1,4 @@ -/* Copyright 2015-2016 Egor Yusov +/* Copyright 2015-2017 Egor Yusov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Graphics/GraphicsEngineD3D12/interface/BufferViewD3D12.h b/Graphics/GraphicsEngineD3D12/interface/BufferViewD3D12.h index 7d9e45c9..a388e4c6 100644 --- a/Graphics/GraphicsEngineD3D12/interface/BufferViewD3D12.h +++ b/Graphics/GraphicsEngineD3D12/interface/BufferViewD3D12.h @@ -1,4 +1,4 @@ -/* Copyright 2015-2016 Egor Yusov +/* Copyright 2015-2017 Egor Yusov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Graphics/GraphicsEngineD3D12/interface/PipelineStateD3D12.h b/Graphics/GraphicsEngineD3D12/interface/PipelineStateD3D12.h index c31ea4cc..e978c014 100644 --- a/Graphics/GraphicsEngineD3D12/interface/PipelineStateD3D12.h +++ b/Graphics/GraphicsEngineD3D12/interface/PipelineStateD3D12.h @@ -1,4 +1,4 @@ -/* Copyright 2015-2016 Egor Yusov +/* Copyright 2015-2017 Egor Yusov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Graphics/GraphicsEngineD3D12/interface/RenderDeviceD3D12.h b/Graphics/GraphicsEngineD3D12/interface/RenderDeviceD3D12.h index 309d355e..3d37c0a8 100644 --- a/Graphics/GraphicsEngineD3D12/interface/RenderDeviceD3D12.h +++ b/Graphics/GraphicsEngineD3D12/interface/RenderDeviceD3D12.h @@ -1,4 +1,4 @@ -/* Copyright 2015-2016 Egor Yusov +/* Copyright 2015-2017 Egor Yusov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Graphics/GraphicsEngineD3D12/interface/RenderDeviceFactoryD3D12.h b/Graphics/GraphicsEngineD3D12/interface/RenderDeviceFactoryD3D12.h index f3aa45f4..2a81cf76 100644 --- a/Graphics/GraphicsEngineD3D12/interface/RenderDeviceFactoryD3D12.h +++ b/Graphics/GraphicsEngineD3D12/interface/RenderDeviceFactoryD3D12.h @@ -1,4 +1,4 @@ -/* Copyright 2015-2016 Egor Yusov +/* Copyright 2015-2017 Egor Yusov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Graphics/GraphicsEngineD3D12/interface/SamplerD3D12.h b/Graphics/GraphicsEngineD3D12/interface/SamplerD3D12.h index 4359fdc5..f8d98e69 100644 --- a/Graphics/GraphicsEngineD3D12/interface/SamplerD3D12.h +++ b/Graphics/GraphicsEngineD3D12/interface/SamplerD3D12.h @@ -1,4 +1,4 @@ -/* Copyright 2015-2016 Egor Yusov +/* Copyright 2015-2017 Egor Yusov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Graphics/GraphicsEngineD3D12/interface/ShaderD3D12.h b/Graphics/GraphicsEngineD3D12/interface/ShaderD3D12.h index 50aa22aa..c8bca697 100644 --- a/Graphics/GraphicsEngineD3D12/interface/ShaderD3D12.h +++ b/Graphics/GraphicsEngineD3D12/interface/ShaderD3D12.h @@ -1,4 +1,4 @@ -/* Copyright 2015-2016 Egor Yusov +/* Copyright 2015-2017 Egor Yusov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Graphics/GraphicsEngineD3D12/interface/ShaderResourceBindingD3D12.h b/Graphics/GraphicsEngineD3D12/interface/ShaderResourceBindingD3D12.h index 6038b88b..27162053 100644 --- a/Graphics/GraphicsEngineD3D12/interface/ShaderResourceBindingD3D12.h +++ b/Graphics/GraphicsEngineD3D12/interface/ShaderResourceBindingD3D12.h @@ -1,4 +1,4 @@ -/* Copyright 2015-2016 Egor Yusov +/* Copyright 2015-2017 Egor Yusov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Graphics/GraphicsEngineD3D12/interface/SwapChainD3D12.h b/Graphics/GraphicsEngineD3D12/interface/SwapChainD3D12.h index eacc0ef4..ab936019 100644 --- a/Graphics/GraphicsEngineD3D12/interface/SwapChainD3D12.h +++ b/Graphics/GraphicsEngineD3D12/interface/SwapChainD3D12.h @@ -1,4 +1,4 @@ -/* Copyright 2015-2016 Egor Yusov +/* Copyright 2015-2017 Egor Yusov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Graphics/GraphicsEngineD3D12/interface/TextureD3D12.h b/Graphics/GraphicsEngineD3D12/interface/TextureD3D12.h index 2fe585ce..449f2692 100644 --- a/Graphics/GraphicsEngineD3D12/interface/TextureD3D12.h +++ b/Graphics/GraphicsEngineD3D12/interface/TextureD3D12.h @@ -1,4 +1,4 @@ -/* Copyright 2015-2016 Egor Yusov +/* Copyright 2015-2017 Egor Yusov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Graphics/GraphicsEngineD3D12/interface/TextureViewD3D12.h b/Graphics/GraphicsEngineD3D12/interface/TextureViewD3D12.h index 967d28a1..f9c83a61 100644 --- a/Graphics/GraphicsEngineD3D12/interface/TextureViewD3D12.h +++ b/Graphics/GraphicsEngineD3D12/interface/TextureViewD3D12.h @@ -1,4 +1,4 @@ -/* Copyright 2015-2016 Egor Yusov +/* Copyright 2015-2017 Egor Yusov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Graphics/GraphicsEngineD3D12/src/BufferD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/BufferD3D12Impl.cpp index 1a516ad3..9f75d08e 100644 --- a/Graphics/GraphicsEngineD3D12/src/BufferD3D12Impl.cpp +++ b/Graphics/GraphicsEngineD3D12/src/BufferD3D12Impl.cpp @@ -1,4 +1,4 @@ -/* Copyright 2015-2016 Egor Yusov +/* Copyright 2015-2017 Egor Yusov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -367,7 +367,7 @@ void BufferD3D12Impl::CreateCBV(D3D12_CPU_DESCRIPTOR_HANDLE CBVDescriptor) void BufferD3D12Impl::DbgVerifyDynamicAllocation(Uint32 ContextId) { VERIFY(m_DynamicData[ContextId].GPUAddress != 0, "Dynamic buffer must be mapped before the first use"); - auto CurrentFrame = ValidatedCast(GetDevice())->GetCurrentFrame(); + auto CurrentFrame = ValidatedCast(GetDevice())->GetCurrentFrameNumber(); VERIFY(m_DynamicData[ContextId].FrameNum == CurrentFrame, "Dynamic allocation is out-of-date. Dynamic buffer must be mapped in the same frame it is used."); VERIFY(GetState() == D3D12_RESOURCE_STATE_GENERIC_READ, "Dynamic buffers are expected to always be in D3D12_RESOURCE_STATE_GENERIC_READ state") } diff --git a/Graphics/GraphicsEngineD3D12/src/BufferViewD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/BufferViewD3D12Impl.cpp index e27c91ea..f0f7b2d7 100644 --- a/Graphics/GraphicsEngineD3D12/src/BufferViewD3D12Impl.cpp +++ b/Graphics/GraphicsEngineD3D12/src/BufferViewD3D12Impl.cpp @@ -1,4 +1,4 @@ -/* Copyright 2015-2016 Egor Yusov +/* Copyright 2015-2017 Egor Yusov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Graphics/GraphicsEngineD3D12/src/CommandContext.cpp b/Graphics/GraphicsEngineD3D12/src/CommandContext.cpp index 932eb333..9f689040 100644 --- a/Graphics/GraphicsEngineD3D12/src/CommandContext.cpp +++ b/Graphics/GraphicsEngineD3D12/src/CommandContext.cpp @@ -1,4 +1,4 @@ -/* Copyright 2015-2016 Egor Yusov +/* Copyright 2015-2017 Egor Yusov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,21 +21,6 @@ * of the possibility of such damages. */ -// -// Copyright (c) Microsoft. All rights reserved. -// This code is licensed under the MIT License (MIT). -// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF -// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY -// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR -// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. -// -// Developed by Minigraph -// -// Author: James Stanard -// -// Adapted to Diligent Engine: Egor Yusov -// - #include "pch.h" #include "CommandContext.h" #include "TextureD3D12Impl.h" @@ -48,7 +33,7 @@ namespace Diligent CommandContext::CommandContext( IMemoryAllocator &MemAllocator, CommandListManager &CmdListManager, GPUDescriptorHeap GPUDescriptorHeaps[], - Uint32 DynamicDescriptorAllocationChunkSize[]) : + const Uint32 DynamicDescriptorAllocationChunkSize[]) : m_pCurGraphicsRootSignature( nullptr), m_pCurGraphicsPipelineState( nullptr), m_pCurComputeRootSignature( nullptr), @@ -112,22 +97,6 @@ ID3D12GraphicsCommandList* CommandContext::Close(ID3D12CommandAllocator **ppAllo } -#if 0 -void CommandContext::BindDescriptorHeaps( void ) -{ - UINT NonNullHeaps = 0; - ID3D12DescriptorHeap* HeapsToBind[D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES]; - for (UINT i = 0; i < D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES; ++i) - { - ID3D12DescriptorHeap* HeapIter = m_CurrentDescriptorHeaps[i]; - if (HeapIter != nullptr) - HeapsToBind[NonNullHeaps++] = HeapIter; - } - - if (NonNullHeaps > 0) - m_pCommandList->SetDescriptorHeaps(NonNullHeaps, HeapsToBind); -} -#endif void GraphicsContext::SetRenderTargets( UINT NumRTVs, ITextureViewD3D12** ppRTVs, ITextureViewD3D12* pDSV ) { @@ -280,39 +249,6 @@ void CommandContext::TransitionResource(D3D12ResourceBase& Resource, IDeviceObje FlushResourceBarriers(); } -#if 0 -void CommandContext::BeginResourceTransition(GpuResource& Resource, D3D12_RESOURCE_STATES NewState, bool FlushImmediate) -{ - // If it's already transitioning, finish that transition - if (Resource.m_TransitioningState != (D3D12_RESOURCE_STATES)-1) - TransitionResource(Resource, Resource.m_TransitioningState); - - D3D12_RESOURCE_STATES OldState = Resource.m_UsageState; - - if (OldState != NewState) - { - ASSERT(m_NumBarriersToFlush < 16, "Exceeded arbitrary limit on buffered barriers"); - D3D12_RESOURCE_BARRIER& BarrierDesc = m_ResourceBarrierBuffer[m_NumBarriersToFlush++]; - - BarrierDesc.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; - BarrierDesc.Transition.pResource = Resource.GetResource(); - BarrierDesc.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; - BarrierDesc.Transition.StateBefore = OldState; - BarrierDesc.Transition.StateAfter = NewState; - - BarrierDesc.Flags = D3D12_RESOURCE_BARRIER_FLAG_BEGIN_ONLY; - - Resource.m_TransitioningState = NewState; - } - - if (FlushImmediate || m_NumBarriersToFlush == 16) - { - m_pCommandList->ResourceBarrier(m_NumBarriersToFlush, m_ResourceBarrierBuffer); - m_NumBarriersToFlush = 0; - } -} -#endif - void CommandContext::FlushResourceBarriers() { if (m_PendingResourceBarriers.empty()) @@ -357,7 +293,7 @@ void CommandContext::InsertAliasBarrier(D3D12ResourceBase& Before, D3D12Resource FlushResourceBarriers(); } -void CommandContext::DiscardUsedDescriptorHeaps(Uint64 FrameNumber) +void CommandContext::DiscardDynamicDescriptors(Uint64 FrameNumber) { for(size_t HeapType = 0; HeapType < _countof(m_DynamicGPUDescriptorAllocator); ++HeapType) m_DynamicGPUDescriptorAllocator[HeapType].DiscardAllocations(FrameNumber); @@ -369,81 +305,4 @@ DescriptorHeapAllocation CommandContext::AllocateDynamicGPUVisibleDescriptor( D3 return m_DynamicGPUDescriptorAllocator[Type].Allocate(Count); } -#if 0 - -void CommandContext::FillBuffer( GpuResource& Dest, size_t DestOffset, DWParam Value, size_t NumBytes ) -{ - DynAlloc TempSpace = m_CpuLinearAllocator.Allocate( NumBytes, 512 ); - __m128 VectorValue = _mm_set1_ps(Value.Float); - SIMDMemFill(TempSpace.DataPtr, VectorValue, Math::DivideByMultiple(NumBytes, 16)); - CopyBufferRegion(Dest, DestOffset, TempSpace.Buffer, TempSpace.Offset, NumBytes ); -} - -void CommandContext::CopySubresource(GpuResource& Dest, UINT DestSubIndex, GpuResource& Src, UINT SrcSubIndex) -{ - // TODO: Add a TransitionSubresource()? - TransitionResource(Dest, D3D12_RESOURCE_STATE_COPY_DEST); - TransitionResource(Src, D3D12_RESOURCE_STATE_COPY_SOURCE); - FlushResourceBarriers(); - - D3D12_TEXTURE_COPY_LOCATION DestLocation = - { - Dest.GetResource(), - D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX, - DestSubIndex - }; - - D3D12_TEXTURE_COPY_LOCATION SrcLocation = - { - Src.GetResource(), - D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX, - SrcSubIndex - }; - - m_pCommandList->CopyTextureRegion(&DestLocation, 0, 0, 0, &SrcLocation, nullptr); -} - -void CommandContext::InitializeTextureArraySlice(GpuResource& Dest, UINT SliceIndex, GpuResource& Src) -{ - CommandContext& Context = CommandContext::Begin(); - - Context.TransitionResource(Dest, D3D12_RESOURCE_STATE_COPY_DEST); - Context.TransitionResource(Src, D3D12_RESOURCE_STATE_COPY_SOURCE); - Context.FlushResourceBarriers(); - - const D3D12_RESOURCE_DESC& DestDesc = Dest.GetResource()->GetDesc(); - const D3D12_RESOURCE_DESC& SrcDesc = Src.GetResource()->GetDesc(); - - ASSERT(SliceIndex < DestDesc.DepthOrArraySize && - SrcDesc.DepthOrArraySize == 1 && - DestDesc.Width == SrcDesc.Width && - DestDesc.Height == SrcDesc.Height && - DestDesc.MipLevels <= SrcDesc.MipLevels - ); - - UINT SubResourceIndex = SliceIndex * DestDesc.MipLevels; - - for (UINT i = 0; i < DestDesc.MipLevels; ++i) - { - D3D12_TEXTURE_COPY_LOCATION destCopyLocation = - { - Dest.GetResource(), - D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX, - SubResourceIndex + i - }; - - D3D12_TEXTURE_COPY_LOCATION srcCopyLocation = - { - Src.GetResource(), - D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX, - i - }; - - Context.m_pCommandList->CopyTextureRegion(&destCopyLocation, 0, 0, 0, &srcCopyLocation, nullptr); - } - - Context.CloseAndExecute(); -} -#endif - } diff --git a/Graphics/GraphicsEngineD3D12/src/CommandListManager.cpp b/Graphics/GraphicsEngineD3D12/src/CommandListManager.cpp index 8ffc64ce..b9b10954 100644 --- a/Graphics/GraphicsEngineD3D12/src/CommandListManager.cpp +++ b/Graphics/GraphicsEngineD3D12/src/CommandListManager.cpp @@ -1,4 +1,4 @@ -/* Copyright 2015-2016 Egor Yusov +/* Copyright 2015-2017 Egor Yusov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -72,9 +72,23 @@ void CommandListManager::RequestAllocator(ID3D12CommandAllocator** ppAllocator) if (!m_DiscardedAllocators.empty()) { + // Pick the oldest allocator at the front of the deque + // If this allocator is not yet available, there is no sense in + // looking at the rest of allocators auto& AllocatorPair = m_DiscardedAllocators.front(); - - if (m_pDeviceD3D12->IsFenceComplete(AllocatorPair.first)) + + // Get the NUMBER OF COMPLETED cmd lists + auto NumCompeltedCmdLists = m_pDeviceD3D12->GetNumCompletedCmdLists(); + // Note that NumCompeltedCmdLists only grows. So if after we queried + // the value, the actual value is increased in other thread, this will not + // be an issue as the only consequence is that the allocator that is + // potentially available may not be used. + + // AllocatorPair.first is the NUMBER of the command list. + // If command list number is N, it can be reused when + // NumCompeltedCmdLists is at least N+1 + // (To reuse allocator used to create CmdList 0, NumCompeltedCmdLists must be at least 1) + if ( AllocatorPair.first < NumCompeltedCmdLists ) { *ppAllocator = AllocatorPair.second.Detach(); auto hr = (*ppAllocator)->Reset(); @@ -95,12 +109,13 @@ void CommandListManager::RequestAllocator(ID3D12CommandAllocator** ppAllocator) } } -void CommandListManager::DiscardAllocator( Uint64 FenceValue, ID3D12CommandAllocator* pAllocator ) +void CommandListManager::DiscardAllocator( Uint64 CmdListNum, ID3D12CommandAllocator* pAllocator ) { std::lock_guard LockGuard(m_AllocatorMutex); - // That fence value indicates we are free to reset the allocator - m_DiscardedAllocators.emplace_back( FenceValue, CComPtr(pAllocator) ); + // CmdListNum is the number of the command list that was created by this allocator. + // This value is used to understand when it is safe to reuse the allocator + m_DiscardedAllocators.emplace_back( CmdListNum, CComPtr(pAllocator) ); } } diff --git a/Graphics/GraphicsEngineD3D12/src/D3D12ResourceBase.cpp b/Graphics/GraphicsEngineD3D12/src/D3D12ResourceBase.cpp index b2e9f431..0744fda7 100644 --- a/Graphics/GraphicsEngineD3D12/src/D3D12ResourceBase.cpp +++ b/Graphics/GraphicsEngineD3D12/src/D3D12ResourceBase.cpp @@ -1,4 +1,4 @@ -/* Copyright 2015-2016 Egor Yusov +/* Copyright 2015-2017 Egor Yusov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Graphics/GraphicsEngineD3D12/src/D3D12TypeConversions.cpp b/Graphics/GraphicsEngineD3D12/src/D3D12TypeConversions.cpp index 738fbc98..68082795 100644 --- a/Graphics/GraphicsEngineD3D12/src/D3D12TypeConversions.cpp +++ b/Graphics/GraphicsEngineD3D12/src/D3D12TypeConversions.cpp @@ -1,4 +1,4 @@ -/* Copyright 2015-2016 Egor Yusov +/* Copyright 2015-2017 Egor Yusov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Graphics/GraphicsEngineD3D12/src/D3D12Utils.cpp b/Graphics/GraphicsEngineD3D12/src/D3D12Utils.cpp index a1f82e1c..c2428e16 100644 --- a/Graphics/GraphicsEngineD3D12/src/D3D12Utils.cpp +++ b/Graphics/GraphicsEngineD3D12/src/D3D12Utils.cpp @@ -1,4 +1,4 @@ -/* Copyright 2015-2016 Egor Yusov +/* Copyright 2015-2017 Egor Yusov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Graphics/GraphicsEngineD3D12/src/DLLMain.cpp b/Graphics/GraphicsEngineD3D12/src/DLLMain.cpp index fff890c0..94065164 100644 --- a/Graphics/GraphicsEngineD3D12/src/DLLMain.cpp +++ b/Graphics/GraphicsEngineD3D12/src/DLLMain.cpp @@ -1,4 +1,4 @@ -/* Copyright 2015-2016 Egor Yusov +/* Copyright 2015-2017 Egor Yusov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Graphics/GraphicsEngineD3D12/src/DescriptorHeap.cpp b/Graphics/GraphicsEngineD3D12/src/DescriptorHeap.cpp index a8ea6756..d226a3b8 100644 --- a/Graphics/GraphicsEngineD3D12/src/DescriptorHeap.cpp +++ b/Graphics/GraphicsEngineD3D12/src/DescriptorHeap.cpp @@ -1,4 +1,4 @@ -/* Copyright 2015-2016 Egor Yusov +/* Copyright 2015-2017 Egor Yusov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -29,7 +29,7 @@ namespace Diligent { - +// Creates a new descriptor heap and reference the entire heap DescriptorHeapAllocationManager::DescriptorHeapAllocationManager(IMemoryAllocator &Allocator, RenderDeviceD3D12Impl *pDeviceD3D12Impl, IDescriptorAllocator *pParentAllocator, @@ -54,6 +54,8 @@ DescriptorHeapAllocationManager::DescriptorHeapAllocationManager(IMemoryAllocato m_FirstGPUHandle = m_pd3d12DescriptorHeap->GetGPUDescriptorHandleForHeapStart(); } +// Uses subrange of descriptors in the existing D3D12 descriptor heap +// that starts at offset FirstDescriptor and uses NumDescriptors descriptors DescriptorHeapAllocationManager::DescriptorHeapAllocationManager(IMemoryAllocator &Allocator, RenderDeviceD3D12Impl *pDeviceD3D12Impl, IDescriptorAllocator *pParentAllocator, @@ -90,40 +92,59 @@ DescriptorHeapAllocationManager::~DescriptorHeapAllocationManager() DescriptorHeapAllocation DescriptorHeapAllocationManager::Allocate(uint32_t Count) { std::lock_guard LockGuard(m_AllocationMutex); + // Methods of VariableSizeGPUAllocationsManager class are not thread safe! + // Use variable-size GPU allocations manager to allocate the requested number of descriptors auto DescriptorHandleOffset = m_FreeBlockManager.Allocate(Count); if (DescriptorHandleOffset == VariableSizeGPUAllocationsManager::InvalidOffset) { return DescriptorHeapAllocation(); } + // Compute the first CPU and GPU descriptor handles in the allocation by + // offseting the first CPU and GPU descriptor handle in the range auto CPUHandle = m_FirstCPUHandle; CPUHandle.ptr += DescriptorHandleOffset * m_DescriptorSize; - auto GPUHandle = m_FirstGPUHandle; + auto GPUHandle = m_FirstGPUHandle; // Will be null if the heap is not GPU-visible if(m_HeapDesc.Flags & D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE) GPUHandle.ptr += DescriptorHandleOffset * m_DescriptorSize; - VERIFY(m_ThisManagerId < std::numeric_limits::max(), "ManagerID exceed allowed limit"); - DescriptorHeapAllocation Allocation( m_pParentAllocator, m_pd3d12DescriptorHeap, CPUHandle, GPUHandle, Count, static_cast(m_ThisManagerId)); - - return Allocation; + VERIFY(m_ThisManagerId < std::numeric_limits::max(), "ManagerID exceeds 16-bit range"); + return DescriptorHeapAllocation( m_pParentAllocator, m_pd3d12DescriptorHeap, CPUHandle, GPUHandle, Count, static_cast(m_ThisManagerId)); } void DescriptorHeapAllocationManager::Free(DescriptorHeapAllocation&& Allocation) { std::lock_guard LockGuard(m_AllocationMutex); + // Methods of VariableSizeGPUAllocationsManager class are not thread safe! VERIFY(Allocation.GetAllocationManagerId() == m_ThisManagerId, "Invalid descriptor heap manager Id") auto DescriptorOffset = (Allocation.GetCpuHandle().ptr - m_FirstCPUHandle.ptr) / m_DescriptorSize; - m_FreeBlockManager.Free(DescriptorOffset, Allocation.GetNumHandles(), m_pDeviceD3D12Impl->GetCurrentFrame()); + + // Note that the allocation is not released immediately, but added to the release queue in the allocations manager + + // The following basic requirement guarantees correctness of resource deallocation: + // + // A resource is never released before the last draw command referencing it is invoked on the immediate context + // + // See http://diligentgraphics.com/diligent-engine/architecture/d3d12/managing-resource-lifetimes/ + // + // If basic requirement is met, GetNextCmdListNumber() will never return a number that is less than the last + // command list number that references descriptors from the allocation + m_FreeBlockManager.Free(DescriptorOffset, Allocation.GetNumHandles(), m_pDeviceD3D12Impl->GetNextCmdListNumber()); + + // Clear the allocation Allocation = DescriptorHeapAllocation(); } -void DescriptorHeapAllocationManager::ReleaseStaleAllocations(Uint64 NumCompletedFrames) +void DescriptorHeapAllocationManager::ReleaseStaleAllocations(Uint64 NumCompletedCmdLists) { - m_FreeBlockManager.ReleaseCompletedFrames(NumCompletedFrames); + std::lock_guard LockGuard(m_AllocationMutex); + // Methods of VariableSizeGPUAllocationsManager class are not thread safe! + + m_FreeBlockManager.ReleaseStaleAllocations(NumCompletedCmdLists); } @@ -151,33 +172,55 @@ CPUDescriptorHeap::~CPUDescriptorHeap() VERIFY(m_CurrentSize == 0, "Not all allocations released" ); VERIFY(m_AvailableHeaps.size() == m_HeapPool.size(), "Not all descriptor heap pools are released"); + Uint32 TotalDescriptors = 0; for (auto HeapPoolIt = m_HeapPool.begin(); HeapPoolIt != m_HeapPool.end(); ++HeapPoolIt) { VERIFY(HeapPoolIt->GetNumAvailableDescriptors() == m_HeapDesc.NumDescriptors, "Not all descriptors in the descriptor pool are released"); - } + TotalDescriptors += HeapPoolIt->GetMaxDescriptors(); + } - LOG_INFO_MESSAGE("Max ", GetD3D12DescriptorHeapTypeLiteralName(m_HeapDesc.Type), " CPU heap size: ", m_MaxHeapSize); + LOG_INFO_MESSAGE(GetD3D12DescriptorHeapTypeLiteralName(m_HeapDesc.Type), " CPU heap max size: ", m_MaxHeapSize, " (", m_MaxHeapSize*100/ TotalDescriptors, "%) " + ". Max stale size: ", m_MaxStaleSize, " (", m_MaxStaleSize * 100 / TotalDescriptors, "%)"); } DescriptorHeapAllocation CPUDescriptorHeap::Allocate( uint32_t Count ) { std::lock_guard LockGuard(m_AllocationMutex); + // Note that every DescriptorHeapAllocationManager object instance is itslef + // thread-safe. Nested mutexes cannot cause a deadlock + DescriptorHeapAllocation Allocation; + // Go through all descriptor heap managers that have free descriptors for (auto AvailableHeapIt = m_AvailableHeaps.begin(); AvailableHeapIt != m_AvailableHeaps.end(); ++AvailableHeapIt) { + // Try to allocate descriptor using the current descriptor heap manager Allocation = m_HeapPool[*AvailableHeapIt].Allocate(Count); + // Remove the manager from the pool if it has no more available descriptors if(m_HeapPool[*AvailableHeapIt].GetNumAvailableDescriptors() == 0) m_AvailableHeaps.erase(*AvailableHeapIt); + // Terminate the loop if descriptor was successfully allocated, otherwise + // go to the next manager if(Allocation.GetCpuHandle().ptr != 0) break; } + // If there were no available descriptor heap managers or no manager was able + // to suffice the allocation request, create a new manager if(Allocation.GetCpuHandle().ptr == 0) { + // Make sure the heap is large enough to accomodate the requested number of descriptors + if(Count > m_HeapDesc.NumDescriptors) + { + LOG_WARNING_MESSAGE("Number of requested descriptors exceeds the descriptor heap size. Increasing the number of descriptors in the heap") + } + m_HeapDesc.NumDescriptors = std::max(m_HeapDesc.NumDescriptors, static_cast(Count)); + // Create a new descriptor heap manager. Note that this constructor creates a new D3D12 descriptor + // heap and references the entire heap. Pool index is used as manager ID m_HeapPool.emplace_back(m_MemAllocator, m_pDeviceD3D12Impl, this, m_HeapPool.size(), m_HeapDesc); auto NewHeapIt = m_AvailableHeaps.insert(m_HeapPool.size()-1); + // Use the new manager to allocate descriptor handles Allocation = m_HeapPool[*NewHeapIt.first].Allocate(Count); } @@ -189,21 +232,28 @@ DescriptorHeapAllocation CPUDescriptorHeap::Allocate( uint32_t Count ) void CPUDescriptorHeap::Free(DescriptorHeapAllocation&& Allocation) { + // Method is called from ~DescriptorHeapAllocation() std::lock_guard LockGuard(m_AllocationMutex); auto ManagerId = Allocation.GetAllocationManagerId(); m_CurrentSize -= static_cast(Allocation.GetNumHandles()); m_HeapPool[ManagerId].Free(std::move(Allocation)); } -void CPUDescriptorHeap::ReleaseStaleAllocations(Uint64 NumCompletedFrames) +void CPUDescriptorHeap::ReleaseStaleAllocations(Uint64 NumCompletedCmdLists) { std::lock_guard LockGuard(m_AllocationMutex); + size_t StaleSize = 0; for (size_t HeapManagerInd = 0; HeapManagerInd < m_HeapPool.size(); ++HeapManagerInd) { - m_HeapPool[HeapManagerInd].ReleaseStaleAllocations(NumCompletedFrames); + // Update size before releasing stale allocations + StaleSize += m_HeapPool[HeapManagerInd].GetNumStaleDescriptors(); + + m_HeapPool[HeapManagerInd].ReleaseStaleAllocations(NumCompletedCmdLists); + // Return the manager to the pool of available managers if it has available descriptors if(m_HeapPool[HeapManagerInd].GetNumAvailableDescriptors() > 0) m_AvailableHeaps.insert(HeapManagerInd); } + m_MaxStaleSize = std::max(m_MaxStaleSize, static_cast(StaleSize)); } @@ -236,12 +286,19 @@ GPUDescriptorHeap::GPUDescriptorHeap(IMemoryAllocator &Allocator, GPUDescriptorHeap::~GPUDescriptorHeap() { - LOG_INFO_MESSAGE("Max ", GetD3D12DescriptorHeapTypeLiteralName(m_HeapDesc.Type), " GPU heap static/dynamic size: ", m_MaxHeapSize, "/", m_MaxDynamicSize); + auto StaticSize = m_HeapAllocationManager.GetMaxDescriptors(); + auto DynamicSize = m_DynamicAllocationsManager.GetMaxDescriptors(); + LOG_INFO_MESSAGE(GetD3D12DescriptorHeapTypeLiteralName(m_HeapDesc.Type), " GPU heap max allocated size (static|dynamic): ", + m_MaxHeapSize, " (", m_MaxHeapSize * 100 / StaticSize,"%) | ", + m_MaxDynamicSize, " (", m_MaxDynamicSize * 100 / DynamicSize, "%). Max stale size (static|dynamic): ", + m_MaxStaleSize, " (", m_MaxStaleSize * 100 / StaticSize, "%) | ", + m_MaxDynamicStaleSize, " (", m_MaxDynamicStaleSize * 100 / DynamicSize, "%)"); } DescriptorHeapAllocation GPUDescriptorHeap::Allocate(uint32_t Count) { - std::lock_guard LockGuard(m_Mutex); + // Note: this mutex may be redundant as DescriptorHeapAllocationManager::Allocate() is itself thread-safe + std::lock_guard LockGuard(m_AllocMutex); DescriptorHeapAllocation Allocation = m_HeapAllocationManager.Allocate(Count); m_CurrentSize += (Allocation.GetCpuHandle().ptr != 0) ? Count : 0; @@ -252,7 +309,8 @@ DescriptorHeapAllocation GPUDescriptorHeap::Allocate(uint32_t Count) DescriptorHeapAllocation GPUDescriptorHeap::AllocateDynamic(uint32_t Count) { - std::lock_guard LockGuard(m_Mutex); + // Note: this mutex may be redundant as DescriptorHeapAllocationManager::Allocate() is itself thread-safe + std::lock_guard LockGuard(m_DynAllocMutex); DescriptorHeapAllocation Allocation = m_DynamicAllocationsManager.Allocate(Count); m_CurrentDynamicSize += (Allocation.GetCpuHandle().ptr != 0) ? Count : 0; @@ -266,24 +324,34 @@ void GPUDescriptorHeap::Free(DescriptorHeapAllocation&& Allocation) auto MgrId = Allocation.GetAllocationManagerId(); VERIFY(MgrId == 0 || MgrId == 1, "Unexpected allocation manager ID"); - std::lock_guard LockGuard(m_Mutex); - + // Note: mutexex may be redundant as DescriptorHeapAllocationManager::Free() is itself thread-safe if(MgrId == 0) { + std::lock_guard LockGuard(m_AllocMutex); m_CurrentSize -= static_cast(Allocation.GetNumHandles()); m_HeapAllocationManager.Free(std::move(Allocation)); } else { + std::lock_guard LockGuard(m_DynAllocMutex); m_CurrentDynamicSize -= static_cast(Allocation.GetNumHandles()); m_DynamicAllocationsManager.Free(std::move(Allocation)); } } -void GPUDescriptorHeap::ReleaseStaleAllocations(Uint64 NumCompletedFrames) +void GPUDescriptorHeap::ReleaseStaleAllocations(Uint64 NumCompletedCmdLists) { - m_HeapAllocationManager.ReleaseStaleAllocations(NumCompletedFrames); - m_DynamicAllocationsManager.ReleaseStaleAllocations(NumCompletedFrames); + { + std::lock_guard LockGuard(m_AllocMutex); + m_MaxStaleSize = std::max(m_MaxStaleSize, static_cast(m_HeapAllocationManager.GetNumStaleDescriptors())); + m_HeapAllocationManager.ReleaseStaleAllocations(NumCompletedCmdLists); + } + + { + std::lock_guard LockGuard(m_DynAllocMutex); + m_MaxDynamicStaleSize = std::max(m_MaxDynamicStaleSize, static_cast(m_DynamicAllocationsManager.GetNumStaleDescriptors())); + m_DynamicAllocationsManager.ReleaseStaleAllocations(NumCompletedCmdLists); + } } @@ -299,14 +367,21 @@ DynamicSuballocationsManager::DynamicSuballocationsManager(IMemoryAllocator &All void DynamicSuballocationsManager::DiscardAllocations(Uint64 FrameNumber) { + // Clear the list and dispose all allocated chunks of GPU descriptor heap. + // The chunks will be added to the release queue in the allocations manager m_Suballocations.clear(); } DescriptorHeapAllocation DynamicSuballocationsManager::Allocate(Uint32 Count) { + // This method is intentionally lock-free as it is expected to + // be called through device context from single thread only + + // Check if there are no chunks or the last chunk does not have enough space if( m_Suballocations.empty() || m_CurrentSuballocationOffset + Count > m_Suballocations.back().GetNumHandles() ) { + // Request a new chunk from the parent GPU descriptor heap auto SuballocationSize = std::max(m_DynamicChunkSize, Count); auto NewDynamicSubAllocation = m_ParentGPUHeap.AllocateDynamic(SuballocationSize); if (NewDynamicSubAllocation.GetCpuHandle().ptr == 0) @@ -318,6 +393,7 @@ DescriptorHeapAllocation DynamicSuballocationsManager::Allocate(Uint32 Count) m_CurrentSuballocationOffset = 0; } + // Perform suballocation from the last chunk auto &CurrentSuballocation = m_Suballocations.back(); auto ManagerId = CurrentSuballocation.GetAllocationManagerId(); @@ -335,7 +411,7 @@ DescriptorHeapAllocation DynamicSuballocationsManager::Allocate(Uint32 Count) void DynamicSuballocationsManager::Free(DescriptorHeapAllocation&& Allocation) { - // Do nothing + // Do nothing. Dynamic allocations are not disposed individually, but as whole chunks at the end of the frame Allocation = DescriptorHeapAllocation(); } diff --git a/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp index 5ebfb4b4..003a464b 100644 --- a/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp +++ b/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp @@ -1,4 +1,4 @@ -/* Copyright 2015-2016 Egor Yusov +/* Copyright 2015-2017 Egor Yusov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -507,7 +507,7 @@ namespace Diligent { if( m_pCurrCmdCtx ) { - VERIFY(!m_bIsDeferred, "Deferred contexts cannot executre command lists directly"); + VERIFY(!m_bIsDeferred, "Deferred contexts cannot execute command lists directly"); ValidatedCast(m_pDevice.RawPtr())->CloseAndExecuteCommandContext(m_pCurrCmdCtx); } diff --git a/Graphics/GraphicsEngineD3D12/src/DynamicUploadHeap.cpp b/Graphics/GraphicsEngineD3D12/src/DynamicUploadHeap.cpp index c747a731..12622465 100644 --- a/Graphics/GraphicsEngineD3D12/src/DynamicUploadHeap.cpp +++ b/Graphics/GraphicsEngineD3D12/src/DynamicUploadHeap.cpp @@ -1,4 +1,4 @@ -/* Copyright 2015-2016 Egor Yusov +/* Copyright 2015-2017 Egor Yusov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -72,15 +72,22 @@ namespace Diligent m_pBuffer->SetName(L"Upload Ring Buffer"); m_GpuVirtualAddress = m_pBuffer->GetGPUVirtualAddress(); - - if (AllowCPUAccess) + + if (AllowCPUAccess) { m_pBuffer->Map(0, nullptr, &m_CpuVirtualAddress); } + + LOG_INFO_MESSAGE("GPU ring buffer created. Size: ", MaxSize, "; GPU virtual address 0x", std::hex, m_GpuVirtualAddress) } void GPURingBuffer::Destroy() { + if(m_pBuffer) + { + LOG_INFO_MESSAGE("Destroying GPU ring buffer. Size: ", m_pBuffer->GetDesc().Width, "; GPU virtual address 0x", std::hex, m_GpuVirtualAddress) + } + if (m_CpuVirtualAddress) { m_pBuffer->Unmap(0, nullptr); @@ -106,11 +113,15 @@ namespace Diligent DynamicAllocation DynamicUploadHeap::Allocate(size_t SizeInBytes, size_t Alignment /*= DEFAULT_ALIGN*/) { - // This is very expensive! Currently other threads cannot allocate dynamic - // data while frame is being finished. + // Every device context has its own upload heap, so there is no need to lock //std::lock_guard Lock(m_Mutex); + // + // Deferred contexts must not update resources or map dynamic buffers + // across several frames! + // + const size_t AlignmentMask = Alignment - 1; // Assert that it's a power of two. VERIFY_EXPR((AlignmentMask & Alignment) == 0); @@ -125,15 +136,21 @@ namespace Diligent DynAlloc = m_RingBuffers.back().Allocate(AlignedSize); } #ifdef _DEBUG - DynAlloc.FrameNum = m_pDeviceD3D12->GetCurrentFrame(); + DynAlloc.FrameNum = m_pDeviceD3D12->GetCurrentFrameNumber(); #endif return DynAlloc; } void DynamicUploadHeap::FinishFrame(Uint64 FrameNum, Uint64 NumCompletedFrames) { + // Every device context has its own upload heap, so there is no need to lock //std::lock_guard Lock(m_Mutex); + // + // Deferred contexts must not update resources or map dynamic buffers + // across several frames! + // + size_t NumBuffsToDelete = 0; for(size_t Ind = 0; Ind < m_RingBuffers.size(); ++Ind) { @@ -145,7 +162,7 @@ namespace Diligent ++NumBuffsToDelete; } } - + if(NumBuffsToDelete) m_RingBuffers.erase(m_RingBuffers.begin(), m_RingBuffers.begin()+NumBuffsToDelete); } diff --git a/Graphics/GraphicsEngineD3D12/src/GenerateMips.cpp b/Graphics/GraphicsEngineD3D12/src/GenerateMips.cpp index 1784a89c..5ef672d4 100644 --- a/Graphics/GraphicsEngineD3D12/src/GenerateMips.cpp +++ b/Graphics/GraphicsEngineD3D12/src/GenerateMips.cpp @@ -1,4 +1,4 @@ -/* Copyright 2015-2016 Egor Yusov +/* Copyright 2015-2017 Egor Yusov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Graphics/GraphicsEngineD3D12/src/PipelineStateD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/PipelineStateD3D12Impl.cpp index c2ed2d83..c5e2cf4b 100644 --- a/Graphics/GraphicsEngineD3D12/src/PipelineStateD3D12Impl.cpp +++ b/Graphics/GraphicsEngineD3D12/src/PipelineStateD3D12Impl.cpp @@ -1,4 +1,4 @@ -/* Copyright 2015-2016 Egor Yusov +/* Copyright 2015-2017 Egor Yusov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -282,6 +282,8 @@ ShaderResourceCacheD3D12* PipelineStateD3D12Impl::CommitAndTransitionShaderResou } #endif + // If the shaders contain no resources or static resources only, shader resource binding may be null. + // In this case use special internal SRB object auto *pResBindingD3D12Impl = pShaderResourceBinding ? ValidatedCast(pShaderResourceBinding) : m_pDefaultShaderResBinding.get(); #ifdef VERIFY_SHADER_BINDINGS @@ -295,6 +297,7 @@ ShaderResourceCacheD3D12* PipelineStateD3D12Impl::CommitAndTransitionShaderResou } #endif + // First time only, copy static shader resources to the cache if(!pResBindingD3D12Impl->StaticResourcesInitialized()) pResBindingD3D12Impl->InitializeStaticResources(this); diff --git a/Graphics/GraphicsEngineD3D12/src/RenderDeviceD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/RenderDeviceD3D12Impl.cpp index 51c89306..d9fc8265 100644 --- a/Graphics/GraphicsEngineD3D12/src/RenderDeviceD3D12Impl.cpp +++ b/Graphics/GraphicsEngineD3D12/src/RenderDeviceD3D12Impl.cpp @@ -1,4 +1,4 @@ -/* Copyright 2015-2016 Egor Yusov +/* Copyright 2015-2017 Egor Yusov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -41,9 +41,10 @@ RenderDeviceD3D12Impl :: RenderDeviceD3D12Impl(IMemoryAllocator &RawMemAllocator m_pd3d12Device(pd3d12Device), m_pd3d12CmdQueue(pd3d12CmdQueue), m_EngineAttribs(CreationAttribs), - m_NextFenceValue(1), - m_LastCompletedFenceValue(0), - m_FenceEventHandle( CreateEvent(nullptr, false, false, nullptr) ), + m_CurrentFrameNumber(0), + m_NextCmdList(0), + m_NumCompletedCmdLists(0), + m_WaitForGPUEventHandle( CreateEvent(nullptr, false, false, nullptr) ), m_CmdListManager(this), m_CPUDescriptorHeaps { @@ -57,6 +58,11 @@ RenderDeviceD3D12Impl :: RenderDeviceD3D12Impl(IMemoryAllocator &RawMemAllocator {RawMemAllocator, this, CreationAttribs.GPUDescriptorHeapSize[0], CreationAttribs.GPUDescriptorHeapDynamicSize[0], D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE}, {RawMemAllocator, this, CreationAttribs.GPUDescriptorHeapSize[1], CreationAttribs.GPUDescriptorHeapDynamicSize[1], D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE} }, + m_DynamicDescriptorAllocationChunkSize + { + CreationAttribs.DynamicDescriptorAllocationChunkSize[0], // D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV + CreationAttribs.DynamicDescriptorAllocationChunkSize[1] // D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER + }, m_ContextPool(STD_ALLOCATOR_RAW_MEM(ContextPoolElemType, GetRawAllocator(), "Allocator for vector>")), m_AvailableContexts(STD_ALLOCATOR_RAW_MEM(CommandContext*, GetRawAllocator(), "Allocator for vector")), m_D3D12ObjReleaseQueue(STD_ALLOCATOR_RAW_MEM(ReleaseQueueElemType, GetRawAllocator(), "Allocator for queue")), @@ -68,22 +74,17 @@ RenderDeviceD3D12Impl :: RenderDeviceD3D12Impl(IMemoryAllocator &RawMemAllocator m_DeviceCaps.bSeparableProgramSupported = True; m_DeviceCaps.bMultithreadedResourceCreationSupported = True; - VERIFY_EXPR(m_FenceEventHandle != INVALID_HANDLE_VALUE); - - auto hr = pd3d12Device->CreateFence(0, D3D12_FENCE_FLAG_NONE, __uuidof(m_pFence), reinterpret_cast(static_cast(&m_pFence))); - VERIFY(SUCCEEDED(hr), "Failed to create fence"); - m_pFence->SetName(L"CommandListManager::m_pFence"); - m_pFence->Signal(m_LastCompletedFenceValue); + VERIFY_EXPR(m_WaitForGPUEventHandle != INVALID_HANDLE_VALUE); - hr = pd3d12Device->CreateFence(0, D3D12_FENCE_FLAG_NONE, __uuidof(m_pNumCompletedFramesFence), reinterpret_cast(static_cast(&m_pNumCompletedFramesFence))); - VERIFY(SUCCEEDED(hr), "Failed to create fence"); - m_pNumCompletedFramesFence->SetName(L"Last completed frame fence"); - m_pNumCompletedFramesFence->Signal(m_NumCompletedFrames); + auto hr = pd3d12Device->CreateFence(0, D3D12_FENCE_FLAG_NONE, __uuidof(m_pCompletedCmdListFence), reinterpret_cast(static_cast(&m_pCompletedCmdListFence))); + VERIFY(SUCCEEDED(hr), "Failed to create the fence"); + m_pCompletedCmdListFence->SetName(L"RenderDeviceD3D12Impl::m_pCompletedCmdListFence fence"); + m_pCompletedCmdListFence->Signal(m_NumCompletedCmdLists); // 0 cmd lists are completed } RenderDeviceD3D12Impl::~RenderDeviceD3D12Impl() { - // Finish current frame. This will release resources taken by previous frames, and + // Finish current frame. This will release resources taken by previous frames, and // will signal current frame as completed. If we do not call FinishFrame(), then // current frame will not be signaled as completed and the second call to FinishFrame() // will not release current frame's resources. @@ -92,7 +93,7 @@ RenderDeviceD3D12Impl::~RenderDeviceD3D12Impl() IdleGPU(); // Call FinishFrame() again to release all resources associated with the current frame FinishFrame(); - CloseHandle(m_FenceEventHandle); + CloseHandle(m_WaitForGPUEventHandle); //LinearAllocator::DestroyAll(); //DynamicDescriptorHeap::DestroyAll(); @@ -105,49 +106,69 @@ void RenderDeviceD3D12Impl::DisposeCommandContext(CommandContext* pCtx) m_AvailableContexts.push_back(pCtx); } -Uint64 RenderDeviceD3D12Impl::CloseAndExecuteCommandContext(CommandContext *pCtx) +void RenderDeviceD3D12Impl::CloseAndExecuteCommandContext(CommandContext *pCtx) { CComPtr pAllocator; auto *pCmdList = pCtx->Close(&pAllocator); - uint64_t FenceValue = 0; + Uint64 SubmittedCmdListNum = 0; { - std::lock_guard LockGuard(m_FenceMutex); + std::lock_guard LockGuard(m_CmdQueueMutex); - // Kickoff the command list + // Submit the command list to the queue ID3D12CommandList *const ppCmdLists[] = {pCmdList}; m_pd3d12CmdQueue->ExecuteCommandLists(1, ppCmdLists); - // Signal the next fence value (with the GPU) - m_pd3d12CmdQueue->Signal(m_pFence, m_NextFenceValue); + // Increment the counter before signaling the fence. + SubmittedCmdListNum = m_NextCmdList; + Atomics::AtomicIncrement(m_NextCmdList); - // And increment the fence value. - FenceValue = m_NextFenceValue++; + // Signal the fence value. Note that for cmd list N that has just been submitted, + // we are signaling value N+1, that has a meaning of the TOTAL NUMBER OF COMPLETED + // cmd lists rather than the index number of the LAST completed cmd list. + // This is convenient as the natural default fence value of 0 + // corresponds to no completed cmd lists + m_pd3d12CmdQueue->Signal(m_pCompletedCmdListFence, m_NextCmdList); } - m_CmdListManager.DiscardAllocator(FenceValue, pAllocator); - pCtx->DiscardUsedDescriptorHeaps(m_CurrentFrame); + // DiscardAllocator() is thread-safe + m_CmdListManager.DiscardAllocator(SubmittedCmdListNum, pAllocator); + + // m_NextCmdList may be different at this point, which does not matter. + // SubmittedCmdListNum stores the actual number when the command list + // was sent for executrion + pCtx->DiscardDynamicDescriptors(SubmittedCmdListNum); { std::lock_guard LockGuard(m_ContextAllocationMutex); m_AvailableContexts.push_back(pCtx); } - - return FenceValue; } -Uint64 RenderDeviceD3D12Impl::IncrementFence(void) -{ - std::lock_guard LockGuard(m_FenceMutex); - m_pd3d12CmdQueue->Signal(m_pFence, m_NextFenceValue); - return m_NextFenceValue++; -} - void RenderDeviceD3D12Impl::IdleGPU(bool ReleasePendingObjects) { - auto FenceValue = IncrementFence(); - WaitForFence(FenceValue); + // We must lock the command queue to avoid other threads interfering with the GPU + std::lock_guard LockGuard(m_CmdQueueMutex); + + // Simulate execution of an empty command list + + // Increment the counter before signaling the fence. + Atomics::AtomicIncrement(m_NextCmdList); + + // Signal the fence value. Note that for cmd list N that has just been submitted, + // we are signaling value N+1, that has a meaning of the TOTAL NUMBER OF COMPLETED cmd lists + m_pd3d12CmdQueue->Signal(m_pCompletedCmdListFence, m_NextCmdList); + + // Wait for the fence + m_pCompletedCmdListFence->SetEventOnCompletion(m_NextCmdList, m_WaitForGPUEventHandle); + WaitForSingleObject(m_WaitForGPUEventHandle, INFINITE); + + VERIFY(GetNumCompletedCmdLists() == m_NextCmdList, "Unexpected number of completed cmd lists"); + + // Note: release queues may now contain objects released during the current frame + // that have cmd list number (m_NextCmdList-1) + if(ReleasePendingObjects) { // Do not wait until the end of the frame and force deletion. @@ -158,74 +179,63 @@ void RenderDeviceD3D12Impl::IdleGPU(bool ReleasePendingObjects) } } - -bool RenderDeviceD3D12Impl::IsFenceComplete(Uint64 FenceValue) +Uint64 RenderDeviceD3D12Impl::GetNumCompletedCmdLists() { - // Avoid querying the fence value by testing against the last one seen. - // The max() is to protect against an unlikely race condition that could cause the last - // completed fence value to regress. - if (FenceValue > m_LastCompletedFenceValue) - m_LastCompletedFenceValue = std::max(m_LastCompletedFenceValue, m_pFence->GetCompletedValue()); + auto NumCompletedCmdLists = m_pCompletedCmdListFence->GetCompletedValue(); + if(NumCompletedCmdLists > m_NumCompletedCmdLists) + m_NumCompletedCmdLists = NumCompletedCmdLists; - return FenceValue <= m_LastCompletedFenceValue; + return m_NumCompletedCmdLists; } -Uint64 RenderDeviceD3D12Impl::FinishFrame() +void RenderDeviceD3D12Impl::FinishFrame() { - m_NumCompletedFrames = std::max(m_NumCompletedFrames, m_pNumCompletedFramesFence->GetCompletedValue()); - for (auto &UploadHeap : m_UploadHeaps) + auto NumCompletedCmdLists = GetNumCompletedCmdLists(); + { - // Currently upload heaps are free-threaded, so other threads must not allocate - // resources at the same time - UploadHeap->FinishFrame(m_CurrentFrame, m_NumCompletedFrames); + // There is no need to lock as new heaps are only created during initialization + // time for every context + //std::lock_guard LockGuard(m_UploadHeapMutex); + + // Upload heaps are 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, so can + // performed in parallel across frame boundaries + for (auto &UploadHeap : m_UploadHeaps) + { + // Currently upload heaps are free-threaded, so other threads must not allocate + // resources at the same time. This means that all dynamic buffers must be unmaped + // in the same frame and all resources must be updated within boundaries of a single frame. + // + // worker thread 2 | pDevice->CrateTexture(InitData) | | pDevice->CrateBuffer(InitData) | | pDevice->CrateTexture(InitData) | + // + // worker thread 2 | pDfrdCtx2->UpdateResource() | || + // || + // worker thread 1 | pDfrdCtx1->Map(WRITE_DISCARD) | | pDfrdCtx1->UpdateResource() | || + // || + // main thread | pCtx->Map(WRITE_DISCARD )| | pCtx->UpdateResource() | || | Present() | + // + // + UploadHeap->FinishFrame(GetNextCmdListNumber(), NumCompletedCmdLists); + } } for(Uint32 CPUHeap=0; CPUHeap < _countof(m_CPUDescriptorHeaps); ++CPUHeap) { - m_CPUDescriptorHeaps[CPUHeap].ReleaseStaleAllocations(m_NumCompletedFrames); + // This is OK if other thread disposes descriptor heap allocation at this time + // The allocation will be registered as part of the current frame + m_CPUDescriptorHeaps[CPUHeap].ReleaseStaleAllocations(NumCompletedCmdLists); } for(Uint32 GPUHeap=0; GPUHeap < _countof(m_GPUDescriptorHeaps); ++GPUHeap) { - m_GPUDescriptorHeaps[GPUHeap].ReleaseStaleAllocations(m_NumCompletedFrames); + m_GPUDescriptorHeaps[GPUHeap].ReleaseStaleAllocations(NumCompletedCmdLists); } ProcessReleaseQueue(); - // How does this work in a multi-threaded environment?? - auto CompletedFrame = m_CurrentFrame++; - m_pd3d12CmdQueue->Signal(m_pNumCompletedFramesFence, m_CurrentFrame); - return CompletedFrame; -} - -bool RenderDeviceD3D12Impl::IsFrameComplete(Uint64 Frame) -{ - // Avoid querying the fence value by testing against the last one seen. - // The max() is to protect against an unlikely race condition that could cause the last - // completed fence value to regress. - if (Frame > m_NumCompletedFrames) - m_NumCompletedFrames = std::max(m_NumCompletedFrames, m_pNumCompletedFramesFence->GetCompletedValue()); - - return Frame <= m_NumCompletedFrames; -} - -void RenderDeviceD3D12Impl::WaitForFence(Uint64 FenceValue) -{ - if (IsFenceComplete(FenceValue)) - return; - - // TODO: Think about how this might affect a multi-threaded situation. Suppose thread A - // wants to wait for fence 100, then thread B comes along and wants to wait for 99. If - // the fence can only have one event set on completion, then thread B has to wait for - // 100 before it knows 99 is ready. Maybe insert sequential events? - { - std::lock_guard LockGuard(m_EventMutex); - - m_pFence->SetEventOnCompletion(FenceValue, m_FenceEventHandle); - WaitForSingleObject(m_FenceEventHandle, INFINITE); - m_LastCompletedFenceValue = FenceValue; - } + Atomics::AtomicIncrement(m_CurrentFrameNumber); } DynamicUploadHeap* RenderDeviceD3D12Impl::RequestUploadHeap() @@ -257,10 +267,9 @@ CommandContext* RenderDeviceD3D12Impl::AllocateCommandContext(const Char *ID) CommandContext* ret = nullptr; if (m_AvailableContexts.empty()) { - Uint32 DynamicDescriptorAllocationChunkSize[] = {256, 32}; auto &CmdCtxAllocator = GetRawAllocator(); auto *pRawMem = ALLOCATE(CmdCtxAllocator, "CommandContext instance", sizeof(CommandContext)); - ret = new (pRawMem) CommandContext( GetRawAllocator(), m_CmdListManager, m_GPUDescriptorHeaps, DynamicDescriptorAllocationChunkSize); + ret = new (pRawMem) CommandContext( GetRawAllocator(), m_CmdListManager, m_GPUDescriptorHeaps, m_DynamicDescriptorAllocationChunkSize); m_ContextPool.emplace_back(ret, STDDeleterRawMem(CmdCtxAllocator) ); } else @@ -280,19 +289,21 @@ CommandContext* RenderDeviceD3D12Impl::AllocateCommandContext(const Char *ID) void RenderDeviceD3D12Impl::SafeReleaseD3D12Object(ID3D12Object* pObj) { std::lock_guard LockGuard(m_ReleasedObjectsMutex); - m_D3D12ObjReleaseQueue.emplace_back( m_CurrentFrame, CComPtr(pObj) ); + m_D3D12ObjReleaseQueue.emplace_back( GetNextCmdListNumber(), CComPtr(pObj) ); } void RenderDeviceD3D12Impl::ProcessReleaseQueue(bool ForceRelease) { std::lock_guard LockGuard(m_ReleasedObjectsMutex); - // Release all objects whose frame number value < number of completed frames - while (m_D3D12ObjReleaseQueue.size()) + auto NumCompletedCmdLists = GetNumCompletedCmdLists(); + // Release all objects whose cmd list number value < number of completed cmd lists + // See http://diligentgraphics.com/diligent-engine/architecture/d3d12/managing-resource-lifetimes/ + while (!m_D3D12ObjReleaseQueue.empty()) { auto &FirstObj = m_D3D12ObjReleaseQueue.front(); // GPU must have been idled when ForceRelease == true - if (FirstObj.first < m_NumCompletedFrames || ForceRelease) + if (FirstObj.first < NumCompletedCmdLists || ForceRelease) m_D3D12ObjReleaseQueue.pop_front(); else break; diff --git a/Graphics/GraphicsEngineD3D12/src/RenderDeviceFactoryD3D12.cpp b/Graphics/GraphicsEngineD3D12/src/RenderDeviceFactoryD3D12.cpp index 762e8a03..db7164dc 100644 --- a/Graphics/GraphicsEngineD3D12/src/RenderDeviceFactoryD3D12.cpp +++ b/Graphics/GraphicsEngineD3D12/src/RenderDeviceFactoryD3D12.cpp @@ -1,4 +1,4 @@ -/* Copyright 2015-2016 Egor Yusov +/* Copyright 2015-2017 Egor Yusov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -179,7 +179,7 @@ void CreateDeviceAndContextsD3D12( const EngineD3D12Attribs& CreationAttribs, #ifndef RELEASE // Prevent the GPU from overclocking or underclocking to get consistent timings - d3d12Device->SetStablePowerState(TRUE); + //d3d12Device->SetStablePowerState(TRUE); #endif // Describe and create the command queue. diff --git a/Graphics/GraphicsEngineD3D12/src/RootSignature.cpp b/Graphics/GraphicsEngineD3D12/src/RootSignature.cpp index 2cecfdac..8be68df4 100644 --- a/Graphics/GraphicsEngineD3D12/src/RootSignature.cpp +++ b/Graphics/GraphicsEngineD3D12/src/RootSignature.cpp @@ -1,4 +1,4 @@ -/* Copyright 2015-2016 Egor Yusov +/* Copyright 2015-2017 Egor Yusov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -74,7 +74,7 @@ D3D12_DESCRIPTOR_RANGE* RootSignature::RootParamsManager::Extend(Uint32 NumExtra pCurrDescriptorRangePtr += NumRanges; } - // Copy existing root view to new memory + // Copy existing root views to new memory for (Uint32 rv = 0; rv < m_NumRootViews; ++rv) { const auto &SrcView = GetRootView(rv); @@ -236,47 +236,72 @@ void RootSignature::InitStaticSampler(SHADER_TYPE ShaderType, const String &Text } } -void RootSignature::AllocateResourceSlot(SHADER_TYPE ShaderType, const D3DShaderResourceAttribs &ShaderResAttribs, D3D12_DESCRIPTOR_RANGE_TYPE RangeType, Uint32 &RootIndex, Uint32 &OffsetFromTableStart) +// http://diligentgraphics.com/diligent-engine/architecture/d3d12/shader-resource-layout#Initializing-Shader-Resource-Layouts-and-Root-Signature-in-a-Pipeline-State-Object +void RootSignature::AllocateResourceSlot(SHADER_TYPE ShaderType, + const D3DShaderResourceAttribs &ShaderResAttribs, + D3D12_DESCRIPTOR_RANGE_TYPE RangeType, + Uint32 &RootIndex, // Output parameter + Uint32 &OffsetFromTableStart // Output parameter + ) { auto ShaderInd = GetShaderTypeIndex(ShaderType); auto ShaderVisibility = GetShaderVisibility(ShaderType); if (RangeType == D3D12_DESCRIPTOR_RANGE_TYPE_CBV && ShaderResAttribs.BindCount == 1) { - // Allocate CBV directly in the root signature - RootIndex = m_RootParams.GetNumRootTables() + m_RootParams.GetNumRootViews(); + // Allocate single CBV directly in the root signature + + // Get the next available root index past all allocated tables and root views + RootIndex = m_RootParams.GetNumRootTables() + m_RootParams.GetNumRootViews(); OffsetFromTableStart = 0; + // Add new root view to existing root parameters m_RootParams.AddRootView(D3D12_ROOT_PARAMETER_TYPE_CBV, RootIndex, ShaderResAttribs.BindPoint, ShaderVisibility, ShaderResAttribs.GetVariableType()); } else { - // Use the same table for static and mutable resources. Mark table type as static (mutable is an equivalent option) + // Use the same table for static and mutable resources. Treat both as static auto RootTableType = (ShaderResAttribs.GetVariableType() == SHADER_VARIABLE_TYPE_DYNAMIC) ? SHADER_VARIABLE_TYPE_DYNAMIC : SHADER_VARIABLE_TYPE_STATIC; auto TableIndKey = ShaderInd * SHADER_VARIABLE_TYPE_NUM_TYPES + RootTableType; - auto &RootTableInd = (( RangeType == D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER ) ? m_SamplerRootTablesMap : m_SrvCbvUavRootTablesMap)[ TableIndKey ]; - if (RootTableInd == InvalidRootTableIndex) + // Get the table array index (this is not the root index!) + auto &RootTableArrayInd = (( RangeType == D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER ) ? m_SamplerRootTablesMap : m_SrvCbvUavRootTablesMap)[ TableIndKey ]; + if (RootTableArrayInd == InvalidRootTableIndex) { + // Root table has not been assigned to this combination yet + + // Get the next available root index past all allocated tables and root views RootIndex = m_RootParams.GetNumRootTables() + m_RootParams.GetNumRootViews(); VERIFY_EXPR(m_RootParams.GetNumRootTables() < 255); - RootTableInd = static_cast( m_RootParams.GetNumRootTables() ); + RootTableArrayInd = static_cast( m_RootParams.GetNumRootTables() ); + // Add root table with one single-descriptor range m_RootParams.AddRootTable(RootIndex, ShaderVisibility, RootTableType, 1); } else { - m_RootParams.AddDescriptorRanges(RootTableInd, 1); + // Add a new single-descriptor range to the existing table at index RootTableArrayInd + m_RootParams.AddDescriptorRanges(RootTableArrayInd, 1); } - - auto &CurrParam = m_RootParams.GetRootTable(RootTableInd); + + // Reference to either existing or just added table + auto &CurrParam = m_RootParams.GetRootTable(RootTableArrayInd); RootIndex = CurrParam.GetRootIndex(); const auto& d3d12RootParam = static_cast(CurrParam); VERIFY( d3d12RootParam.ShaderVisibility == ShaderVisibility, "Shader visibility is not correct" ); + // Descriptors are tightly packed, so the next descriptor offset is the + // current size of the table OffsetFromTableStart = CurrParam.GetDescriptorTableSize(); + // New just added range is the last range in the descriptor table Uint32 NewDescriptorRangeIndex = d3d12RootParam.DescriptorTable.NumDescriptorRanges-1; - CurrParam.SetDescriptorRange(NewDescriptorRangeIndex, RangeType, ShaderResAttribs.BindPoint, ShaderResAttribs.BindCount, 0, OffsetFromTableStart); + CurrParam.SetDescriptorRange(NewDescriptorRangeIndex, + RangeType, // Range type (CBV, SRV, UAV or SAMPLER) + ShaderResAttribs.BindPoint, // Shader register + ShaderResAttribs.BindCount, // Number of registers used (1 for non-array resources) + 0, // Register space. Always 0 for now + OffsetFromTableStart // Offset in descriptors from the table start + ); } } @@ -465,8 +490,12 @@ void RootSignature::Finalize(ID3D12Device *pd3d12Device) } } +//http://diligentgraphics.com/diligent-engine/architecture/d3d12/shader-resource-cache#Initializing-the-Cache-for-Shader-Resource-Binding-Object void RootSignature::InitResourceCache(RenderDeviceD3D12Impl *pDeviceD3D12Impl, ShaderResourceCacheD3D12& ResourceCache, IMemoryAllocator &CacheMemAllocator)const { + // Get root table size for every root index + // m_RootParams keeps root tables sorted by the array index, not the root index + // Root views are treated as one-descriptor tables std::vector > CacheTableSizes(m_RootParams.GetNumRootTables() + m_RootParams.GetNumRootViews(), 0, STD_ALLOCATOR_RAW_MEM(Uint32, GetRawAllocator(), "Allocator for vector") ); for(Uint32 rt = 0; rt < m_RootParams.GetNumRootTables(); ++rt) { @@ -479,8 +508,10 @@ void RootSignature::InitResourceCache(RenderDeviceD3D12Impl *pDeviceD3D12Impl, S auto &RootParam = m_RootParams.GetRootView(rv); CacheTableSizes[RootParam.GetRootIndex()] = 1; } + // Initialize resource cache to hold root tables ResourceCache.Initialize(CacheMemAllocator, static_cast(CacheTableSizes.size()), CacheTableSizes.data()); + // Allocate space in GPU-visible descriptor heap for static and mutable variables only Uint32 TotalSrvCbvUavDescriptors = m_TotalSrvCbvUavSlots[SHADER_VARIABLE_TYPE_STATIC] + m_TotalSrvCbvUavSlots[SHADER_VARIABLE_TYPE_MUTABLE]; @@ -495,6 +526,10 @@ void RootSignature::InitResourceCache(RenderDeviceD3D12Impl *pDeviceD3D12Impl, S if(TotalSamplerDescriptors) SamplerHeapSpace = pDeviceD3D12Impl->AllocateGPUDescriptors(D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, TotalSamplerDescriptors); + // Iterate through all root static/mutable tables and assign start offsets. The tables are tightly packed, so + // start offset of table N+1 is start offset of table N plus the size of table N. + // Root tables with dynamic resources as well as root views are not assigned space in GPU-visible allocation + // (root views are simply not processed) Uint32 SrvCbvUavTblStartOffset = 0; Uint32 SamplerTblStartOffset = 0; for(Uint32 rt = 0; rt < m_RootParams.GetNumRootTables(); ++rt) @@ -523,18 +558,18 @@ void RootSignature::InitResourceCache(RenderDeviceD3D12Impl *pDeviceD3D12Impl, S { if( HeapType == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV ) { - RootTableCache.TableStartOffset = SrvCbvUavTblStartOffset; + RootTableCache.m_TableStartOffset = SrvCbvUavTblStartOffset; SrvCbvUavTblStartOffset += TableSize; } else { - RootTableCache.TableStartOffset = SamplerTblStartOffset; + RootTableCache.m_TableStartOffset = SamplerTblStartOffset; SamplerTblStartOffset += TableSize; } } else { - VERIFY_EXPR(RootTableCache.TableStartOffset == ShaderResourceCacheD3D12::InvalidDescriptorOffset) + VERIFY_EXPR(RootTableCache.m_TableStartOffset == ShaderResourceCacheD3D12::InvalidDescriptorOffset) } } @@ -544,7 +579,8 @@ void RootSignature::InitResourceCache(RenderDeviceD3D12Impl *pDeviceD3D12Impl, S auto &RootParam = m_RootParams.GetRootView(rv); const auto& D3D12RootParam = static_cast(RootParam); auto &RootTableCache = ResourceCache.GetRootTable(RootParam.GetRootIndex()); - VERIFY_EXPR(RootTableCache.TableStartOffset == ShaderResourceCacheD3D12::InvalidDescriptorOffset) + // Root views are not assigned valid table start offset + VERIFY_EXPR(RootTableCache.m_TableStartOffset == ShaderResourceCacheD3D12::InvalidDescriptorOffset) SHADER_TYPE dbgShaderType = ShaderTypeFromShaderVisibility(D3D12RootParam.ShaderVisibility); VERIFY_EXPR(D3D12RootParam.ParameterType == D3D12_ROOT_PARAMETER_TYPE_CBV); diff --git a/Graphics/GraphicsEngineD3D12/src/SamplerD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/SamplerD3D12Impl.cpp index e6e95bac..0d443e85 100644 --- a/Graphics/GraphicsEngineD3D12/src/SamplerD3D12Impl.cpp +++ b/Graphics/GraphicsEngineD3D12/src/SamplerD3D12Impl.cpp @@ -1,4 +1,4 @@ -/* Copyright 2015-2016 Egor Yusov +/* Copyright 2015-2017 Egor Yusov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Graphics/GraphicsEngineD3D12/src/ShaderD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/ShaderD3D12Impl.cpp index fd43fa49..6e2b7484 100644 --- a/Graphics/GraphicsEngineD3D12/src/ShaderD3D12Impl.cpp +++ b/Graphics/GraphicsEngineD3D12/src/ShaderD3D12Impl.cpp @@ -1,4 +1,4 @@ -/* Copyright 2015-2016 Egor Yusov +/* Copyright 2015-2017 Egor Yusov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -50,6 +50,7 @@ ShaderD3D12Impl::ShaderD3D12Impl(FixedBlockMemoryAllocator& ShaderObjAllocator, m_pShaderResources.reset(pResources, STDDeleterRawMem(Allocator)); // Clone only static resources that will be set directly in the shader + // http://diligentgraphics.com/diligent-engine/architecture/d3d12/shader-resource-layout#Initializing-Special-Resource-Layout-for-Managing-Static-Shader-Resources SHADER_VARIABLE_TYPE VarTypes[] = {SHADER_VARIABLE_TYPE_STATIC}; m_StaticResLayout.Initialize(pRenderDeviceD3D12->GetD3D12Device(), m_pShaderResources, GetRawAllocator(), VarTypes, _countof(VarTypes), &m_ConstResCache, nullptr); } diff --git a/Graphics/GraphicsEngineD3D12/src/ShaderResourceBindingD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/ShaderResourceBindingD3D12Impl.cpp index 118707a2..737fd6f7 100644 --- a/Graphics/GraphicsEngineD3D12/src/ShaderResourceBindingD3D12Impl.cpp +++ b/Graphics/GraphicsEngineD3D12/src/ShaderResourceBindingD3D12Impl.cpp @@ -1,4 +1,4 @@ -/* Copyright 2015-2016 Egor Yusov +/* Copyright 2015-2017 Egor Yusov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -51,6 +51,7 @@ ShaderResourceBindingD3D12Impl::ShaderResourceBindingD3D12Impl( FixedBlockMemory auto &ShaderResLayoutDataAllocator = pPSO->GetShaderResourceLayoutDataAllocator(ShaderInd); + // http://diligentgraphics.com/diligent-engine/architecture/d3d12/shader-resource-layout#Initializing-Resource-Layouts-in-a-Shader-Resource-Binding-Object SHADER_VARIABLE_TYPE Types[] = {SHADER_VARIABLE_TYPE_STATIC, SHADER_VARIABLE_TYPE_MUTABLE, SHADER_VARIABLE_TYPE_DYNAMIC}; const auto &SrcLayout = pPSO->GetShaderResLayout(ShaderType); new (m_pResourceLayouts + s) ShaderResourceLayoutD3D12(*this, SrcLayout, ShaderResLayoutDataAllocator, Types, _countof(Types), m_ShaderResourceCache); diff --git a/Graphics/GraphicsEngineD3D12/src/ShaderResourceCacheD3D12.cpp b/Graphics/GraphicsEngineD3D12/src/ShaderResourceCacheD3D12.cpp index 700b49b5..0ac5ac16 100644 --- a/Graphics/GraphicsEngineD3D12/src/ShaderResourceCacheD3D12.cpp +++ b/Graphics/GraphicsEngineD3D12/src/ShaderResourceCacheD3D12.cpp @@ -1,4 +1,4 @@ -/* Copyright 2015-2016 Egor Yusov +/* Copyright 2015-2017 Egor Yusov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,13 +27,14 @@ namespace Diligent { + // http://diligentgraphics.com/diligent-engine/architecture/d3d12/shader-resource-cache#Cache-Structure void ShaderResourceCacheD3D12::Initialize(IMemoryAllocator &MemAllocator, Uint32 NumTables, Uint32 TableSizes[]) { // Memory layout: // __________________________________________________________ - // | m_pResources, m_NumResources | - // m_pMemory | | - // | | V + // m_pMemory | m_pResources, m_NumResources | + // | | | + // V | V // | RootTable[0] | .... | RootTable[Nrt-1] | Res[0] | ... | Res[n-1] | .... | Res[0] | ... | Res[m-1] | // | A // | | diff --git a/Graphics/GraphicsEngineD3D12/src/ShaderResourceLayoutD3D12.cpp b/Graphics/GraphicsEngineD3D12/src/ShaderResourceLayoutD3D12.cpp index 924131e4..092111f7 100644 --- a/Graphics/GraphicsEngineD3D12/src/ShaderResourceLayoutD3D12.cpp +++ b/Graphics/GraphicsEngineD3D12/src/ShaderResourceLayoutD3D12.cpp @@ -1,4 +1,4 @@ -/* Copyright 2015-2016 Egor Yusov +/* Copyright 2015-2017 Egor Yusov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -50,7 +50,12 @@ ShaderResourceLayoutD3D12::ShaderResourceLayoutD3D12(IObject &Owner, ShaderResourceLayoutD3D12::~ShaderResourceLayoutD3D12() { + // For some reason MS compiler generates this false warning: + // warning C4189: 'CbvSrvUav': local variable is initialized but not referenced +#pragma warning(push) +#pragma warning(disable : 4189) auto* CbvSrvUav = reinterpret_cast(m_ResourceBuffer.get()); +#pragma warning(pop) for(Uint32 r=0; r < GetTotalSrvCbvUavCount(); ++r) CbvSrvUav[r].~SRV_CBV_UAV(); @@ -92,9 +97,10 @@ void ShaderResourceLayoutD3D12::AllocateMemory(IMemoryAllocator &Allocator) m_Samplers = reinterpret_cast(reinterpret_cast(pRawMem) + TotalSrvCbvUav); } -// Clones layout from the reference layout +// Clones layout from the reference layout maintained by the pipeline state // Root indices and descriptor table offsets must be correct // Resource cache is not initialized. +// http://diligentgraphics.com/diligent-engine/architecture/d3d12/shader-resource-layout#Initializing-Resource-Layouts-in-a-Shader-Resource-Binding-Object ShaderResourceLayoutD3D12::ShaderResourceLayoutD3D12(IObject &Owner, const ShaderResourceLayoutD3D12& SrcLayout, IMemoryAllocator &ResourceLayoutDataAllocator, @@ -164,6 +170,8 @@ ShaderResourceLayoutD3D12::ShaderResourceLayoutD3D12(IObject &Owner, #endif } +// http://diligentgraphics.com/diligent-engine/architecture/d3d12/shader-resource-layout#Initializing-Shader-Resource-Layouts-and-Root-Signature-in-a-Pipeline-State-Object +// http://diligentgraphics.com/diligent-engine/architecture/d3d12/shader-resource-cache#Initializing-Shader-Resource-Layouts-in-a-Pipeline-State void ShaderResourceLayoutD3D12::Initialize(ID3D12Device *pd3d12Device, const std::shared_ptr& pSrcResources, IMemoryAllocator &LayoutDataAllocator, @@ -180,6 +188,7 @@ void ShaderResourceLayoutD3D12::Initialize(ID3D12Device *pd3d12Device, Uint32 AllowedTypeBits = GetAllowedTypeBits(AllowedVarTypes, NumAllowedTypes); + // Count number of resources to allocate all needed memory m_pResources->ProcessResources( AllowedVarTypes, NumAllowedTypes, @@ -226,7 +235,7 @@ void ShaderResourceLayoutD3D12::Initialize(ID3D12Device *pd3d12Device, Uint32 CurrCbvSrvUav[SHADER_VARIABLE_TYPE_NUM_TYPES] = {0,0,0}; Uint32 CurrSampler[SHADER_VARIABLE_TYPE_NUM_TYPES] = {0,0,0}; - int MaxBindPoint[4] = {-1, -1, -1, -1}; + Uint32 StaticResCacheTblSizes[4] = {0, 0, 0, 0}; auto AddResource = [&](const D3DShaderResourceAttribs &Attribs, CachedResourceType ResType, Uint32 SamplerId = SRV_CBV_UAV::InvalidSamplerId) { @@ -241,13 +250,20 @@ void ShaderResourceLayoutD3D12::Initialize(ID3D12Device *pd3d12Device, else { // If root signature is not provided - use artifial root signature to store - // static shader resources + // static shader resources: + // SRVs at root index D3D12_DESCRIPTOR_RANGE_TYPE_SRV (0) + // UAVs at root index D3D12_DESCRIPTOR_RANGE_TYPE_UAV (1) + // CBVs at root index D3D12_DESCRIPTOR_RANGE_TYPE_CBV (2) + // Samplers at root index D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER (3) + + // http://diligentgraphics.com/diligent-engine/architecture/d3d12/shader-resource-layout#Initializing-Special-Resource-Layout-for-Managing-Static-Shader-Resources + VERIFY_EXPR(m_pResourceCache != nullptr); RootIndex = DescriptorRangeType; Offset = Attribs.BindPoint; // Resources in the static resource cache are indexed by the bind point - MaxBindPoint[RootIndex] = std::max(MaxBindPoint[RootIndex], static_cast(Offset + Attribs.BindCount)); + StaticResCacheTblSizes[RootIndex] = std::max(StaticResCacheTblSizes[RootIndex], Offset + Attribs.BindCount); } VERIFY(RootIndex != SRV_CBV_UAV::InvalidRootIndex, "Root index must be valid") VERIFY(Offset != SRV_CBV_UAV::InvalidOffset, "Offset must be valid") @@ -299,15 +315,15 @@ void ShaderResourceLayoutD3D12::Initialize(ID3D12Device *pd3d12Device, VERIFY_EXPR(m_pResourceCache != nullptr); // We use the following artifial root signature: - // CBVs at root index D3D12_DESCRIPTOR_RANGE_TYPE_CBV, - // SRVs at root index D3D12_DESCRIPTOR_RANGE_TYPE_SRV, - // UAVs at root index D3D12_DESCRIPTOR_RANGE_TYPE_UAV, and - // Samplers at root index D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER + // SRVs at root index D3D12_DESCRIPTOR_RANGE_TYPE_SRV (0) + // UAVs at root index D3D12_DESCRIPTOR_RANGE_TYPE_UAV (1) + // CBVs at root index D3D12_DESCRIPTOR_RANGE_TYPE_CBV (2) + // Samplers at root index D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER (3) // Every resource is stored at offset that equals its bind point SamplerRootIndex = D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER; SamplerOffset = SrcSamplerAttribs.BindPoint; // Resources in the static resource cache are indexed by the bind point - MaxBindPoint[SamplerRootIndex] = std::max(MaxBindPoint[SamplerRootIndex], static_cast(SamplerOffset + SrcSamplerAttribs.BindCount)); + StaticResCacheTblSizes[SamplerRootIndex] = std::max(StaticResCacheTblSizes[SamplerRootIndex], SamplerOffset + SrcSamplerAttribs.BindCount); } VERIFY(SamplerRootIndex != Sampler::InvalidRootIndex, "Sampler root index must be valid") VERIFY(SamplerOffset != Sampler::InvalidOffset, "Sampler offset must be valid") @@ -346,20 +362,16 @@ void ShaderResourceLayoutD3D12::Initialize(ID3D12Device *pd3d12Device, if(m_pResourceCache) { + // Initialize resource cache to store static resources + // http://diligentgraphics.com/diligent-engine/architecture/d3d12/shader-resource-cache#Initializing-the-Cache-for-Static-Shader-Resources + // http://diligentgraphics.com/diligent-engine/architecture/d3d12/shader-resource-cache#Initializing-Shader-Objects VERIFY_EXPR(pRootSig == nullptr); - Uint32 CachedTblSizes[4] = - { - static_cast(MaxBindPoint[D3D12_DESCRIPTOR_RANGE_TYPE_SRV] + 1), - static_cast(MaxBindPoint[D3D12_DESCRIPTOR_RANGE_TYPE_UAV] + 1), - static_cast(MaxBindPoint[D3D12_DESCRIPTOR_RANGE_TYPE_CBV] + 1), - static_cast(MaxBindPoint[D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER] + 1) - }; - m_pResourceCache->Initialize(GetRawAllocator(), _countof(CachedTblSizes), CachedTblSizes); + m_pResourceCache->Initialize(GetRawAllocator(), _countof(StaticResCacheTblSizes), StaticResCacheTblSizes); #ifdef _DEBUG - m_pResourceCache->GetRootTable(D3D12_DESCRIPTOR_RANGE_TYPE_SRV).SetDebugAttribs(MaxBindPoint[D3D12_DESCRIPTOR_RANGE_TYPE_SRV] + 1, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, m_pResources->GetShaderType()); - m_pResourceCache->GetRootTable(D3D12_DESCRIPTOR_RANGE_TYPE_UAV).SetDebugAttribs(MaxBindPoint[D3D12_DESCRIPTOR_RANGE_TYPE_UAV] + 1, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, m_pResources->GetShaderType()); - m_pResourceCache->GetRootTable(D3D12_DESCRIPTOR_RANGE_TYPE_CBV).SetDebugAttribs(MaxBindPoint[D3D12_DESCRIPTOR_RANGE_TYPE_CBV] + 1, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, m_pResources->GetShaderType()); - m_pResourceCache->GetRootTable(D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER).SetDebugAttribs(MaxBindPoint[D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER] + 1, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, m_pResources->GetShaderType()); + m_pResourceCache->GetRootTable(D3D12_DESCRIPTOR_RANGE_TYPE_SRV).SetDebugAttribs(StaticResCacheTblSizes[D3D12_DESCRIPTOR_RANGE_TYPE_SRV], D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, m_pResources->GetShaderType()); + m_pResourceCache->GetRootTable(D3D12_DESCRIPTOR_RANGE_TYPE_UAV).SetDebugAttribs(StaticResCacheTblSizes[D3D12_DESCRIPTOR_RANGE_TYPE_UAV], D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, m_pResources->GetShaderType()); + m_pResourceCache->GetRootTable(D3D12_DESCRIPTOR_RANGE_TYPE_CBV).SetDebugAttribs(StaticResCacheTblSizes[D3D12_DESCRIPTOR_RANGE_TYPE_CBV], D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, m_pResources->GetShaderType()); + m_pResourceCache->GetRootTable(D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER).SetDebugAttribs(StaticResCacheTblSizes[D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER], D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, m_pResources->GetShaderType()); #endif } @@ -392,6 +404,8 @@ void ShaderResourceLayoutD3D12::InitVariablesHashMap() void ShaderResourceLayoutD3D12::SRV_CBV_UAV::CacheCB(IDeviceObject *pBuffer, ShaderResourceCacheD3D12::Resource& DstRes, Uint32 ArrayInd, D3D12_CPU_DESCRIPTOR_HANDLE ShdrVisibleHeapCPUDescriptorHandle) { + // http://diligentgraphics.com/diligent-engine/architecture/d3d12/shader-resource-cache#Binding-Objects-to-Shader-Variables + // We cannot use ValidatedCast<> here as the resource retrieved from the // resource mapping can be of wrong type RefCntAutoPtr pBuffD3D12(pBuffer, IID_BufferD3D12); @@ -399,10 +413,17 @@ void ShaderResourceLayoutD3D12::SRV_CBV_UAV::CacheCB(IDeviceObject *pBuffer, Sha { if( pBuffD3D12->GetDesc().BindFlags & BIND_UNIFORM_BUFFER ) { - if( Attribs.GetVariableType() != SHADER_VARIABLE_TYPE_DYNAMIC && DstRes.pObject != nullptr && DstRes.pObject != pBuffD3D12) + if( Attribs.GetVariableType() != SHADER_VARIABLE_TYPE_DYNAMIC && DstRes.pObject != nullptr ) { - auto VarTypeStr = GetShaderVariableTypeLiteralName(Attribs.GetVariableType()); - LOG_ERROR_MESSAGE( "Non-null constant buffer is already bound to ", VarTypeStr, " shader variable \"", Attribs.GetPrintName(ArrayInd), "\" in shader \"", m_ParentResLayout.GetShaderName(), "\". Attempring to bind another constant buffer is an error and may cause unpredicted behavior. Use another shader resource binding instance or mark shader variable as dynamic." ) + if(DstRes.pObject != pBuffD3D12) + { + auto VarTypeStr = GetShaderVariableTypeLiteralName(Attribs.GetVariableType()); + LOG_ERROR_MESSAGE( "Non-null constant buffer is already bound to ", VarTypeStr, " shader variable \"", Attribs.GetPrintName(ArrayInd), "\" in shader \"", m_ParentResLayout.GetShaderName(), "\". Attempring to bind another constant buffer is an error and will be ignored. Use another shader resource binding instance or mark shader variable as dynamic." ) + } + + // Do not update resource if one is already bound unless it is dynamic. This may be + // dangerous as CopyDescriptorsSimple() may interfere with GPU reading the same descriptor. + return; } DstRes.Type = GetResType(); @@ -411,6 +432,10 @@ void ShaderResourceLayoutD3D12::SRV_CBV_UAV::CacheCB(IDeviceObject *pBuffer, Sha if(ShdrVisibleHeapCPUDescriptorHandle.ptr != 0 ) { + // Dynamic resources are assigned descriptor in the GPU-visible heap at every draw call, and + // the descriptor is copied by the RootSignature when resources are committed + VERIFY(DstRes.pObject == nullptr, "Static and mutable resource descriptors must be copied only once"); + ID3D12Device *pd3d12Device = m_ParentResLayout.m_pd3d12Device; pd3d12Device->CopyDescriptorsSimple(1, ShdrVisibleHeapCPUDescriptorHandle, DstRes.CPUDescriptorHandle, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); } @@ -477,22 +502,33 @@ void ShaderResourceLayoutD3D12::SRV_CBV_UAV::CacheResourceView(IDeviceObject *pV return; } #endif - if( Attribs.GetVariableType() != SHADER_VARIABLE_TYPE_DYNAMIC && DstRes.pObject != nullptr && DstRes.pObject != pViewD3D12) + if( Attribs.GetVariableType() != SHADER_VARIABLE_TYPE_DYNAMIC && DstRes.pObject != nullptr ) { - auto VarTypeStr = GetShaderVariableTypeLiteralName(Attribs.GetVariableType()); - LOG_ERROR_MESSAGE( "Non-null resource is already bound to ", VarTypeStr, " shader variable \"", Attribs.GetPrintName(ArrayIndex), "\" in shader \"", m_ParentResLayout.GetShaderName(), "\". Attempting to bind another resource or null is an error and may cause unpredicted behavior. Use another shader resource binding instance or mark shader variable as dynamic." ); + if(DstRes.pObject != pViewD3D12) + { + auto VarTypeStr = GetShaderVariableTypeLiteralName(Attribs.GetVariableType()); + LOG_ERROR_MESSAGE( "Non-null resource is already bound to ", VarTypeStr, " shader variable \"", Attribs.GetPrintName(ArrayIndex), "\" in shader \"", m_ParentResLayout.GetShaderName(), "\". Attempting to bind another resource or null is an error and will be ignored. Use another shader resource binding instance or mark shader variable as dynamic." ); + } + + // Do not update resource if one is already bound unless it is dynamic. This may be + // dangerous as CopyDescriptorsSimple() may interfere with GPU reading the same descriptor. + return; } DstRes.Type = GetResType(); - DstRes.pObject = pViewD3D12; DstRes.CPUDescriptorHandle = pViewD3D12->GetCPUDescriptorHandle(); VERIFY(DstRes.CPUDescriptorHandle.ptr != 0, "No relevant D3D12 view") if(ShdrVisibleHeapCPUDescriptorHandle.ptr != 0) { + // Dynamic resources are assigned descriptor in the GPU-visible heap at every draw call, and + // the descriptor is copied by the RootSignature when resources are committed + VERIFY(DstRes.pObject == nullptr, "Static and mutable resource descriptors must be copied only once"); + ID3D12Device *pd3d12Device = m_ParentResLayout.m_pd3d12Device; pd3d12Device->CopyDescriptorsSimple(1, ShdrVisibleHeapCPUDescriptorHandle, DstRes.CPUDescriptorHandle, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); } + DstRes.pObject = pViewD3D12; BindSamplerProc(pViewD3D12); } @@ -504,7 +540,7 @@ void ShaderResourceLayoutD3D12::SRV_CBV_UAV::CacheResourceView(IDeviceObject *pV void ShaderResourceLayoutD3D12::Sampler::CacheSampler(ITextureViewD3D12 *pTexViewD3D12, Uint32 ArrayIndex, D3D12_CPU_DESCRIPTOR_HANDLE ShdrVisibleHeapCPUDescriptorHandle) { - auto &pResourceCache = m_ParentResLayout.m_pResourceCache; + auto *pResourceCache = m_ParentResLayout.m_pResourceCache; VERIFY(pResourceCache, "Resource cache is null"); VERIFY(Attribs.IsValidBindPoint(), "Invalid bind point"); VERIFY_EXPR(ArrayIndex < Attribs.BindCount); @@ -536,10 +572,17 @@ void ShaderResourceLayoutD3D12::Sampler::CacheSampler(ITextureViewD3D12 *pTexVie auto pSampler = pTexViewD3D12->GetSampler(); if( pSampler ) { - if( Attribs.GetVariableType() != SHADER_VARIABLE_TYPE_DYNAMIC && DstSam.pObject != nullptr && DstSam.pObject != pSampler) + if( Attribs.GetVariableType() != SHADER_VARIABLE_TYPE_DYNAMIC && DstSam.pObject != nullptr) { - auto VarTypeStr = GetShaderVariableTypeLiteralName(Attribs.GetVariableType()); - LOG_ERROR_MESSAGE( "Non-null sampler is already bound to ", VarTypeStr, " shader variable \"", Attribs.GetPrintName(ArrayIndex), "\" in shader \"", m_ParentResLayout.GetShaderName(), "\". Attempting to bind another sampler is an error and may cause unpredicted behavior. Use another shader resource binding instance or mark shader variable as dynamic." ) + if(DstSam.pObject != pSampler) + { + auto VarTypeStr = GetShaderVariableTypeLiteralName(Attribs.GetVariableType()); + LOG_ERROR_MESSAGE( "Non-null sampler is already bound to ", VarTypeStr, " shader variable \"", Attribs.GetPrintName(ArrayIndex), "\" in shader \"", m_ParentResLayout.GetShaderName(), "\". Attempting to bind another sampler is an error and will be ignored. Use another shader resource binding instance or mark shader variable as dynamic." ) + } + + // Do not update resource if one is already bound unless it is dynamic. This may be + // dangerous as CopyDescriptorsSimple() may interfere with GPU reading the same descriptor. + return; } DstSam.Type = CachedResourceType::Sampler; @@ -550,6 +593,10 @@ void ShaderResourceLayoutD3D12::Sampler::CacheSampler(ITextureViewD3D12 *pTexVie if(ShdrVisibleHeapCPUDescriptorHandle.ptr != 0) { + // Dynamic resources are assigned descriptor in the GPU-visible heap at every draw call, and + // the descriptor is copied by the RootSignature when resources are committed + VERIFY(DstSam.pObject == nullptr, "Static and mutable resource descriptors must be copied only once"); + ID3D12Device *pd3d12Device = m_ParentResLayout.m_pd3d12Device; pd3d12Device->CopyDescriptorsSimple(1, ShdrVisibleHeapCPUDescriptorHandle, DstSam.CPUDescriptorHandle, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER); } @@ -581,7 +628,7 @@ ShaderResourceLayoutD3D12::Sampler &ShaderResourceLayoutD3D12::GetAssignedSample void ShaderResourceLayoutD3D12::SRV_CBV_UAV::BindResource(IDeviceObject *pObj, Uint32 ArrayIndex, const ShaderResourceLayoutD3D12 *dbgResLayout) { - auto &pResourceCache = m_ParentResLayout.m_pResourceCache; + auto *pResourceCache = m_ParentResLayout.m_pResourceCache; VERIFY(pResourceCache, "Resource cache is null"); VERIFY(dbgResLayout == nullptr || pResourceCache == dbgResLayout->m_pResourceCache, "Invalid resource cache"); VERIFY_EXPR(ArrayIndex < Attribs.BindCount); @@ -674,7 +721,7 @@ void ShaderResourceLayoutD3D12::SRV_CBV_UAV::BindResource(IDeviceObject *pObj, U bool ShaderResourceLayoutD3D12::SRV_CBV_UAV::IsBound(Uint32 ArrayIndex) { - auto &pResourceCache = m_ParentResLayout.m_pResourceCache; + auto *pResourceCache = m_ParentResLayout.m_pResourceCache; VERIFY(pResourceCache, "Resource cache is null"); VERIFY_EXPR(ArrayIndex < Attribs.BindCount); @@ -708,7 +755,6 @@ void ShaderResourceLayoutD3D12::BindResources( IResourceMapping* pResourceMappin return; } - // Bind constant buffers Uint32 TotalResources = GetTotalSrvCbvUavCount(); for(Uint32 r=0; r < TotalResources; ++r) { @@ -793,16 +839,21 @@ void ShaderResourceLayoutD3D12::CopyStaticResourceDesriptorHandles(const ShaderR for(Uint32 r=0; r < m_NumCbvSrvUav[SHADER_VARIABLE_TYPE_STATIC]; ++r) { + // Get resource attributes const auto &res = GetSrvCbvUav(SHADER_VARIABLE_TYPE_STATIC, r); VERIFY(SrcLayout.m_pResources->GetShaderType() == m_pResources->GetShaderType(), "Incosistent shader types") auto RangeType = GetDescriptorRangeType(res.GetResType()); for(Uint32 ArrInd = 0; ArrInd < res.Attribs.BindCount; ++ArrInd) { auto BindPoint = res.Attribs.BindPoint + ArrInd; - // Static resources are indexed in the resource cache by its bind point + // Source resource in the static resource cache is in the root table at index RangeType, at offset BindPoint + // D3D12_DESCRIPTOR_RANGE_TYPE_SRV = 0, + // D3D12_DESCRIPTOR_RANGE_TYPE_UAV = 1 + // D3D12_DESCRIPTOR_RANGE_TYPE_CBV = 2 const auto &SrcRes = SrcLayout.m_pResourceCache->GetRootTable(RangeType).GetResource(BindPoint, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, SrcLayout.m_pResources->GetShaderType()); if( !SrcRes.pObject ) LOG_ERROR_MESSAGE( "No resource assigned to static shader variable \"", res.Attribs.GetPrintName(ArrInd), "\" in shader \"", GetShaderName(), "\"." ); + // Destination resource is at the root index and offset defined by the resource layout auto &DstRes = m_pResourceCache->GetRootTable(res.GetRootIndex()).GetResource(res.OffsetFromTableStart + ArrInd, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, m_pResources->GetShaderType()); if(DstRes.pObject != SrcRes.pObject) @@ -815,6 +866,7 @@ void ShaderResourceLayoutD3D12::CopyStaticResourceDesriptorHandles(const ShaderR auto ShdrVisibleHeapCPUDescriptorHandle = m_pResourceCache->GetShaderVisibleTableCPUDescriptorHandle(res.GetRootIndex(), res.OffsetFromTableStart + ArrInd); VERIFY_EXPR(ShdrVisibleHeapCPUDescriptorHandle.ptr != 0 || DstRes.Type == CachedResourceType::CBV); + // Root views are not assigned space in the GPU-visible descriptor heap allocation if (ShdrVisibleHeapCPUDescriptorHandle.ptr != 0) { m_pd3d12Device->CopyDescriptorsSimple(1, ShdrVisibleHeapCPUDescriptorHandle, SrcRes.CPUDescriptorHandle, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); @@ -840,7 +892,8 @@ void ShaderResourceLayoutD3D12::CopyStaticResourceDesriptorHandles(const ShaderR for(Uint32 ArrInd = 0; ArrInd < SamInfo.Attribs.BindCount; ++ArrInd) { auto BindPoint = SamInfo.Attribs.BindPoint + ArrInd; - // Static resources are indexed by the bind point in the resource cache + // Source sampler in the static resource cache is in the root table at index 3 + // (D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER = 3), at offset BindPoint auto& SrcSampler = SrcLayout.m_pResourceCache->GetRootTable(D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER).GetResource(BindPoint, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, SrcLayout.m_pResources->GetShaderType()); if( !SrcSampler.pObject ) LOG_ERROR_MESSAGE( "No sampler assigned to static shader variable \"", res.Attribs.GetPrintName(ArrInd), "\" in shader \"", GetShaderName(), "\"." ); @@ -894,7 +947,8 @@ void ShaderResourceLayoutD3D12::dbgVerifyBindings()const VERIFY(CachedRes.Type == CachedResourceType::Unknown, "Unexpected cached resource types") if( !CachedRes.pObject || - (CachedRes.CPUDescriptorHandle.ptr == 0 && ValidatedCast(CachedRes.pObject.RawPtr())->GetDesc().Usage != USAGE_DYNAMIC) ) + // Dynamic buffers do not have CPU descriptor handle as they do not keep D3D12 buffer, and space is allocated from the GPU ring buffer + CachedRes.CPUDescriptorHandle.ptr == 0 && !(CachedRes.Type==CachedResourceType::CBV && ValidatedCast(CachedRes.pObject.RawPtr())->GetDesc().Usage == USAGE_DYNAMIC) ) LOG_ERROR_MESSAGE( "No resource is bound to ", GetShaderVariableTypeLiteralName(res.Attribs.GetVariableType()), " variable \"", res.Attribs.GetPrintName(ArrInd), "\" in shader \"", GetShaderName(), "\"" ) if (res.Attribs.BindCount > 1 && res.IsValidSampler()) @@ -944,7 +998,7 @@ void ShaderResourceLayoutD3D12::dbgVerifyBindings()const if (res.IsValidSampler()) { - VERIFY(res.GetResType() == CachedResourceType::TexSRV, "Sampler can only be assigned to texture SRV" ); + VERIFY(res.GetResType() == CachedResourceType::TexSRV, "Sampler can only be assigned to a texture SRV" ); const auto &SamInfo = const_cast(this)->GetAssignedSampler(res); VERIFY( !SamInfo.Attribs.IsStaticSampler(), "Static samplers should never be assigned space in the cache" ) VERIFY(SamInfo.Attribs.IsValidBindPoint(), "Sampler bind point must be valid") diff --git a/Graphics/GraphicsEngineD3D12/src/ShaderResourcesD3D12.cpp b/Graphics/GraphicsEngineD3D12/src/ShaderResourcesD3D12.cpp index e7543ce6..c42f663e 100644 --- a/Graphics/GraphicsEngineD3D12/src/ShaderResourcesD3D12.cpp +++ b/Graphics/GraphicsEngineD3D12/src/ShaderResourcesD3D12.cpp @@ -1,4 +1,4 @@ -/* Copyright 2015-2016 Egor Yusov +/* Copyright 2015-2017 Egor Yusov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Graphics/GraphicsEngineD3D12/src/SwapChainD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/SwapChainD3D12Impl.cpp index dad6639f..2e42ca44 100644 --- a/Graphics/GraphicsEngineD3D12/src/SwapChainD3D12Impl.cpp +++ b/Graphics/GraphicsEngineD3D12/src/SwapChainD3D12Impl.cpp @@ -1,4 +1,4 @@ -/* Copyright 2015-2016 Egor Yusov +/* Copyright 2015-2017 Egor Yusov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Graphics/GraphicsEngineD3D12/src/TextureD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/TextureD3D12Impl.cpp index d5ce27d7..8361421f 100644 --- a/Graphics/GraphicsEngineD3D12/src/TextureD3D12Impl.cpp +++ b/Graphics/GraphicsEngineD3D12/src/TextureD3D12Impl.cpp @@ -1,4 +1,4 @@ -/* Copyright 2015-2016 Egor Yusov +/* Copyright 2015-2017 Egor Yusov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Graphics/GraphicsEngineD3D12/src/TextureViewD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/TextureViewD3D12Impl.cpp index 0b93926b..57749298 100644 --- a/Graphics/GraphicsEngineD3D12/src/TextureViewD3D12Impl.cpp +++ b/Graphics/GraphicsEngineD3D12/src/TextureViewD3D12Impl.cpp @@ -1,4 +1,4 @@ -/* Copyright 2015-2016 Egor Yusov +/* Copyright 2015-2017 Egor Yusov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Graphics/GraphicsEngineD3D12/src/pch.cpp b/Graphics/GraphicsEngineD3D12/src/pch.cpp index 997e0f4a..d5f45c6a 100644 --- a/Graphics/GraphicsEngineD3D12/src/pch.cpp +++ b/Graphics/GraphicsEngineD3D12/src/pch.cpp @@ -1,4 +1,4 @@ -/* Copyright 2015-2016 Egor Yusov +/* Copyright 2015-2017 Egor Yusov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. -- cgit v1.2.3