summaryrefslogtreecommitdiffstats
path: root/Graphics/GraphicsEngineD3D12
diff options
context:
space:
mode:
authorEgor Yusov <egor.yusov@gmail.com>2017-05-20 21:00:37 +0000
committerEgor Yusov <egor.yusov@gmail.com>2017-05-20 21:00:37 +0000
commit109a75aac22463802f03dfc6588951ed0b04892a (patch)
tree51e121c71b7e8d30bab1eb400e21497677797a03 /Graphics/GraphicsEngineD3D12
parentResolved conflicts (diff)
downloadDiligentCore-109a75aac22463802f03dfc6588951ed0b04892a.tar.gz
DiligentCore-109a75aac22463802f03dfc6588951ed0b04892a.zip
Merge from dev branch
Diffstat (limited to 'Graphics/GraphicsEngineD3D12')
-rw-r--r--Graphics/GraphicsEngineD3D12/include/BufferD3D12Impl.h3
-rw-r--r--Graphics/GraphicsEngineD3D12/include/BufferViewD3D12Impl.h3
-rw-r--r--Graphics/GraphicsEngineD3D12/include/CommandContext.h242
-rw-r--r--Graphics/GraphicsEngineD3D12/include/CommandListD3D12Impl.h2
-rw-r--r--Graphics/GraphicsEngineD3D12/include/CommandListManager.h12
-rw-r--r--Graphics/GraphicsEngineD3D12/include/D3D12ResourceBase.h2
-rw-r--r--Graphics/GraphicsEngineD3D12/include/D3D12TypeConversions.h2
-rw-r--r--Graphics/GraphicsEngineD3D12/include/D3D12TypeDefinitions.h2
-rw-r--r--Graphics/GraphicsEngineD3D12/include/D3D12Utils.h2
-rw-r--r--Graphics/GraphicsEngineD3D12/include/DescriptorHeap.h220
-rw-r--r--Graphics/GraphicsEngineD3D12/include/DeviceContextD3D12Impl.h2
-rw-r--r--Graphics/GraphicsEngineD3D12/include/DynamicUploadHeap.h4
-rw-r--r--Graphics/GraphicsEngineD3D12/include/GenerateMips.h2
-rw-r--r--Graphics/GraphicsEngineD3D12/include/PipelineStateD3D12Impl.h2
-rw-r--r--Graphics/GraphicsEngineD3D12/include/RenderDeviceD3D12Impl.h87
-rw-r--r--Graphics/GraphicsEngineD3D12/include/RootSignature.h9
-rw-r--r--Graphics/GraphicsEngineD3D12/include/SamplerD3D12Impl.h2
-rw-r--r--Graphics/GraphicsEngineD3D12/include/ShaderD3D12Impl.h2
-rw-r--r--Graphics/GraphicsEngineD3D12/include/ShaderResourceBindingD3D12Impl.h2
-rw-r--r--Graphics/GraphicsEngineD3D12/include/ShaderResourceCacheD3D12.h69
-rw-r--r--Graphics/GraphicsEngineD3D12/include/ShaderResourceLayoutD3D12.h82
-rw-r--r--Graphics/GraphicsEngineD3D12/include/ShaderResourcesD3D12.h2
-rw-r--r--Graphics/GraphicsEngineD3D12/include/SwapChainD3D12Impl.h2
-rw-r--r--Graphics/GraphicsEngineD3D12/include/TextureD3D12Impl.h4
-rw-r--r--Graphics/GraphicsEngineD3D12/include/TextureViewD3D12Impl.h5
-rw-r--r--Graphics/GraphicsEngineD3D12/include/pch.h2
-rw-r--r--Graphics/GraphicsEngineD3D12/interface/BufferD3D12.h2
-rw-r--r--Graphics/GraphicsEngineD3D12/interface/BufferViewD3D12.h2
-rw-r--r--Graphics/GraphicsEngineD3D12/interface/PipelineStateD3D12.h2
-rw-r--r--Graphics/GraphicsEngineD3D12/interface/RenderDeviceD3D12.h2
-rw-r--r--Graphics/GraphicsEngineD3D12/interface/RenderDeviceFactoryD3D12.h2
-rw-r--r--Graphics/GraphicsEngineD3D12/interface/SamplerD3D12.h2
-rw-r--r--Graphics/GraphicsEngineD3D12/interface/ShaderD3D12.h2
-rw-r--r--Graphics/GraphicsEngineD3D12/interface/ShaderResourceBindingD3D12.h2
-rw-r--r--Graphics/GraphicsEngineD3D12/interface/SwapChainD3D12.h2
-rw-r--r--Graphics/GraphicsEngineD3D12/interface/TextureD3D12.h2
-rw-r--r--Graphics/GraphicsEngineD3D12/interface/TextureViewD3D12.h2
-rw-r--r--Graphics/GraphicsEngineD3D12/src/BufferD3D12Impl.cpp4
-rw-r--r--Graphics/GraphicsEngineD3D12/src/BufferViewD3D12Impl.cpp2
-rw-r--r--Graphics/GraphicsEngineD3D12/src/CommandContext.cpp147
-rw-r--r--Graphics/GraphicsEngineD3D12/src/CommandListManager.cpp27
-rw-r--r--Graphics/GraphicsEngineD3D12/src/D3D12ResourceBase.cpp2
-rw-r--r--Graphics/GraphicsEngineD3D12/src/D3D12TypeConversions.cpp2
-rw-r--r--Graphics/GraphicsEngineD3D12/src/D3D12Utils.cpp2
-rw-r--r--Graphics/GraphicsEngineD3D12/src/DLLMain.cpp2
-rw-r--r--Graphics/GraphicsEngineD3D12/src/DescriptorHeap.cpp122
-rw-r--r--Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp4
-rw-r--r--Graphics/GraphicsEngineD3D12/src/DynamicUploadHeap.cpp31
-rw-r--r--Graphics/GraphicsEngineD3D12/src/GenerateMips.cpp2
-rw-r--r--Graphics/GraphicsEngineD3D12/src/PipelineStateD3D12Impl.cpp5
-rw-r--r--Graphics/GraphicsEngineD3D12/src/RenderDeviceD3D12Impl.cpp195
-rw-r--r--Graphics/GraphicsEngineD3D12/src/RenderDeviceFactoryD3D12.cpp4
-rw-r--r--Graphics/GraphicsEngineD3D12/src/RootSignature.cpp70
-rw-r--r--Graphics/GraphicsEngineD3D12/src/SamplerD3D12Impl.cpp2
-rw-r--r--Graphics/GraphicsEngineD3D12/src/ShaderD3D12Impl.cpp3
-rw-r--r--Graphics/GraphicsEngineD3D12/src/ShaderResourceBindingD3D12Impl.cpp3
-rw-r--r--Graphics/GraphicsEngineD3D12/src/ShaderResourceCacheD3D12.cpp9
-rw-r--r--Graphics/GraphicsEngineD3D12/src/ShaderResourceLayoutD3D12.cpp134
-rw-r--r--Graphics/GraphicsEngineD3D12/src/ShaderResourcesD3D12.cpp2
-rw-r--r--Graphics/GraphicsEngineD3D12/src/SwapChainD3D12Impl.cpp2
-rw-r--r--Graphics/GraphicsEngineD3D12/src/TextureD3D12Impl.cpp2
-rw-r--r--Graphics/GraphicsEngineD3D12/src/TextureViewD3D12Impl.cpp2
-rw-r--r--Graphics/GraphicsEngineD3D12/src/pch.cpp2
63 files changed, 826 insertions, 746 deletions
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<DynamicAllocation, STDAllocatorRawMem<DynamicAllocation> > 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<ID3D12GraphicsCommandList> m_pCommandList;
CComPtr<ID3D12CommandAllocator> 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<ComputeContext&>(*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<Uint64, CComPtr<ID3D12CommandAllocator> > DiscardedAllocatorQueueElemType;
std::deque< DiscardedAllocatorQueueElemType, STDAllocatorRawMem<DiscardedAllocatorQueueElemType> > 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 <mutex>
@@ -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<Uint16>::max(), "DescriptorSize exceeds allowed limit")
- m_DescriptorSize = static_cast<Uint16>( DescriptorSize );
- }
-
- DescriptorHeapAllocation( IDescriptorAllocator *pAllocator, ID3D12DescriptorHeap *pHeap, D3D12_CPU_DESCRIPTOR_HANDLE CpuHandle, D3D12_GPU_DESCRIPTOR_HANDLE GpuHandle, Uint32 NHandles, Uint16 AllocationManagerId = static_cast<Uint16>(-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<Uint16>(-1) ) :
m_FirstCpuHandle(CpuHandle),
m_FirstGpuHandle(GpuHandle),
m_pAllocator(pAllocator),
@@ -86,6 +92,7 @@ public:
m_DescriptorSize = static_cast<Uint16>( 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<Uint16>(-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<IDescriptorAllocator> 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<Uint16>(-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<size_t>(-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<ID3D12DescriptorHeap> 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<size_t>(-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<DescriptorHeapAllocationManager, STDAllocatorRawMem<DescriptorHeapAllocationManager> > m_HeapPool;
+ // Indices of available descriptor heap managers
std::set<size_t, std::less<size_t>, STDAllocatorRawMem<size_t> > 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<ID3D12DescriptorHeap> 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<DescriptorHeapAllocation, STDAllocatorRawMem<DescriptorHeapAllocation> > 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<GPURingBuffer, STDAllocatorRawMem<GPURingBuffer> > 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<Uint64>(m_NextCmdList);}
+ Uint64 GetCurrentFrameNumber()const {return static_cast<Uint64>(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<ID3D12Fence> m_pFence;
- Uint64 m_NextFenceValue;
- Uint64 m_LastCompletedFenceValue;
- HANDLE m_FenceEventHandle;
-
- CComPtr<ID3D12Fence> 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<ID3D12Fence> m_pCompletedCmdListFence;
+
+ HANDLE m_WaitForGPUEventHandle;
+
CommandListManager m_CmdListManager;
typedef std::unique_ptr<CommandContext, STDDeleterRawMem<CommandContext> > 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<Uint8>(-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<Uint32>(-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<IDeviceObject> 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<D3D12_DESCRIPTOR_HEAP_TYPE HeapType>
@@ -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<const ShaderResourcesD3D12>& pSrcResources,
IMemoryAllocator &LayoutDataAllocator,
@@ -149,10 +160,10 @@ public:
// sizeof(SRV_CBV_UAV) == 32 (x64)
struct SRV_CBV_UAV : ShaderVariableD3DBase<ShaderResourceLayoutD3D12>
{
- 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<Uint16>(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<Uint16>(ResType) << RootIndBits) | (RootIndex & RootIndMask)),
SamplerId( static_cast<Uint16>(_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<typename TResourceViewType,
typename TViewTypeEnum,
@@ -247,16 +267,16 @@ public:
// sizeof(Sampler) == 24 (x64)
struct Sampler
{
- Sampler(const Sampler&) = delete;
- Sampler(Sampler&&) = delete;
+ Sampler(const Sampler&) = delete;
+ Sampler(Sampler&&) = delete;
Sampler& operator = (const Sampler&) = delete;
- Sampler& operator = (Sampler&&) = delete;
+ Sampler& operator = (Sampler&&) = delete;
const D3DShaderResourceAttribs &Attribs;
ShaderResourceLayoutD3D12 &m_ParentResLayout;
static const Uint32 InvalidRootIndex = static_cast<Uint32>(-1);
- static const Uint32 InvalidOffset = static_cast<Uint32>(-1);
+ static const Uint32 InvalidOffset = static_cast<Uint32>(-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<void, STDDeleterRawMem<void> > 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<ITextureD3D12, TextureViewD3D12Impl,
public:
typedef TextureBase<ITextureD3D12, TextureViewD3D12Impl, FixedBlockMemoryAllocator, FixedBlockMemoryAllocator> 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<RenderDeviceD3D12Impl>(GetDevice())->GetCurrentFrame();
+ auto CurrentFrame = ValidatedCast<RenderDeviceD3D12Impl>(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<std::mutex> LockGuard(m_AllocatorMutex);
- // That fence value indicates we are free to reset the allocator
- m_DiscardedAllocators.emplace_back( FenceValue, CComPtr<ID3D12CommandAllocator>(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<ID3D12CommandAllocator>(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<std::mutex> 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<Uint16>::max(), "ManagerID exceed allowed limit");
- DescriptorHeapAllocation Allocation( m_pParentAllocator, m_pd3d12DescriptorHeap, CPUHandle, GPUHandle, Count, static_cast<Uint16>(m_ThisManagerId));
-
- return Allocation;
+ VERIFY(m_ThisManagerId < std::numeric_limits<Uint16>::max(), "ManagerID exceeds 16-bit range");
+ return DescriptorHeapAllocation( m_pParentAllocator, m_pd3d12DescriptorHeap, CPUHandle, GPUHandle, Count, static_cast<Uint16>(m_ThisManagerId));
}
void DescriptorHeapAllocationManager::Free(DescriptorHeapAllocation&& Allocation)
{
std::lock_guard<std::mutex> 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<std::mutex> 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<std::mutex> 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<UINT>(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<std::mutex> LockGuard(m_AllocationMutex);
auto ManagerId = Allocation.GetAllocationManagerId();
m_CurrentSize -= static_cast<Uint32>(Allocation.GetNumHandles());
m_HeapPool[ManagerId].Free(std::move(Allocation));
}
-void CPUDescriptorHeap::ReleaseStaleAllocations(Uint64 NumCompletedFrames)
+void CPUDescriptorHeap::ReleaseStaleAllocations(Uint64 NumCompletedCmdLists)
{
std::lock_guard<std::mutex> 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<Uint32>(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<std::mutex> LockGuard(m_Mutex);
+ // Note: this mutex may be redundant as DescriptorHeapAllocationManager::Allocate() is itself thread-safe
+ std::lock_guard<std::mutex> 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<std::mutex> LockGuard(m_Mutex);
+ // Note: this mutex may be redundant as DescriptorHeapAllocationManager::Allocate() is itself thread-safe
+ std::lock_guard<std::mutex> 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<std::mutex> LockGuard(m_Mutex);
-
+ // Note: mutexex may be redundant as DescriptorHeapAllocationManager::Free() is itself thread-safe
if(MgrId == 0)
{
+ std::lock_guard<std::mutex> LockGuard(m_AllocMutex);
m_CurrentSize -= static_cast<Uint32>(Allocation.GetNumHandles());
m_HeapAllocationManager.Free(std::move(Allocation));
}
else
{
+ std::lock_guard<std::mutex> LockGuard(m_DynAllocMutex);
m_CurrentDynamicSize -= static_cast<Uint32>(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<std::mutex> LockGuard(m_AllocMutex);
+ m_MaxStaleSize = std::max(m_MaxStaleSize, static_cast<Uint32>(m_HeapAllocationManager.GetNumStaleDescriptors()));
+ m_HeapAllocationManager.ReleaseStaleAllocations(NumCompletedCmdLists);
+ }
+
+ {
+ std::lock_guard<std::mutex> LockGuard(m_DynAllocMutex);
+ m_MaxDynamicStaleSize = std::max(m_MaxDynamicStaleSize, static_cast<Uint32>(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<RenderDeviceD3D12Impl>(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<std::mutex> 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<std::mutex> 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<ShaderResourceBindingD3D12Impl>(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<unique_ptr<CommandContext>>")),
m_AvailableContexts(STD_ALLOCATOR_RAW_MEM(CommandContext*, GetRawAllocator(), "Allocator for vector<CommandContext*>")),
m_D3D12ObjReleaseQueue(STD_ALLOCATOR_RAW_MEM(ReleaseQueueElemType, GetRawAllocator(), "Allocator for queue<ReleaseQueueElemType>")),
@@ -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<void**>(static_cast<ID3D12Fence**>(&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<void**>(static_cast<ID3D12Fence**>(&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<void**>(static_cast<ID3D12Fence**>(&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<ID3D12CommandAllocator> pAllocator;
auto *pCmdList = pCtx->Close(&pAllocator);
- uint64_t FenceValue = 0;
+ Uint64 SubmittedCmdListNum = 0;
{
- std::lock_guard<std::mutex> LockGuard(m_FenceMutex);
+ std::lock_guard<std::mutex> 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<std::mutex> LockGuard(m_ContextAllocationMutex);
m_AvailableContexts.push_back(pCtx);
}
-
- return FenceValue;
}
-Uint64 RenderDeviceD3D12Impl::IncrementFence(void)
-{
- std::lock_guard<std::mutex> 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<std::mutex> 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<std::mutex> 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<std::mutex> 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<CommandContext>(CmdCtxAllocator) );
}
else
@@ -280,19 +289,21 @@ CommandContext* RenderDeviceD3D12Impl::AllocateCommandContext(const Char *ID)
void RenderDeviceD3D12Impl::SafeReleaseD3D12Object(ID3D12Object* pObj)
{
std::lock_guard<std::mutex> LockGuard(m_ReleasedObjectsMutex);
- m_D3D12ObjReleaseQueue.emplace_back( m_CurrentFrame, CComPtr<ID3D12Object>(pObj) );
+ m_D3D12ObjReleaseQueue.emplace_back( GetNextCmdListNumber(), CComPtr<ID3D12Object>(pObj) );
}
void RenderDeviceD3D12Impl::ProcessReleaseQueue(bool ForceRelease)
{
std::lock_guard<std::mutex> 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<Uint8>( m_RootParams.GetNumRootTables() );
+ RootTableArrayInd = static_cast<Uint8>( 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<const D3D12_ROOT_PARAMETER&>(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<Uint32, STDAllocatorRawMem<Uint32> > CacheTableSizes(m_RootParams.GetNumRootTables() + m_RootParams.GetNumRootViews(), 0, STD_ALLOCATOR_RAW_MEM(Uint32, GetRawAllocator(), "Allocator for vector<Uint32>") );
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<Uint32>(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<const D3D12_ROOT_PARAMETER&>(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<ShaderResourcesD3D12>(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<SRV_CBV_UAV*>(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<Sampler*>(reinterpret_cast<SRV_CBV_UAV*>(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<const ShaderResourcesD3D12>& 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<int>(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<int>(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<Uint32>(MaxBindPoint[D3D12_DESCRIPTOR_RANGE_TYPE_SRV] + 1),
- static_cast<Uint32>(MaxBindPoint[D3D12_DESCRIPTOR_RANGE_TYPE_UAV] + 1),
- static_cast<Uint32>(MaxBindPoint[D3D12_DESCRIPTOR_RANGE_TYPE_CBV] + 1),
- static_cast<Uint32>(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<BufferD3D12Impl> 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<D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV>(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<const BufferD3D12Impl>(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<const BufferD3D12Impl>(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<ShaderResourceLayoutD3D12*>(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.