Skip to content

Commit d694139

Browse files
DeviceContextWebGPU: optimized dynamic offsets handling in CommitBindGroups
Do not call SetBindGroup if offsets have not changed
1 parent 617a582 commit d694139

File tree

4 files changed

+90
-47
lines changed

4 files changed

+90
-47
lines changed

Graphics/GraphicsEngineWebGPU/include/DeviceContextWebGPUImpl.hpp

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -440,13 +440,14 @@ class DeviceContextWebGPUImpl final : public DeviceContextBase<EngineWebGPUImplT
440440
{
441441
WGPUBindGroup wgpuBindGroup = nullptr;
442442

443-
// The total number of resources with dynamic offsets, given by pSignature->GetDynamicOffsetCount().
444-
// Note that this is not the actual number of dynamic buffers in the resource cache.
445-
Uint32 DynamicOffsetCount = 0;
446-
447443
// Bind index to use with wgpuEncoderSetBindGroup
448444
Uint32 BindIndex = ~0u;
449445

446+
// Memory to store dynamic buffer offsets for wgpuEncoderSetBindGroup.
447+
// The total number of resources with dynamic offsets is given by pSignature->GetDynamicOffsetCount().
448+
// Note that this is not the actual number of dynamic buffers in the resource cache.
449+
std::vector<Uint32> DynamicBufferOffsets;
450+
450451
bool IsActive() const
451452
{
452453
return BindIndex != BindGroupInfo{}.BindIndex;
@@ -465,9 +466,6 @@ class DeviceContextWebGPUImpl final : public DeviceContextBase<EngineWebGPUImplT
465466
}
466467
} m_BindInfo;
467468

468-
// Memory to store dynamic buffer offsets for wgpuEncoderSetBindGroup.
469-
std::vector<Uint32> m_DynamicBufferOffsets;
470-
471469
struct PendingClears
472470
{
473471
using RenderTargetClearColors = std::array<float[4], MAX_RENDER_TARGETS>;

Graphics/GraphicsEngineWebGPU/include/ShaderResourceCacheWebGPU.hpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,9 @@ class ShaderResourceCacheWebGPU : public ShaderResourceCacheBase
8989
void SetUniformBuffer(RefCntAutoPtr<IDeviceObject>&& _pBuffer, Uint64 _RangeOffset, Uint64 _RangeSize);
9090
void SetStorageBuffer(RefCntAutoPtr<IDeviceObject>&& _pBufferView);
9191

92+
template <typename ResType>
93+
Uint32 GetDynamicBufferOffset(DeviceContextIndex CtxId) const;
94+
9295
explicit operator bool() const { return pObject != nullptr; }
9396
};
9497

@@ -173,9 +176,10 @@ class ShaderResourceCacheWebGPU : public ShaderResourceCacheBase
173176

174177
WGPUBindGroup UpdateBindGroup(WGPUDevice wgpuDevice, Uint32 GroupIndex, WGPUBindGroupLayout wgpuGroupLayout);
175178

176-
Uint32 GetDynamicBufferOffsets(DeviceContextIndex CtxId,
177-
std::vector<uint32_t>& Offsets,
178-
Uint32 GroupIdx) const;
179+
// Returns true if any dynamic offset has changed
180+
bool GetDynamicBufferOffsets(DeviceContextIndex CtxId,
181+
std::vector<uint32_t>& Offsets,
182+
Uint32 GroupIdx) const;
179183

180184
#ifdef DILIGENT_DEBUG
181185
// For debug purposes only

Graphics/GraphicsEngineWebGPU/src/DeviceContextWebGPUImpl.cpp

Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,7 @@ void DeviceContextWebGPUImpl::SetPipelineState(IPipelineState* pPipelineState)
9191

9292
const Uint32 SignatureCount = m_pPipelineState->GetResourceSignatureCount();
9393

