Skip to content

Commit

Permalink
D3D12: moved dynamic buffer allocations to device context (close #420)
Browse files Browse the repository at this point in the history
  • Loading branch information
TheMostDiligent committed Feb 20, 2025
1 parent 164e9d6 commit a614507
Show file tree
Hide file tree
Showing 6 changed files with 148 additions and 107 deletions.
41 changes: 1 addition & 40 deletions Graphics/GraphicsEngineD3D12/include/BufferD3D12Impl.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2019-2022 Diligent Graphics LLC
* Copyright 2019-2025 Diligent Graphics LLC
* Copyright 2015-2019 Egor Yusov
*
* Licensed under the Apache License, Version 2.0 (the "License");
Expand Down Expand Up @@ -65,10 +65,6 @@ class BufferD3D12Impl final : public BufferBase<EngineD3D12ImplTraits>, public D

IMPLEMENT_QUERY_INTERFACE_IN_PLACE(IID_BufferD3D12, TBufferBase)

#ifdef DILIGENT_DEVELOPMENT
void DvpVerifyDynamicAllocation(const DeviceContextD3D12Impl* pCtx) const;
#endif

/// Implementation of IBufferD3D12::GetD3D12Buffer().
virtual ID3D12Resource* DILIGENT_CALL_TYPE GetD3D12Buffer(Uint64& DataStartByteOffset, IDeviceContext* pContext) override final;

Expand All @@ -91,24 +87,6 @@ class BufferD3D12Impl final : public BufferBase<EngineD3D12ImplTraits>, public D
/// Implementation of IBuffer::GetSparseProperties().
virtual SparseBufferProperties DILIGENT_CALL_TYPE GetSparseProperties() const override final;

__forceinline D3D12_GPU_VIRTUAL_ADDRESS GetGPUAddress(DeviceContextIndex ContextId, const DeviceContextD3D12Impl* pCtx) const
{
if (m_Desc.Usage == USAGE_DYNAMIC)
{
#ifdef DILIGENT_DEVELOPMENT
if (pCtx != nullptr)
{
DvpVerifyDynamicAllocation(pCtx);
}
#endif
return m_DynamicData[ContextId].GPUAddress;
}
else
{
return GetD3D12Resource()->GetGPUVirtualAddress();
}
}

__forceinline D3D12_GPU_VIRTUAL_ADDRESS GetGPUAddress()
{
VERIFY_EXPR(m_Desc.Usage != USAGE_DYNAMIC);
Expand All @@ -126,23 +104,6 @@ class BufferD3D12Impl final : public BufferBase<EngineD3D12ImplTraits>, public D
void CreateSRV(struct BufferViewDesc& SRVDesc, D3D12_CPU_DESCRIPTOR_HANDLE SRVDescriptor) const;

DescriptorHeapAllocation m_CBVDescriptorAllocation;

// Align the struct size to the cache line size to avoid false sharing
static constexpr size_t CacheLineSize = 64;
struct alignas(CacheLineSize) CtxDynamicData : D3D12DynamicAllocation
{
CtxDynamicData& operator=(const D3D12DynamicAllocation& Allocation)
{
*static_cast<D3D12DynamicAllocation*>(this) = Allocation;
return *this;
}
Uint8 Padding[CacheLineSize - sizeof(D3D12DynamicAllocation)] = {};
};
static_assert(sizeof(CtxDynamicData) == CacheLineSize, "Unexpected sizeof(CtxDynamicData)");

friend DeviceContextD3D12Impl;
// Array of dynamic allocations for every device context.
std::vector<CtxDynamicData, STDAllocatorRawMem<CtxDynamicData>> m_DynamicData;
};

} // namespace Diligent
41 changes: 40 additions & 1 deletion Graphics/GraphicsEngineD3D12/include/DeviceContextD3D12Impl.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2019-2024 Diligent Graphics LLC
* Copyright 2019-2025 Diligent Graphics LLC
* Copyright 2015-2019 Egor Yusov
*
* Licensed under the Apache License, Version 2.0 (the "License");
Expand Down Expand Up @@ -360,6 +360,12 @@ class DeviceContextD3D12Impl final : public DeviceContextNextGenBase<EngineD3D12
return *m_QueryMgr;
}

