Skip to content

Commit a614507

Browse files
D3D12: moved dynamic buffer allocations to device context (close #420)
1 parent 164e9d6 commit a614507

File tree

6 files changed

+148
-107
lines changed

6 files changed

+148
-107
lines changed

Graphics/GraphicsEngineD3D12/include/BufferD3D12Impl.hpp

Lines changed: 1 addition & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2019-2022 Diligent Graphics LLC
2+
* Copyright 2019-2025 Diligent Graphics LLC
33
* Copyright 2015-2019 Egor Yusov
44
*
55
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -65,10 +65,6 @@ class BufferD3D12Impl final : public BufferBase<EngineD3D12ImplTraits>, public D
6565

6666
IMPLEMENT_QUERY_INTERFACE_IN_PLACE(IID_BufferD3D12, TBufferBase)
6767

68-
#ifdef DILIGENT_DEVELOPMENT
69-
void DvpVerifyDynamicAllocation(const DeviceContextD3D12Impl* pCtx) const;
70-
#endif
71-
7268
/// Implementation of IBufferD3D12::GetD3D12Buffer().
7369
virtual ID3D12Resource* DILIGENT_CALL_TYPE GetD3D12Buffer(Uint64& DataStartByteOffset, IDeviceContext* pContext) override final;
7470

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

94-
__forceinline D3D12_GPU_VIRTUAL_ADDRESS GetGPUAddress(DeviceContextIndex ContextId, const DeviceContextD3D12Impl* pCtx) const
95-
{
96-
if (m_Desc.Usage == USAGE_DYNAMIC)
97-
{
98-
#ifdef DILIGENT_DEVELOPMENT
99-
if (pCtx != nullptr)
100-
{
101-
DvpVerifyDynamicAllocation(pCtx);
102-
}
103-
#endif
104-
return m_DynamicData[ContextId].GPUAddress;
105-
}
106-
else
107-
{
108-
return GetD3D12Resource()->GetGPUVirtualAddress();
109-
}
110-
}
111-
11290
__forceinline D3D12_GPU_VIRTUAL_ADDRESS GetGPUAddress()
11391
{
11492
VERIFY_EXPR(m_Desc.Usage != USAGE_DYNAMIC);
@@ -126,23 +104,6 @@ class BufferD3D12Impl final : public BufferBase<EngineD3D12ImplTraits>, public D
126104
void CreateSRV(struct BufferViewDesc& SRVDesc, D3D12_CPU_DESCRIPTOR_HANDLE SRVDescriptor) const;
127105

128106
DescriptorHeapAllocation m_CBVDescriptorAllocation;
129-
130-
// Align the struct size to the cache line size to avoid false sharing
131-
static constexpr size_t CacheLineSize = 64;
132-
struct alignas(CacheLineSize) CtxDynamicData : D3D12DynamicAllocation
133-
{
134-
CtxDynamicData& operator=(const D3D12DynamicAllocation& Allocation)
135-
{
136-
*static_cast<D3D12DynamicAllocation*>(this) = Allocation;
137-
return *this;
138-
}
139-
Uint8 Padding[CacheLineSize - sizeof(D3D12DynamicAllocation)] = {};
140-
};
141-
static_assert(sizeof(CtxDynamicData) == CacheLineSize, "Unexpected sizeof(CtxDynamicData)");
142-
143-
friend DeviceContextD3D12Impl;
144-
// Array of dynamic allocations for every device context.
145-
std::vector<CtxDynamicData, STDAllocatorRawMem<CtxDynamicData>> m_DynamicData;
146107
};
147108

148109
} // namespace Diligent

Graphics/GraphicsEngineD3D12/include/DeviceContextD3D12Impl.hpp

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2019-2024 Diligent Graphics LLC
2+
* Copyright 2019-2025 Diligent Graphics LLC
33
* Copyright 2015-2019 Egor Yusov
44
*
55
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -360,6 +360,12 @@ class DeviceContextD3D12Impl final : public DeviceContextNextGenBase<EngineD3D12
360360
return *m_QueryMgr;
361361
}
362362