94-
Uint32 ActiveBindGroupIndex = 0;
95-
Uint32 MaxDynamicOffsetCount = 0;
94+
Uint32 ActiveBindGroupIndex = 0;
9695
for (Uint32 i = 0; i < SignatureCount; ++i)
9796
{
9897
PipelineResourceSignatureWebGPUImpl* pSign = m_pPipelineState->GetResourceSignature(i);
@@ -117,10 +116,11 @@ void DeviceContextWebGPUImpl::SetPipelineState(IPipelineState* pPipelineState)
117116
if (pSign->HasBindGroup(BindGroupId))
118117
{
119118
const Uint32 DynamicOffsetCount = pSign->GetDynamicOffsetCount(BindGroupId);
120-
MaxDynamicOffsetCount = std::max(MaxDynamicOffsetCount, DynamicOffsetCount);
119+
BindGroup.DynamicBufferOffsets.resize(DynamicOffsetCount);
120+
for (Uint32& Offset : BindGroup.DynamicBufferOffsets)
121+
Offset = ~0u;
121122

122-
BindGroup.DynamicOffsetCount = DynamicOffsetCount;
123-
BindGroup.BindIndex = ActiveBindGroupIndex++;
123+
BindGroup.BindIndex = ActiveBindGroupIndex++;
124124
}
125125
else
126126
{
@@ -130,8 +130,6 @@ void DeviceContextWebGPUImpl::SetPipelineState(IPipelineState* pPipelineState)
130130
}
131131
}
132132
VERIFY(m_pPipelineState->GetPipelineLayout().GetBindGroupCount() == ActiveBindGroupIndex, "Bind group count mismatch");
133-
134-
m_DynamicBufferOffsets.resize(MaxDynamicOffsetCount);
135133
}
136134

137135
void DeviceContextWebGPUImpl::TransitionShaderResources(IShaderResourceBinding* pShaderResourceBinding)
@@ -214,13 +212,13 @@ void DeviceContextWebGPUImpl::CommitShaderResources(IShaderResourceBinding*
214212
VERIFY_EXPR(BGIndex == ResourceCache.GetNumBindGroups());
215213
}
216214

217-
void SetBindGroup(WGPURenderPassEncoder Encoder, uint32_t GroupIndex, WGPUBindGroup Group, size_t DynamicOffsetCount, uint32_t const* DynamicOffsets)
215+
void SetBindGroup(WGPURenderPassEncoder Encoder, uint32_t GroupIndex, WGPUBindGroup Group, const std::vector<Uint32>& DynamicOffsets)
218216
{
219-
wgpuRenderPassEncoderSetBindGroup(Encoder, GroupIndex, Group, DynamicOffsetCount, DynamicOffsets);
217+
wgpuRenderPassEncoderSetBindGroup(Encoder, GroupIndex, Group, DynamicOffsets.size(), !DynamicOffsets.empty() ? DynamicOffsets.data() : nullptr);
220218
}
221-
void SetBindGroup(WGPUComputePassEncoder Encoder, uint32_t GroupIndex, WGPUBindGroup Group, size_t DynamicOffsetCount, uint32_t const* DynamicOffsets)
219+
void SetBindGroup(WGPUComputePassEncoder Encoder, uint32_t GroupIndex, WGPUBindGroup Group, const std::vector<Uint32>& DynamicOffsets)
222220
{
223-
wgpuComputePassEncoderSetBindGroup(Encoder, GroupIndex, Group, DynamicOffsetCount, DynamicOffsets);
221+
wgpuComputePassEncoderSetBindGroup(Encoder, GroupIndex, Group, DynamicOffsets.size(), !DynamicOffsets.empty() ? DynamicOffsets.data() : nullptr);
224222
}
225223