#ifdef DILIGENT_DEVELOPMENT
void DvpVerifyDynamicAllocation(const BufferD3D12Impl* pBuffer) const;
#endif
__forceinline D3D12_GPU_VIRTUAL_ADDRESS GetBufferGPUAddress(const BufferD3D12Impl* pBuffer, bool VerifyDynamicAllocation = true) const;
ID3D12Resource* GetDynamicBufferD3D12ResourceAndOffset(const BufferD3D12Impl* pBuffer, Uint64& DataStartByteOffset);

private:
void CommitD3D12IndexBuffer(GraphicsContext& GraphCtx, VALUE_TYPE IndexType);
void CommitD3D12VertexBuffers(GraphicsContext& GraphCtx);
Expand Down Expand Up @@ -510,6 +516,16 @@ class DeviceContextD3D12Impl final : public DeviceContextNextGenBase<EngineD3D12
};
std::unordered_map<MappedTextureKey, TextureUploadSpace, MappedTextureKey::Hasher> m_MappedTextures;

struct MappedBuffer
{
D3D12DynamicAllocation Allocation;
#ifdef DILIGENT_DEVELOPMENT
UniqueIdentifier DvpBufferUID = -1;
#endif
};
// NB: using absl::flat_hash_map<const BufferD3D12Impl*, MappedBuffer> is considerably slower.
std::vector<MappedBuffer> m_MappedBuffers;

Int32 m_ActiveQueriesCounter = 0;

std::vector<OptimizedClearValue> m_AttachmentClearValues;
Expand All @@ -522,4 +538,27 @@ class DeviceContextD3D12Impl final : public DeviceContextNextGenBase<EngineD3D12
DescriptorHeapAllocation m_NullRTV;
};

__forceinline D3D12_GPU_VIRTUAL_ADDRESS DeviceContextD3D12Impl::GetBufferGPUAddress(const BufferD3D12Impl* pBuffer, bool VerifyDynamicAllocation) const
{
VERIFY_EXPR(pBuffer != nullptr);

if (pBuffer->GetD3D12Resource() != nullptr)
{
return pBuffer->GetD3D12Resource()->GetGPUVirtualAddress();
}

#ifdef DILIGENT_DEVELOPMENT
if (VerifyDynamicAllocation)
{
DvpVerifyDynamicAllocation(pBuffer);
}
#endif

const Uint32 DynamicBufferId = pBuffer->GetDynamicBufferId();
VERIFY(DynamicBufferId != ~0u, "Dynamic buffer '", pBuffer->GetDesc().Name, "' does not have dynamic buffer ID");
return DynamicBufferId < m_MappedBuffers.size() ?
m_MappedBuffers[DynamicBufferId].Allocation.GPUAddress :
0;
}

} // namespace Diligent
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2019-2024 Diligent Graphics LLC
* Copyright 2019-2025 Diligent Graphics LLC
* Copyright 2015-2019 Egor Yusov
*
* Licensed under the Apache License, Version 2.0 (the "License");
Expand Down Expand Up @@ -50,6 +50,7 @@ namespace Diligent

class CommandContext;
struct D3DShaderResourceAttribs;
class DeviceContextD3D12Impl;