363+
#ifdef DILIGENT_DEVELOPMENT
364+
void DvpVerifyDynamicAllocation(const BufferD3D12Impl* pBuffer) const;
365+
#endif
366+
__forceinline D3D12_GPU_VIRTUAL_ADDRESS GetBufferGPUAddress(const BufferD3D12Impl* pBuffer, bool VerifyDynamicAllocation = true) const;
367+
ID3D12Resource* GetDynamicBufferD3D12ResourceAndOffset(const BufferD3D12Impl* pBuffer, Uint64& DataStartByteOffset);
368+
363369
private:
364370
void CommitD3D12IndexBuffer(GraphicsContext& GraphCtx, VALUE_TYPE IndexType);
365371
void CommitD3D12VertexBuffers(GraphicsContext& GraphCtx);
@@ -510,6 +516,16 @@ class DeviceContextD3D12Impl final : public DeviceContextNextGenBase<EngineD3D12
510516
};
511517
std::unordered_map<MappedTextureKey, TextureUploadSpace, MappedTextureKey::Hasher> m_MappedTextures;
512518

519+
struct MappedBuffer
520+
{
521+
D3D12DynamicAllocation Allocation;
522+
#ifdef DILIGENT_DEVELOPMENT
523+
UniqueIdentifier DvpBufferUID = -1;
524+
#endif
525+
};
526+
// NB: using absl::flat_hash_map<const BufferD3D12Impl*, MappedBuffer> is considerably slower.
527+
std::vector<MappedBuffer> m_MappedBuffers;
528+
513529
Int32 m_ActiveQueriesCounter = 0;
514530

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

541+
__forceinline D3D12_GPU_VIRTUAL_ADDRESS DeviceContextD3D12Impl::GetBufferGPUAddress(const BufferD3D12Impl* pBuffer, bool VerifyDynamicAllocation) const
542+
{
543+
VERIFY_EXPR(pBuffer != nullptr);
544+
545+
if (pBuffer->GetD3D12Resource() != nullptr)
546+
{
547+
return pBuffer->GetD3D12Resource()->GetGPUVirtualAddress();
548+
}
549+
550+
#ifdef DILIGENT_DEVELOPMENT
551+
if (VerifyDynamicAllocation)
552+
{
553+
DvpVerifyDynamicAllocation(pBuffer);
554+
}
555+
#endif
556+
557+
const Uint32 DynamicBufferId = pBuffer->GetDynamicBufferId();
558+
VERIFY(DynamicBufferId != ~0u, "Dynamic buffer '", pBuffer->GetDesc().Name, "' does not have dynamic buffer ID");
559+
return DynamicBufferId < m_MappedBuffers.size() ?
560+
m_MappedBuffers[DynamicBufferId].Allocation.GPUAddress :
561+
0;
562+
}
563+
525564
} // namespace Diligent

Graphics/GraphicsEngineD3D12/include/PipelineResourceSignatureD3D12Impl.hpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2019-2024 Diligent Graphics LLC
2+
* Copyright 2019-2025 Diligent Graphics LLC
33
* Copyright 2015-2019 Egor Yusov
44
*
55
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -50,6 +50,7 @@ namespace Diligent
5050

5151
class CommandContext;
5252
struct D3DShaderResourceAttribs;
53+
class DeviceContextD3D12Impl;
5354