226224
template <typename CmdEncoderType>
@@ -234,25 +232,35 @@ void DeviceContextWebGPUImpl::CommitBindGroups(CmdEncoderType CmdEncoder, Uint32
234232

235233
for (Uint32 sign = FirstSign; sign <= LastSign; ++sign)
236234
{
235+
const Uint32 SRBBit = 1u << sign;
236+
if ((CommitSRBMask & SRBBit) == 0)
237+
continue;
238+
237239
Uint32 BindGroupCacheIndex = 0;
238240
for (PipelineResourceSignatureWebGPUImpl::BIND_GROUP_ID BindGroupId : {PipelineResourceSignatureWebGPUImpl::BIND_GROUP_ID_STATIC_MUTABLE,
239241
PipelineResourceSignatureWebGPUImpl::BIND_GROUP_ID_DYNAMIC})
240242
{
241-
const WebGPUResourceBindInfo::BindGroupInfo& BindGroup = m_BindInfo.BindGroups[sign][BindGroupId];
243+
WebGPUResourceBindInfo::BindGroupInfo& BindGroup = m_BindInfo.BindGroups[sign][BindGroupId];
242244
if (!BindGroup.IsActive())
243245
continue;
244246

245247
const ShaderResourceCacheWebGPU* ResourceCache = m_BindInfo.ResourceCaches[sign];
246248
VERIFY_EXPR(ResourceCache != nullptr);
247-
const Uint32 NumOffsetsWritten = ResourceCache->GetDynamicBufferOffsets(GetContextId(), m_DynamicBufferOffsets, BindGroupCacheIndex++);
248-
VERIFY(NumOffsetsWritten == BindGroup.DynamicOffsetCount,
249-
"The number of dynamic offsets written (", NumOffsetsWritten, ") does not match the expected number (", BindGroup.DynamicOffsetCount,
250-
"). This likely indicates mismatch between the SRB and the PSO");
251-
(void)NumOffsetsWritten;
249+
bool DynamicOffsetsChanged = false;
250+
if (!BindGroup.DynamicBufferOffsets.empty())
251+
{
252+
DynamicOffsetsChanged = ResourceCache->GetDynamicBufferOffsets(GetContextId(), BindGroup.DynamicBufferOffsets, BindGroupCacheIndex);
253+
}
254+
++BindGroupCacheIndex;
255+
256+
if ((m_BindInfo.StaleSRBMask & SRBBit) == 0 && !DynamicOffsetsChanged)
257+
{
258+
continue;
259+
}
252260

253261
if (WGPUBindGroup wgpuBindGroup = BindGroup.wgpuBindGroup)
254262
{
255-
SetBindGroup(CmdEncoder, BindGroup.BindIndex, wgpuBindGroup, BindGroup.DynamicOffsetCount, m_DynamicBufferOffsets.data());
263+
SetBindGroup(CmdEncoder, BindGroup.BindIndex, wgpuBindGroup, BindGroup.DynamicBufferOffsets);
256264
}
257265
else
258266
{

Graphics/GraphicsEngineWebGPU/src/ShaderResourceCacheWebGPU.cpp

Lines changed: 52 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,37 @@ void ShaderResourceCacheWebGPU::Resource::SetStorageBuffer(RefCntAutoPtr<IDevice
220220
#endif
221221
}
222222

223+
template <>
224+
Uint32 ShaderResourceCacheWebGPU::Resource::GetDynamicBufferOffset<BufferWebGPUImpl>(DeviceContextIndex CtxId) const
225+
{
226+
Uint32 Offset = BufferDynamicOffset;
227+
if (const BufferWebGPUImpl* pBufferWGPU = pObject.ConstPtr<BufferWebGPUImpl>())
228+
{
229+
// Do not verify dynamic allocation here as there may be some buffers that are not used by the PSO.
230+
// The allocations of the buffers that are actually used will be verified by
231+
// PipelineResourceSignatureWebGPUImpl::DvpValidateCommittedResource().
232+
Offset += StaticCast<Uint32>(pBufferWGPU->GetDynamicOffset(CtxId, nullptr /* Do not verify allocation*/));
233+
}
234+
return Offset;
235+
}
236+
237+
template <>
238+
Uint32 ShaderResourceCacheWebGPU::Resource::GetDynamicBufferOffset<BufferViewWebGPUImpl>(DeviceContextIndex CtxId) const
239+
{
240+
Uint32 Offset = BufferDynamicOffset;
241+
if (const BufferViewWebGPUImpl* pBufferWGPUView = pObject.ConstPtr<BufferViewWebGPUImpl>())
242+
{
243+
if (const BufferWebGPUImpl* pBufferWGPU = pBufferWGPUView->GetBuffer<const BufferWebGPUImpl>())
244+
{
245+
// Do not verify dynamic allocation here as there may be some buffers that are not used by the PSO.
246+
// The allocations of the buffers that are actually used will be verified by
247+
// PipelineResourceSignatureWebGPUImpl::DvpValidateCommittedResource().
248+
Offset += StaticCast<Uint32>(pBufferWGPU->GetDynamicOffset(CtxId, nullptr /* Do not verify allocation*/));
249+
}
250+
}
251+
return Offset;
252+
}
253+
223254
void ShaderResourceCacheWebGPU::InitializeResources(Uint32 GroupIdx, Uint32 Offset, Uint32 ArraySize, BindGroupEntryType Type, bool HasImmutableSampler)
224255
{
225256
BindGroup& Group = GetBindGroup(GroupIdx);
@@ -444,9 +475,9 @@ WGPUBindGroup ShaderResourceCacheWebGPU::UpdateBindGroup(WGPUDevice wgpuDevice,
444475
return Group.m_wgpuBindGroup;
445476
}
446477

447-
Uint32 ShaderResourceCacheWebGPU::GetDynamicBufferOffsets(DeviceContextIndex CtxId,
448-
std::vector<uint32_t>& Offsets,
449-
Uint32 GroupIdx) const
478+
bool ShaderResourceCacheWebGPU::GetDynamicBufferOffsets(DeviceContextIndex CtxId,
479+
std::vector<uint32_t>& Offsets,
480+
Uint32 GroupIdx) const
450481
{
451482
// In each bind group, all uniform buffers with dynamic offsets (BindGroupEntryType::UniformBufferDynamic)
452483
// for every shader stage come first, followed by all storage buffers with dynamic offsets
@@ -456,19 +487,19 @@ Uint32 ShaderResourceCacheWebGPU::GetDynamicBufferOffsets(DeviceContextIndex
456487
const BindGroup& Group = GetBindGroup(GroupIdx);
457488
const Uint32 GroupSize = Group.GetSize();
458489

459-
Uint32 res = 0;
460-
Uint32 OffsetInd = 0;
490+
Uint32 res = 0;
491+
Uint32 OffsetInd = 0;
492+
bool OffsetsChanged = false;
461493
while (res < GroupSize)
462494
{
463495
const Resource& Res = Group.GetResource(res);
464496
if (Res.Type == BindGroupEntryType::UniformBufferDynamic)
465497
{
466-
const BufferWebGPUImpl* pBufferWGPU = Res.pObject.ConstPtr<BufferWebGPUImpl>();
467-
// Do not verify dynamic allocation here as there may be some buffers that are not used by the PSO.
468-
// The allocations of the buffers that are actually used will be verified by
469-
// PipelineResourceSignatureWebGPUImpl::DvpValidateCommittedResource().
470-
const Uint64 Offset = pBufferWGPU != nullptr ? pBufferWGPU->GetDynamicOffset(CtxId, nullptr /* Do not verify allocation*/) : 0;
471-
Offsets[OffsetInd++] = Res.BufferDynamicOffset + StaticCast<Uint32>(Offset);
498+
const Uint32 Offset = Res.GetDynamicBufferOffset<BufferWebGPUImpl>(CtxId);
499+
Uint32& DstOffset = Offsets[OffsetInd++];
500+
if (DstOffset != Offset)
501+
OffsetsChanged = true;
502+
DstOffset = Offset;
472503
++res;
473504
}
474505
else
@@ -481,13 +512,11 @@ Uint32 ShaderResourceCacheWebGPU::GetDynamicBufferOffsets(DeviceContextIndex
481512
if (Res.Type == BindGroupEntryType::StorageBufferDynamic ||
482513
Res.Type == BindGroupEntryType::StorageBufferDynamic_ReadOnly)
483514
{
484-
const BufferViewWebGPUImpl* pBufferWGPUView = Res.pObject.ConstPtr<BufferViewWebGPUImpl>();
485-
const BufferWebGPUImpl* pBufferWGPU = pBufferWGPUView != nullptr ? pBufferWGPUView->GetBuffer<const BufferWebGPUImpl>() : nullptr;
486-
// Do not verify dynamic allocation here as there may be some buffers that are not used by the PSO.
487-
// The allocations of the buffers that are actually used will be verified by
488-
// PipelineResourceSignatureWebGPUImpl::DvpValidateCommittedResource().
489-
const Uint64 Offset = pBufferWGPU != nullptr ? pBufferWGPU->GetDynamicOffset(CtxId, nullptr /* Do not verify allocation*/) : 0;
490-
Offsets[OffsetInd++] = Res.BufferDynamicOffset + StaticCast<Uint32>(Offset);
515+
const Uint32 Offset = Res.GetDynamicBufferOffset<BufferViewWebGPUImpl>(CtxId);
516+
Uint32& DstOffset = Offsets[OffsetInd++];
517+
if (DstOffset != Offset)
518+
OffsetsChanged = true;
519+
DstOffset = Offset;
491520
++res;
492521
}
493522
else
@@ -505,7 +534,11 @@ Uint32 ShaderResourceCacheWebGPU::GetDynamicBufferOffsets(DeviceContextIndex
505534
}
506535
#endif
507536

508-
return OffsetInd;
537+
VERIFY(OffsetInd == Offsets.size(),
538+
"The number of dynamic offsets written (", OffsetInd, ") does not match the expected number (", Offsets.size(),
539+
"). This likely indicates the mismatch between the SRB and the PSO");
540+
541+
return OffsetsChanged;
509542
}
510543

511544
#ifdef DILIGENT_DEBUG

0 commit comments

Comments
 (0)