struct ImmutableSamplerAttribsD3D12
{
Expand Down Expand Up @@ -146,8 +147,8 @@ class PipelineResourceSignatureD3D12Impl final : public PipelineResourceSignatur
struct CommitCacheResourcesAttribs
{
ID3D12Device* const pd3d12Device;
CommandContext& Ctx;
const DeviceContextIndex DeviceCtxId;
CommandContext& CmdCtx;
const DeviceContextD3D12Impl* pDeviceCtx;
const bool IsCompute;
const ShaderResourceCacheD3D12* pResourceCache = nullptr;
Uint32 BaseRootIndex = ~0u;
Expand Down
49 changes: 7 additions & 42 deletions Graphics/GraphicsEngineD3D12/src/BufferD3D12Impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,22 +46,13 @@ BufferD3D12Impl::BufferD3D12Impl(IReferenceCounters* pRefCounters,
RenderDeviceD3D12Impl* pRenderDeviceD3D12,
const BufferDesc& BuffDesc,
const BufferData* pBuffData /*= nullptr*/) :
// clang-format off
TBufferBase
{
TBufferBase{
pRefCounters,
BuffViewObjMemAllocator,
pRenderDeviceD3D12,
BuffDesc,
false
},
m_DynamicData
(
BuffDesc.Usage == USAGE_DYNAMIC ? (pRenderDeviceD3D12->GetNumImmediateContexts() + pRenderDeviceD3D12->GetNumDeferredContexts()) : 0,
CtxDynamicData{},
STD_ALLOCATOR_RAW_MEM(D3D12DynamicAllocation, GetRawAllocator(), "Allocator for vector<DynamicAllocation>")
)
// clang-format on
false,
}
{
ValidateBufferInitData(m_Desc, pBuffData);

Expand All @@ -88,7 +79,6 @@ BufferD3D12Impl::BufferD3D12Impl(IReferenceCounters* pRefCounters,
// Dynamic upload heap buffer is always in D3D12_RESOURCE_STATE_GENERIC_READ state.

SetState(RESOURCE_STATE_GENERIC_READ);
VERIFY_EXPR(m_DynamicData.size() == pRenderDeviceD3D12->GetNumImmediateContexts() + pRenderDeviceD3D12->GetNumDeferredContexts());
}
else
{
Expand Down Expand Up @@ -308,22 +298,13 @@ BufferD3D12Impl::BufferD3D12Impl(IReferenceCounters* pRefCounters,
const BufferDesc& BuffDesc,
RESOURCE_STATE InitialState,
ID3D12Resource* pd3d12Buffer) :
// clang-format off
TBufferBase
{
TBufferBase{
pRefCounters,
BuffViewObjMemAllocator,
pRenderDeviceD3D12,
BufferDescFromD3D12Resource(BuffDesc, pd3d12Buffer),
false
},
m_DynamicData
(
BuffDesc.Usage == USAGE_DYNAMIC ? (pRenderDeviceD3D12->GetNumImmediateContexts() + pRenderDeviceD3D12->GetNumDeferredContexts()) : 0,
CtxDynamicData{},
STD_ALLOCATOR_RAW_MEM(D3D12DynamicAllocation, GetRawAllocator(), "Allocator for vector<DynamicAllocation>")
)
// clang-format on
false,
}
{
m_pd3d12Resource = pd3d12Buffer;
SetState(InitialState);
Expand Down Expand Up @@ -436,26 +417,10 @@ ID3D12Resource* BufferD3D12Impl::GetD3D12Buffer(Uint64& DataStartByteOffset, IDe
{
VERIFY(m_Desc.Usage == USAGE_DYNAMIC, "Dynamic buffer is expected");
DeviceContextD3D12Impl* pCtxD3D12 = ClassPtrCast<DeviceContextD3D12Impl>(pContext);
#ifdef DILIGENT_DEVELOPMENT
DvpVerifyDynamicAllocation(pCtxD3D12);
#endif
DeviceContextIndex ContextId = pCtxD3D12->GetContextId();
DataStartByteOffset = m_DynamicData[ContextId].Offset;
return m_DynamicData[ContextId].pBuffer;
return pCtxD3D12->GetDynamicBufferD3D12ResourceAndOffset(this, DataStartByteOffset);
}
}

#ifdef DILIGENT_DEVELOPMENT
void BufferD3D12Impl::DvpVerifyDynamicAllocation(const DeviceContextD3D12Impl* pCtx) const
{
DeviceContextIndex ContextId = pCtx->GetContextId();
Uint64 CurrentFrame = pCtx->GetFrameNumber();
DEV_CHECK_ERR(m_DynamicData[ContextId].GPUAddress != 0, "Dynamic buffer '", m_Desc.Name, "' has not been mapped before its first use. Context Id: ", ContextId, ". Note: memory for dynamic buffers is allocated when a buffer is mapped.");
DEV_CHECK_ERR(m_DynamicData[ContextId].DvpCtxFrameNumber == CurrentFrame, "Dynamic allocation of dynamic buffer '", m_Desc.Name, "' in frame ", CurrentFrame, " is out-of-date. Note: contents of all dynamic resources is discarded at the end of every frame. A buffer must be mapped before its first use in any frame.");
VERIFY(GetState() == RESOURCE_STATE_GENERIC_READ, "Dynamic buffers are expected to always be in RESOURCE_STATE_GENERIC_READ state");
}
#endif

void BufferD3D12Impl::SetD3D12ResourceState(D3D12_RESOURCE_STATES state)
{
SetState(D3D12ResourceStatesToResourceStateFlags(state));
Expand Down
Loading

0 comments on commit a614507

Please sign in to comment.