5455
struct ImmutableSamplerAttribsD3D12
5556
{
@@ -146,8 +147,8 @@ class PipelineResourceSignatureD3D12Impl final : public PipelineResourceSignatur
146147
struct CommitCacheResourcesAttribs
147148
{
148149
ID3D12Device* const pd3d12Device;
149-
CommandContext& Ctx;
150-
const DeviceContextIndex DeviceCtxId;
150+
CommandContext& CmdCtx;
151+
const DeviceContextD3D12Impl* pDeviceCtx;
151152
const bool IsCompute;
152153
const ShaderResourceCacheD3D12* pResourceCache = nullptr;
153154
Uint32 BaseRootIndex = ~0u;

Graphics/GraphicsEngineD3D12/src/BufferD3D12Impl.cpp

Lines changed: 7 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -46,22 +46,13 @@ BufferD3D12Impl::BufferD3D12Impl(IReferenceCounters* pRefCounters,
4646
RenderDeviceD3D12Impl* pRenderDeviceD3D12,
4747
const BufferDesc& BuffDesc,
4848
const BufferData* pBuffData /*= nullptr*/) :
49-
// clang-format off
50-
TBufferBase
51-
{
49+
TBufferBase{
5250
pRefCounters,
5351
BuffViewObjMemAllocator,
5452
pRenderDeviceD3D12,
5553
BuffDesc,
56-
false
57-
},
58-
m_DynamicData
59-
(
60-
BuffDesc.Usage == USAGE_DYNAMIC ? (pRenderDeviceD3D12->GetNumImmediateContexts() + pRenderDeviceD3D12->GetNumDeferredContexts()) : 0,
61-
CtxDynamicData{},
62-
STD_ALLOCATOR_RAW_MEM(D3D12DynamicAllocation, GetRawAllocator(), "Allocator for vector<DynamicAllocation>")
63-
)
64-
// clang-format on
54+
false,
55+
}
6556
{
6657
ValidateBufferInitData(m_Desc, pBuffData);
6758

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

9081
SetState(RESOURCE_STATE_GENERIC_READ);
91-
VERIFY_EXPR(m_DynamicData.size() == pRenderDeviceD3D12->GetNumImmediateContexts() + pRenderDeviceD3D12->GetNumDeferredContexts());
9282
}
9383
else
9484
{
@@ -308,22 +298,13 @@ BufferD3D12Impl::BufferD3D12Impl(IReferenceCounters* pRefCounters,
308298
const BufferDesc& BuffDesc,
309299
RESOURCE_STATE InitialState,
310300
ID3D12Resource* pd3d12Buffer) :
311-
// clang-format off
312-
TBufferBase
313-
{
301+
TBufferBase{
314302
pRefCounters,
315303
BuffViewObjMemAllocator,
316304
pRenderDeviceD3D12,
317305
BufferDescFromD3D12Resource(BuffDesc, pd3d12Buffer),
318-
false
319-
},
320-
m_DynamicData
321-
(
322-
BuffDesc.Usage == USAGE_DYNAMIC ? (pRenderDeviceD3D12->GetNumImmediateContexts() + pRenderDeviceD3D12->GetNumDeferredContexts()) : 0,
323-
CtxDynamicData{},
324-
STD_ALLOCATOR_RAW_MEM(D3D12DynamicAllocation, GetRawAllocator(), "Allocator for vector<DynamicAllocation>")
325-
)
326-
// clang-format on
306+
false,
307+
}
327308
{
328309
m_pd3d12Resource = pd3d12Buffer;
329310
SetState(InitialState);
@@ -436,26 +417,10 @@ ID3D12Resource* BufferD3D12Impl::GetD3D12Buffer(Uint64& DataStartByteOffset, IDe
436417
{
437418
VERIFY(m_Desc.Usage == USAGE_DYNAMIC, "Dynamic buffer is expected");
438419
DeviceContextD3D12Impl* pCtxD3D12 = ClassPtrCast<DeviceContextD3D12Impl>(pContext);
439-
#ifdef DILIGENT_DEVELOPMENT
440-
DvpVerifyDynamicAllocation(pCtxD3D12);
441-
#endif
442-
DeviceContextIndex ContextId = pCtxD3D12->GetContextId();
443-
DataStartByteOffset = m_DynamicData[ContextId].Offset;
444-
return m_DynamicData[ContextId].pBuffer;
420+
return pCtxD3D12->GetDynamicBufferD3D12ResourceAndOffset(this, DataStartByteOffset);
445421
}
446422
}
447423

448-
#ifdef DILIGENT_DEVELOPMENT
449-
void BufferD3D12Impl::DvpVerifyDynamicAllocation(const DeviceContextD3D12Impl* pCtx) const
450-
{
451-
DeviceContextIndex ContextId = pCtx->GetContextId();
452-
Uint64 CurrentFrame = pCtx->GetFrameNumber();
453-
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.");
454-
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.");
455-
VERIFY(GetState() == RESOURCE_STATE_GENERIC_READ, "Dynamic buffers are expected to always be in RESOURCE_STATE_GENERIC_READ state");
456-
}
457-
#endif
458-
459424
void BufferD3D12Impl::SetD3D12ResourceState(D3D12_RESOURCE_STATES state)
460425
{
461426
SetState(D3D12ResourceStatesToResourceStateFlags(state));

0 commit comments

Comments
 (0)